提交 fdc78cfa 编写于 作者: A ascarpino

8098581: SecureRandom.nextBytes() hurts performance with small size requests

Reviewed-by: valeriep
上级 a533f45f
...@@ -464,7 +464,7 @@ public class SecureRandom extends java.util.Random { ...@@ -464,7 +464,7 @@ public class SecureRandom extends java.util.Random {
* @param bytes the array to be filled in with random bytes. * @param bytes the array to be filled in with random bytes.
*/ */
@Override @Override
synchronized public void nextBytes(byte[] bytes) { public void nextBytes(byte[] bytes) {
secureRandomSpi.engineNextBytes(bytes); secureRandomSpi.engineNextBytes(bytes);
} }
......
...@@ -18,6 +18,7 @@ attributes = compatibility ...@@ -18,6 +18,7 @@ attributes = compatibility
disabledMechanisms = { disabledMechanisms = {
CKM_DSA_KEY_PAIR_GEN CKM_DSA_KEY_PAIR_GEN
SecureRandom
# the following mechanisms are disabled due to performance issues # the following mechanisms are disabled due to performance issues
# (Solaris bug 6337157) # (Solaris bug 6337157)
CKM_DSA_SHA1 CKM_DSA_SHA1
......
/* /*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -28,6 +28,8 @@ package sun.security.provider; ...@@ -28,6 +28,8 @@ package sun.security.provider;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.security.*; import java.security.*;
import java.util.Arrays;
import sun.security.util.Debug; import sun.security.util.Debug;
/** /**
...@@ -334,7 +336,9 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -334,7 +336,9 @@ public final class NativePRNG extends SecureRandomSpi {
private final static long MAX_BUFFER_TIME = 100; private final static long MAX_BUFFER_TIME = 100;
// size of the "next" buffer // size of the "next" buffer
private final static int BUFFER_SIZE = 32; private static final int MAX_BUFFER_SIZE = 65536;
private static final int MIN_BUFFER_SIZE = 32;
private int bufferSize = 256;
// Holder for the seedFile. Used if we ever add seed material. // Holder for the seedFile. Used if we ever add seed material.
File seedFile; File seedFile;
...@@ -351,7 +355,7 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -351,7 +355,7 @@ public final class NativePRNG extends SecureRandomSpi {
private volatile sun.security.provider.SecureRandom mixRandom; private volatile sun.security.provider.SecureRandom mixRandom;
// buffer for next bits // buffer for next bits
private final byte[] nextBuffer; private byte[] nextBuffer;
// number of bytes left in nextBuffer // number of bytes left in nextBuffer
private int buffered; private int buffered;
...@@ -359,6 +363,16 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -359,6 +363,16 @@ public final class NativePRNG extends SecureRandomSpi {
// time we read the data into the nextBuffer // time we read the data into the nextBuffer
private long lastRead; private long lastRead;
// Count for the number of buffer size changes requests
// Positive value in increase size, negative to lower it.
private int change_buffer = 0;
// Request limit to trigger an increase in nextBuffer size
private static final int REQ_LIMIT_INC = 1000;
// Request limit to trigger a decrease in nextBuffer size
private static final int REQ_LIMIT_DEC = -100;
// mutex lock for nextBytes() // mutex lock for nextBytes()
private final Object LOCK_GET_BYTES = new Object(); private final Object LOCK_GET_BYTES = new Object();
...@@ -373,7 +387,7 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -373,7 +387,7 @@ public final class NativePRNG extends SecureRandomSpi {
this.seedFile = seedFile; this.seedFile = seedFile;
seedIn = new FileInputStream(seedFile); seedIn = new FileInputStream(seedFile);
nextIn = new FileInputStream(nextFile); nextIn = new FileInputStream(nextFile);
nextBuffer = new byte[BUFFER_SIZE]; nextBuffer = new byte[bufferSize];
} }
// get the SHA1PRNG for mixing // get the SHA1PRNG for mixing
...@@ -466,9 +480,47 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -466,9 +480,47 @@ public final class NativePRNG extends SecureRandomSpi {
// if not, read new bytes // if not, read new bytes
private void ensureBufferValid() throws IOException { private void ensureBufferValid() throws IOException {
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
if ((buffered > 0) && (time - lastRead < MAX_BUFFER_TIME)) { int new_buffer_size = 0;
return;
// Check if buffer has bytes available that are not too old
if (buffered > 0) {
if (time - lastRead < MAX_BUFFER_TIME) {
return;
} else {
// byte is old, so subtract from counter to shrink buffer
change_buffer--;
}
} else {
// No bytes available, so add to count to increase buffer
change_buffer++;
} }
// If counter has it a limit, increase or decrease size
if (change_buffer > REQ_LIMIT_INC) {
new_buffer_size = nextBuffer.length * 2;
} else if (change_buffer < REQ_LIMIT_DEC) {
new_buffer_size = nextBuffer.length / 2;
}
// If buffer size is to be changed, replace nextBuffer.
if (new_buffer_size > 0) {
if (new_buffer_size <= MAX_BUFFER_SIZE &&
new_buffer_size >= MIN_BUFFER_SIZE) {
nextBuffer = new byte[new_buffer_size];
if (debug != null) {
debug.println("Buffer size changed to " +
new_buffer_size);
}
} else {
if (debug != null) {
debug.println("Buffer reached limit: " +
nextBuffer.length);
}
}
change_buffer = 0;
}
// Load fresh random bytes into nextBuffer
lastRead = time; lastRead = time;
readFully(nextIn, nextBuffer); readFully(nextIn, nextBuffer);
buffered = nextBuffer.length; buffered = nextBuffer.length;
...@@ -478,24 +530,40 @@ public final class NativePRNG extends SecureRandomSpi { ...@@ -478,24 +530,40 @@ public final class NativePRNG extends SecureRandomSpi {
// read from "next" and XOR with bytes generated by the // read from "next" and XOR with bytes generated by the
// mixing SHA1PRNG // mixing SHA1PRNG
private void implNextBytes(byte[] data) { private void implNextBytes(byte[] data) {
synchronized (LOCK_GET_BYTES) {
try { try {
getMixRandom().engineNextBytes(data); getMixRandom().engineNextBytes(data);
int len = data.length; int data_len = data.length;
int ofs = 0; int ofs = 0;
while (len > 0) { int len;
ensureBufferValid(); int buf_pos;
int bufferOfs = nextBuffer.length - buffered; int localofs;
while ((len > 0) && (buffered > 0)) { byte[] localBuffer;
data[ofs++] ^= nextBuffer[bufferOfs++];
len--; while (data_len > 0) {
buffered--; synchronized (LOCK_GET_BYTES) {
ensureBufferValid();
buf_pos = nextBuffer.length - buffered;
if (data_len > buffered) {
len = buffered;
buffered = 0;
} else {
len = data_len;
buffered -= len;
}
localBuffer = Arrays.copyOfRange(nextBuffer, buf_pos,
buf_pos + len);
} }
localofs = 0;
while (len > localofs) {
data[ofs] ^= localBuffer[localofs];
ofs++;
localofs++;
}
data_len -= len;
} }
} catch (IOException e) { } catch (IOException e){
throw new ProviderException("nextBytes() failed", e); throw new ProviderException("nextBytes() failed", e);
} }
}
} }
} }
} }
/* /*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -43,12 +43,7 @@ public class DefaultProvider { ...@@ -43,12 +43,7 @@ public class DefaultProvider {
out.println("TEST: Default provider with constructor"); out.println("TEST: Default provider with constructor");
SecureRandom secureRandom = new SecureRandom(); SecureRandom secureRandom = new SecureRandom();
String provider = secureRandom.getProvider().getName(); String provider = secureRandom.getProvider().getName();
if (OS_NAME.startsWith(SUNOS)) { if (!provider.equals("SUN")) {
if (!provider.startsWith("SunPKCS11-")) {
throw new RuntimeException("Unexpected provider name: "
+ provider);
}
} else if (!provider.equals("SUN")) {
throw new RuntimeException("Unexpected provider name: " throw new RuntimeException("Unexpected provider name: "
+ provider); + provider);
} }
...@@ -77,16 +72,6 @@ public class DefaultProvider { ...@@ -77,16 +72,6 @@ public class DefaultProvider {
instance = SecureRandom.getInstance(algorithm); instance = SecureRandom.getInstance(algorithm);
assertInstance(instance, algorithm, provider); assertInstance(instance, algorithm, provider);
out.println("Passed."); out.println("Passed.");
if (OS_NAME.startsWith(SUNOS)) {
out.println(
"TEST: PKCS11 is supported on Solaris by SunPKCS11 provider");
algorithm = "PKCS11";
provider = "SunPKCS11-Solaris";
instance = SecureRandom.getInstance(algorithm);
assertInstance(instance, algorithm, provider);
out.println("Passed.");
}
} }
private static void assertInstance(SecureRandom instance, private static void assertInstance(SecureRandom instance,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册