Использование UUID небезопасно, потому что части UUID вообще не случайны. Процедура @erickson очень аккуратная, но не создает строки одинаковой длины. Следующий фрагмент должен быть достаточным:
/*
* The random generator used by this class to create random keys.
* In a holder class to defer initialization until needed.
*/
private static class RandomHolder {
static final Random random = new SecureRandom();
public static String randomKey(int length) {
return String.format("%"+length+"s", new BigInteger(length*5/*base 32,2^5*/, random)
.toString(32)).replace('\u0020', '0');
}
}
Зачем выбирать length*5
. Предположим простой случай случайной строки длины 1, поэтому один случайный символ. Чтобы получить случайный символ, содержащий все цифры 0-9 и символы a-z, нам понадобится случайное число от 0 до 35, чтобы получить один из каждого символа. BigInteger
предоставляет конструктор для генерации случайного числа, равномерно распределенного по диапазону 0 to (2^numBits - 1)
. К сожалению, 35 не является числом, которое может быть получено 2 ^ numBits - 1. Таким образом, у нас есть два варианта: либо пойти с 2^5-1=31
, либо 2^6-1=63
. Если бы мы выбрали 2^6
, мы получили бы много «лишних» / «более длинных» чисел. Поэтому 2^5
- лучший вариант, даже если мы потеряем 4 символа (w-z). Чтобы сгенерировать строку определенной длины, мы можем просто использовать номер 2^(length*numBits)-1
. Последняя проблема, если нам нужна строка с определенной длиной, случайный может генерировать небольшое число, поэтому длина не выполняется, поэтому нам нужно наложить строку на требуемую длину, добавляя нули.