changeset 408:3d4d8bc2ef64

6591117: Poor preformance of PKCS#11 security provider compared to Sun default provider Summary: Added internal buffering to PKCS11 SecureRandom impl Reviewed-by: vinnie
author valeriep
date Fri, 06 Aug 2010 15:05:36 -0700
parents 9f17abb48a34
children 85b819949825
files src/share/classes/sun/security/pkcs11/P11SecureRandom.java
diffstat 1 files changed, 56 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/sun/security/pkcs11/P11SecureRandom.java	Fri Aug 06 14:56:01 2010 -0700
+++ b/src/share/classes/sun/security/pkcs11/P11SecureRandom.java	Fri Aug 06 15:05:36 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. 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
@@ -27,6 +27,7 @@
 
 import java.util.*;
 
+import java.io.*;
 import java.security.*;
 
 import sun.security.pkcs11.wrapper.*;
@@ -61,9 +62,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,15 +124,27 @@
         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);
         }
     }
 
@@ -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);
+        }
+    }
 }