Use thread local variables for (Secure)Randoms

This commit is contained in:
Florian Schmaus 2017-03-10 17:16:53 +01:00
parent 09b6608a3a
commit 1cc9cec677
2 changed files with 27 additions and 8 deletions

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2014-2016 Florian Schmaus * Copyright 2014-2017 Florian Schmaus
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,6 +22,7 @@ import java.security.SecureRandom;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Random;
import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.CallbackHandler;
@ -41,7 +42,12 @@ public abstract class ScramMechanism extends SASLMechanism {
private static final byte[] SERVER_KEY_BYTES = toBytes("Server Key"); private static final byte[] SERVER_KEY_BYTES = toBytes("Server Key");
private static final byte[] ONE = new byte[] { 0, 0, 0, 1 }; private static final byte[] ONE = new byte[] { 0, 0, 0, 1 };
private static final SecureRandom RANDOM = new SecureRandom(); private static final ThreadLocal<SecureRandom> SECURE_RANDOM = new ThreadLocal<SecureRandom>() {
@Override
protected SecureRandom initialValue() {
return new SecureRandom();
}
};
private static final Cache<String, Keys> CACHE = new LruCache<String, Keys>(10); private static final Cache<String, Keys> CACHE = new LruCache<String, Keys>(10);
@ -292,8 +298,9 @@ public abstract class ScramMechanism extends SASLMechanism {
String getRandomAscii() { String getRandomAscii() {
int count = 0; int count = 0;
char[] randomAscii = new char[RANDOM_ASCII_BYTE_COUNT]; char[] randomAscii = new char[RANDOM_ASCII_BYTE_COUNT];
final Random random = SECURE_RANDOM.get();
while (count < RANDOM_ASCII_BYTE_COUNT) { while (count < RANDOM_ASCII_BYTE_COUNT) {
int r = RANDOM.nextInt(128); int r = random.nextInt(128);
char c = (char) r; char c = (char) r;
// RFC 5802 § 5.1 specifies 'r:' to exclude the ',' character and to be only printable ASCII characters // RFC 5802 § 5.1 specifies 'r:' to exclude the ',' character and to be only printable ASCII characters
if (!isPrintableNonCommaAsciiChar(c)) { if (!isPrintableNonCommaAsciiChar(c)) {

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2003-2007 Jive Software, 2016 Florian Schmaus. * Copyright 2003-2007 Jive Software, 2016-2017 Florian Schmaus.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -271,7 +271,12 @@ public class StringUtils {
* The Random class is not considered to be cryptographically secure, so * The Random class is not considered to be cryptographically secure, so
* only use these random Strings for low to medium security applications. * only use these random Strings for low to medium security applications.
*/ */
private static final Random randGen = new Random(); private static final ThreadLocal<Random> randGen = new ThreadLocal<Random>() {
@Override
protected Random initialValue() {
return new Random();
}
};
/** /**
* Array of numbers and letters of mixed case. Numbers appear in the list * Array of numbers and letters of mixed case. Numbers appear in the list
@ -299,15 +304,22 @@ public class StringUtils {
if (length < 1) { if (length < 1) {
return null; return null;
} }
final Random random = randGen.get();
// Create a char buffer to put random letters and numbers in. // Create a char buffer to put random letters and numbers in.
char [] randBuffer = new char[length]; char [] randBuffer = new char[length];
for (int i=0; i<randBuffer.length; i++) { for (int i=0; i<randBuffer.length; i++) {
randBuffer[i] = numbersAndLetters[randGen.nextInt(numbersAndLetters.length)]; randBuffer[i] = numbersAndLetters[random.nextInt(numbersAndLetters.length)];
} }
return new String(randBuffer); return new String(randBuffer);
} }
private static final SecureRandom SECURE_RANDOM = new SecureRandom(); private static final ThreadLocal<SecureRandom> SECURE_RANDOM = new ThreadLocal<SecureRandom>() {
@Override
protected SecureRandom initialValue() {
return new SecureRandom();
}
};
public static String randomString(final int length) { public static String randomString(final int length) {
if (length < 1) { if (length < 1) {
@ -315,7 +327,7 @@ public class StringUtils {
} }
byte[] randomBytes = new byte[length]; byte[] randomBytes = new byte[length];
SECURE_RANDOM.nextBytes(randomBytes); SECURE_RANDOM.get().nextBytes(randomBytes);
char[] randomChars = new char[length]; char[] randomChars = new char[length];
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
randomChars[i] = getPrintableChar(randomBytes[i]); randomChars[i] = getPrintableChar(randomBytes[i]);