@@ -16,7 +16,13 @@ public final class ExtendedRandom {
1616
1717 private OpenJCEPlusProvider provider ;
1818 private NativeInterface nativeInterface ;
19- final long ockPRNGContextId ;
19+ private final String algName ;
20+
21+ private long ockPRNGContextId ;
22+ private boolean usingThreadLocalContext = true ;
23+
24+ private static final ThreadLocal <PRNGContextPointer > prngContextBufferSha256 = new ThreadLocal <PRNGContextPointer >();
25+ private static final ThreadLocal <PRNGContextPointer > prngContextBufferSha512 = new ThreadLocal <PRNGContextPointer >();
2026
2127 public static ExtendedRandom getInstance (String algName , OpenJCEPlusProvider provider )
2228 throws NativeException {
@@ -32,11 +38,35 @@ public static ExtendedRandom getInstance(String algName, OpenJCEPlusProvider pro
3238 }
3339
3440 private ExtendedRandom (String algName , OpenJCEPlusProvider provider ) throws NativeException {
41+ this .algName = algName ;
3542 this .provider = provider ;
3643 this .nativeInterface = provider .isFIPS () ? NativeOCKAdapterFIPS .getInstance () : NativeOCKAdapterNonFIPS .getInstance ();
37- this .ockPRNGContextId = this .nativeInterface .EXTRAND_create (algName );
44+ this .ockPRNGContextId = getPRNGContext (algName );
45+ }
46+
47+ private long getPRNGContext (String algName ) throws NativeException {
48+ PRNGContextPointer prngCtx = null ;
49+ ThreadLocal <PRNGContextPointer > prngCtxBuffer = null ;
50+
51+ switch (algName ) {
52+ case "SHA256" :
53+ prngCtxBuffer = prngContextBufferSha256 ;
54+ break ;
55+ case "SHA512" :
56+ prngCtxBuffer = prngContextBufferSha512 ;
57+ break ;
58+ default :
59+ throw new IllegalArgumentException (
60+ "Unsupported HASHDRBG algorithm: " + algName );
61+ }
62+
63+ prngCtx = prngCtxBuffer .get ();
64+ if (prngCtx == null ) {
65+ prngCtx = new PRNGContextPointer (algName , this .nativeInterface , this .provider );
66+ prngCtxBuffer .set (prngCtx );
67+ }
3868
39- this . provider . registerCleanable ( this , cleanOCKResources ( ockPRNGContextId , nativeInterface ) );
69+ return prngCtx . getCtx ( );
4070 }
4171
4272 public synchronized void nextBytes (byte [] bytes ) throws NativeException {
@@ -55,22 +85,48 @@ public synchronized void setSeed(byte[] seed) throws NativeException {
5585 }
5686
5787 if (seed .length > 0 ) {
88+ createInstanceContextForReSeed ();
5889 this .nativeInterface .EXTRAND_setSeed (ockPRNGContextId , seed );
5990 }
6091 }
6192
62- private Runnable cleanOCKResources (long ockPRNGContextId , NativeInterface nativeInterface ) {
93+ private void createInstanceContextForReSeed () throws NativeException {
94+ if (!usingThreadLocalContext ) {
95+ return ;
96+ }
97+
98+ long instanceCtx = this .nativeInterface .EXTRAND_create (algName );
99+ this .ockPRNGContextId = instanceCtx ;
100+ this .usingThreadLocalContext = false ;
101+
102+ this .provider .registerCleanable (this , cleanOCKResources (instanceCtx , nativeInterface ));
103+ }
104+
105+ private static Runnable cleanOCKResources (long ockPRNGContextId , NativeInterface nativeInterface ) {
63106 return () -> {
64107 try {
65108 if (ockPRNGContextId != 0 ) {
66109 nativeInterface .EXTRAND_delete (ockPRNGContextId );
67110 }
68111 } catch (Exception e ) {
69112 if (OpenJCEPlusProvider .getDebug () != null ) {
70- OpenJCEPlusProvider .getDebug ().println ("An error occurred while cleaning : " + e .getMessage ());
113+ OpenJCEPlusProvider .getDebug ().println ("An error occurred while cleaning: " + e .getMessage ());
71114 e .printStackTrace ();
72115 }
73116 }
74117 };
75118 }
119+
120+ private static final class PRNGContextPointer {
121+ final long prngCtx ;
122+
123+ PRNGContextPointer (String algName , NativeInterface nativeInterface , OpenJCEPlusProvider provider ) throws NativeException {
124+ this .prngCtx = nativeInterface .EXTRAND_create (algName );
125+ provider .registerCleanable (this , ExtendedRandom .cleanOCKResources (this .prngCtx , nativeInterface ));
126+ }
127+
128+ long getCtx () {
129+ return this .prngCtx ;
130+ }
131+ }
76132}
0 commit comments