1. Введение
В этом кратком руководстве мы узнаем о java.security.SecureRandom,
классе, который предоставляет криптографически стойкий генератор случайных чисел.
2. Сравнение с java.util.Random
Стандартные реализации JDK для java.util.Random
используют алгоритм Linear Congruential Generator (LCG) для предоставления случайных чисел. Проблема этого алгоритма в том, что он не является криптографически стойким. Другими словами, сгенерированные значения гораздо более предсказуемы, поэтому злоумышленники могут использовать их для компрометации нашей системы.
Чтобы преодолеть эту проблему, мы должны использовать java.security.SecureRandom
в любых решениях по безопасности . Он создает криптографически стойкие случайные значения с помощью криптографически стойкого генератора псевдослучайных чисел ( CSPRNG ).
Чтобы лучше понять разницу между LCG и CSPRNG, посмотрите на приведенную ниже диаграмму, на которой представлено распределение значений для обоих алгоритмов:
3. Генерация случайных значений
Наиболее распространенным способом использования SecureRandom
является создание значений int
, long
, float
, double
или boolean
:
int randomInt = secureRandom.nextInt();
long randomLong = secureRandom.nextLong();
float randomFloat = secureRandom.nextFloat();
double randomDouble = secureRandom.nextDouble();
boolean randomBoolean = secureRandom.nextBoolean();
Для генерации значений int
мы можем передать верхнюю границу в качестве параметра:
int randomInt = secureRandom.nextInt(upperBound);
Кроме того, мы можем сгенерировать поток значений для int,
double
и long
:
IntStream randomIntStream = secureRandom.ints();
LongStream randomLongStream = secureRandom.longs();
DoubleStream randomDoubleStream = secureRandom.doubles();
Для всех потоков мы можем явно задать размер потока:
IntStream intStream = secureRandom.ints(streamSize);
а также исходные (включительно) и связанные (исключающие) значения:
IntStream intStream = secureRandom.ints(streamSize, originValue, boundValue);
Мы также можем сгенерировать последовательность случайных байтов . Функция nextBytes()
берет предоставленный пользователем массив байтов
и заполняет его случайными байтами
:
byte[] values = new byte[124];
secureRandom.nextBytes(values);
4. Выбор алгоритма
По умолчанию SecureRandom
использует алгоритм SHA1PRNG для генерации случайных значений. Мы можем явно заставить его использовать другой алгоритм, вызвав метод getInstance()
:
SecureRandom secureRandom = SecureRandom.getInstance("NativePRNG");
Создание SecureRandom
с новым
оператором эквивалентно SecureRandom.getInstance("SHA1PRNG")
.
Все генераторы случайных чисел, доступные в Java, можно найти на официальной странице документации .
5. Семена
Каждый экземпляр SecureRandom
создается с начальным семенем. Он работает как база для предоставления случайных значений и изменяется каждый раз, когда мы генерируем новое значение.
Использование оператора new или вызов
SecureRandom.getInstance()
позволит получить начальное значение по умолчанию из /dev/urandom
.
Мы можем изменить начальное значение, передав его в качестве параметра конструктора:
byte[] seed = getSecureRandomSeed();
SecureRandom secureRandom = new SecureRandom(seed);
или вызвав метод set для уже созданного объекта:
byte[] seed = getSecureRandomSeed();
secureRandom.setSeed(seed);
Помните, что если мы создадим два экземпляра SecureRandom
с одним и тем же начальным числом и для каждого из них будет выполнена одинаковая последовательность вызовов методов, они будут генерировать и возвращать идентичные последовательности чисел.
6. Заключение
В этом руководстве мы узнали, как работает SecureRandom
и как его использовать для генерации случайных значений.
Как всегда, весь код, представленный в этом руководстве, можно найти на GitHub .