How do you generate a secure random (or pseudo-random) alphanumeric string in Java efficiently?
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'