How to generate a secure random alphanumeric string in Java efficiently?
How do you gener开发者_运维问答ate a secure random (or pseudo-random) alphanumeric string in Java efficiently?
Initialize an array containing all the accepted chars (CHARS_ARRAY
), then instantiate a SecureRandom instance, and call nextInt(CHARS_ARRAY.length)
repeatedly to get a random index in your char array. Append each char to a StringBuilder
until you get the expected number of chars.
If you use Apache Commons Lang, the easiest way is
RandomStringUtils.random(20, 0, 0, true, true, null, new SecureRandom());
String chrs = "0123456789abcdefghijklmnopqrstuvwxyz-_ABCDEFGHIJKLMNOPQRSTUVWXYZ";
SecureRandom secureRandom = SecureRandom.getInstanceStrong();
// 9 is the length of the string you want
String customTag = secureRandom.ints(9, 0, chrs.length()).mapToObj(i -> chrs.charAt(i))
.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append).toString();
System.out.println(customTag);
Examples:
// q3HX6EctP
// WjRrMjQT4
// sX-Piq4DB
Here's a slightly modified version of my code from the duplicate question.
public final class RandomString
{
/* Assign a string that contains the set of characters you allow. */
private static final String symbols = "ABCDEFGJKLMNPRSTUVWXYZ0123456789";
private final Random random = new SecureRandom();
private final char[] buf;
public RandomString(int length)
{
if (length < 1)
throw new IllegalArgumentException("length < 1: " + length);
buf = new char[length];
}
public String nextString()
{
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols.charAt(random.nextInt(symbols.length()));
return new String(buf);
}
}
import java.security.SecureRandom;
import java.util.Random;
public class PasswordHelper {
public static String generatePassword (int length) {
//minimum length of 6
if (length < 6) {
length = 6;
}
final char[] allAllowed = "abcdefghijklmnopqrstuvwxyzABCDEFGJKLMNPRSTUVWXYZ0123456789".toCharArray();
//Use cryptographically secure random number generator
Random random = new SecureRandom();
StringBuilder password = new StringBuilder();
for (int i = 0; i < length; i++) {
password.append(allAllowed[random.nextInt(allAllowed.length)]);
}
return password.toString();
}
}
Using UUIDs:
UUID random = UUID.randomUUID();
System.out.println( random );
Generate a public key for an open-key encryption algorithm and convert the byte sequence to string via Base64 algorithm.
My spec for this randomly generated string was to produce a 35 character length encryption key (a-zA-Z2-7 characters only for first 25 chars). After every 5th character a -
used, and the last 5 characters were to be an integer between 10_000 and 19_999.
Here's the code for what I did (in Kotlin).
companion object {
/**
* Letters lower & upper case excluding:
*
* - l, o, B, O
*
* Numbers excluding:
*
* - 0, 1, 8, 9
* */
val acceptedChars: CharArray
get() = charArrayOf(
'a', 'b', 'c', 'd', 'e',
'f', 'g', 'h', 'i', 'j',
'k', 'm', 'n', 'p', 'q',
'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', 'A',
'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L',
'M', 'N', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '2', '3',
'4', '5', '6', '7'
)
val acceptedInts: CharArray
get() = charArrayOf(
'0', '1', '2', '3', '4',
'5', '6', '7', '8', '9'
)
fun generate(): EncryptionKey {
val random = SecureRandom()
val stringBuilder = StringBuilder()
for (i in 0 until 35) {
when (i) {
5, 11, 17, 23, 29 -> {
stringBuilder.append("-")
}
30 -> {
stringBuilder.append("1")
}
31, 32, 33, 34 -> {
val index = random.nextInt(acceptedInts.size)
stringBuilder.append(acceptedInts[index])
}
else -> {
val index = random.nextInt(acceptedChars.size)
stringBuilder.append(acceptedChars[index])
}
}
}
return EncryptionKey(stringBuilder.toString())
}
}
results produced:
value: 'nK6UI-DWYvu-dbmhD-KPe5X-22dPT-10027', length: '35'
value: 'NIFvi-aX4GW-3xCYV-YSAVs-tASIK-15301', length: '35'
value: 'SpNkT-qxHR7-hSMkK-hVxpp-AqLFh-19409', length: '35'
value: 'bNvi2-svqX7-cfEw5-LNYDn-C2FtW-16197', length: '35'
value: 'hhjLX-KmRQU-KbHyU-CkNyD-5ASk6-14537', length: '35'
value: 'Xd2cj-braCm-FaE4E-Jvn2G-2Dv5J-12243', length: '35'
value: '7beFb-aeSe2-iHXZe-mTUHT-aEbry-17349', length: '35'
value: 'NExMa-xCAbU-VkpyS-xeEkj-QUayd-16311', length: '35'
value: '52HWN-EX7wV-csbhj-InhtU-gbV46-18606', length: '35'
value: 'n3RTZ-whpjQ-ZjW5n-tTyfR-eLDSF-14003', length: '35'
value: 'aJEks-ccKdU-KGJdh-Rz4ck-tR7Uq-12199', length: '35'
value: 'nMcUF-ctbcy-FEfq7-VJhRx-pCKej-16369', length: '35'
Initialize an array containing all the accepted chars ( CHARS_ARRAY ), then instantiate a SecureRandom instance, and call nextInt(CHARS_ARRAY. length) repeatedly to get a random index in your char array. Append each char to a StringBuilder until you get the expected number of chars.
I'm not sure about efficienty (probably you can't create much more efficient variant), but this variant is simple and secure (while RandomStringUtils is not):
SecureRandom randomGenerator = new SecureRandom();
byte[] randomBytes = new byte[20];
randomGenerator.nextBytes(randomBytes);
String randomString = new BigInteger(1, randomBytes).toString(16);
It you want to a little more efficient variant, specify randomGenerator as class field or as a static field.
Taked from https://stackoverflow.com/a/44227131/5122436
http://download.oracle.com/javase/6/docs/api/java/security/SecureRandom.html
From the Javadoc:
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
精彩评论