6591117: Poor preformance of PKCS#11 security provider compared to Sun default provider
Summary: Added internal buffering to PKCS11 SecureRandom impl
Reviewed-by: wetmore
--- a/jdk/src/share/classes/sun/security/pkcs11/P11SecureRandom.java Thu Mar 18 17:05:42 2010 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11SecureRandom.java Thu Mar 18 17:32:45 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
package sun.security.pkcs11;
import java.util.*;
-
+import java.io.*;
import java.security.*;
import sun.security.pkcs11.wrapper.*;
@@ -61,9 +61,28 @@
// buffer, if mixing is used
private byte[] mixBuffer;
- // bytes remaining in buffer, if mixing is used
+ // bytes remaining in mixBuffer, if mixing is used
private int buffered;
+ /*
+ * we buffer data internally for efficiency but limit the lifetime
+ * to avoid using stale bits.
+ */
+ // lifetime in ms, currently 100 ms (0.1 s)
+ private static final long MAX_IBUFFER_TIME = 100;
+
+ // size of the internal buffer
+ private static final int IBUFFER_SIZE = 32;
+
+ // internal buffer for the random bits
+ private transient byte[] iBuffer = new byte[IBUFFER_SIZE];
+
+ // number of bytes remain in iBuffer
+ private transient int ibuffered = 0;
+
+ // time that data was read into iBuffer
+ private transient long lastRead = 0L;
+
P11SecureRandom(Token token) {
this.token = token;
}
@@ -104,16 +123,29 @@
if ((bytes == null) || (bytes.length == 0)) {
return;
}
- Session session = null;
- try {
- session = token.getOpSession();
- token.p11.C_GenerateRandom(session.id(), bytes);
- mix(bytes);
- } catch (PKCS11Exception e) {
- throw new ProviderException("nextBytes() failed", e);
- } finally {
- token.releaseSession(session);
+ if (bytes.length <= IBUFFER_SIZE) {
+ int ofs = 0;
+ synchronized (iBuffer) {
+ while (ofs < bytes.length) {
+ long time = System.currentTimeMillis();
+ // refill the internal buffer if empty or stale
+ if ((ibuffered == 0) ||
+ !(time - lastRead < MAX_IBUFFER_TIME)) {
+ lastRead = time;
+ implNextBytes(iBuffer);
+ ibuffered = IBUFFER_SIZE;
+ }
+ // copy the buffered bytes into 'bytes'
+ while ((ofs < bytes.length) && (ibuffered > 0)) {
+ bytes[ofs++] = iBuffer[IBUFFER_SIZE - ibuffered--];
+ }
+ }
+ }
+ } else {
+ // avoid using the buffer - just fill bytes directly
+ implNextBytes(bytes);
}
+
}
// see JCA spec
@@ -143,4 +175,17 @@
}
}
+ // fill up the specified buffer with random bytes, and mix them
+ private void implNextBytes(byte[] bytes) {
+ Session session = null;
+ try {
+ session = token.getOpSession();
+ token.p11.C_GenerateRandom(session.id(), bytes);
+ mix(bytes);
+ } catch (PKCS11Exception e) {
+ throw new ProviderException("nextBytes() failed", e);
+ } finally {
+ token.releaseSession(session);
+ }
+ }
}