Crypto.getRandomValues: примеры (JAVASCRIPT)

Использование crypto.getRandomValues в JavaScript: полное руководство
Раздел: Crypto, Генерация
crypto.getRandomValues(array (TypedArray)): TypedArray

Базовое описание функции

crypto.getRandomValues() - это метод объекта crypto, доступный в современных браузерах и средах выполнения JavaScript, таких как Node.js. Его основное назначение - генерация криптографически стойких случайных значений.

Функция используется в ситуациях, требующих высокой степени энтропии и безопасности, например при создании токенов, ключей сессий, UUID, соли для хеширования паролей или любых других значений, где предсказуемость может стать уязвимостью.

Метод принимает один обязательный аргумент:

  • typedArray: Типизированный массив (Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, BigUint64Array), который будет заполнен случайными байтами. Размер массива ограничен 65536 байтами.

Возвращаемое значение: тот же самый типизированный массив, переданный в аргументе, но с заполненными случайными значениями. Изменения происходят по ссылке.

Простые примеры использования

Генерация массива из 10 случайных байтов:

const array = new Uint8Array(10);
console.log('До:', array);
crypto.getRandomValues(array);
console.log('После:', array);
До: Uint8Array(10) [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
После: Uint8Array(10) [ 132, 78, 201, 54, 12, 99, 45, 211, 3, 180 ]

Создание массива случайных 32-битных целых чисел:

const intArray = new Int32Array(5);
crypto.getRandomValues(intArray);
console.log(intArray);
Int32Array(5) [ -1834567234, 987654321, 123456789, -456123987, 214748364 ]

Использование BigUint64Array для очень больших чисел:

const bigArray = new BigUint64Array(3);
crypto.getRandomValues(bigArray);
console.log(bigArray);
BigUint64Array(3) [ 12345678901234567890n, 9876543210987654321n, 5555555555555555555n ]

Альтернативные функции в JavaScript

Math.random() - наиболее известная функция, генерирующая псевдослучайное число от 0 (включительно) до 1 (исключительно). Она не является криптографически стойкой и использует детерминированный алгоритм, что делает ее значения потенциально предсказуемыми. Подходит для небезопасных задач, таких как визуальные эффекты, игры или случайная сортировка массивов.

crypto.randomUUID() - функция для генерации уникальных идентификаторов (UUID версии 4). Внутренне использует криптографически стойкий генератор случайных чисел. Предпочтительна для создания ID сессий, токенов или уникальных ключей в базе данных.

В среде Node.js доступен модуль crypto с функцией crypto.randomBytes(), которая возвращает буфер со случайными байтами. Также есть crypto.randomInt() для генерации случайного целого числа в заданном диапазоне.

Аналоги в других языках программирования

Python (модуль secrets): Предоставляет криптографически стойкие функции для генерации случайных данных.

import secrets
# Генерация 10 случайных байт
random_bytes = secrets.token_bytes(10)
print(random_bytes.hex())
# Генерация случайного 32-битного целого
random_int = secrets.randbits(32)
print(random_int)
a3f87c1b4e92d0
305419896

PHP (random_bytes, random_int): Функции из модуля random.

<?
// Генерация 10 случайных байт
$bytes = random_bytes(10);
echo bin2hex($bytes) . "\n";
// Генерация случайного целого в диапазоне
$int = random_int(1, 1000);
echo $int;
?>
4d2e8f1a6b3c9d
742

C (функция rand из stdlib.h): Не является криптографически стойкой. Для безопасности используют функции из openssl/RAND_bytes.h или системные вызовы, такие как /dev/urandom в Unix-системах.

#include 
#include 
#include 
int main() {
    srand(time(NULL));
    int r = rand();
    printf("%d", r);
    return 0;
}
1804289383

MySQL (функция RAND): Генерирует псевдослучайное число с плавающей точкой. Не подходит для криптографии.

SELECT RAND();
0.654321

Распространенные ошибки

1. Превышение квоты байтов. Метод выбрасывает исключение QuotaExceededError, если длина переданного массива превышает 65536 байт.

try {
    // Uint8Array с длиной 70000 элементов = 70000 байт > 65536
    const hugeArray = new Uint8Array(70000);
    crypto.getRandomValues(hugeArray);
} catch (e) {
    console.error('Ошибка:', e.name, '-', e.message);
}
Ошибка: QuotaExceededError - Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (70000) exceeds the number of bytes of entropy that are available (65536).

2. Передача неподдерживаемого типа массива.

try {
    const floatArray = new Float64Array(5);
    crypto.getRandomValues(floatArray); // Float64Array не поддерживается
} catch (e) {
    console.error('Ошибка:', e.name);
}
Ошибка: TypeError

3. Использование обычного массива вместо типизированного.

try {
    const normalArray = [];
    crypto.getRandomValues(normalArray);
} catch (e) {
    console.error('Ошибка:', e.name);
}
Ошибка: TypeError

История изменений

Изначально метод crypto.getRandomValues() поддерживал ограниченный набор типизированных массивов: Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array.

С появлением поддержки больших целых чисел (BigInt) в JavaScript, спецификация Web Cryptography API была расширена. В современных браузерах (начиная с версий Chrome 67, Firefox 78, Safari 15) метод также поддерживает BigInt64Array и BigUint64Array.

Эти изменения позволяют генерировать криптографически стойкие случайные 64-битные целые числа, что полезно для работы с большими числовыми пространствами.

Расширенные примеры применения

1. Генерация криптографически стойкой случайной строки заданной длины.

Пример javascript
function getRandomString(length) {
    const allowedChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    const randomArray = new Uint8Array(length);
    crypto.getRandomValues(randomArray);
    const result = [];
    randomArray.forEach(byte => {
        result.push(allowedChars.charAt(byte % allowedChars.length));
    });
    return result.join('');
}
console.log(getRandomString(16));
k7Dp9qF3mZ2aR1xY8

2. Создание случайного буфера для использования в качестве криптографического ключа (соли).

Пример javascript
function generateSalt(byteLength = 32) {
    const salt = new Uint8Array(byteLength);
    crypto.getRandomValues(salt);
    return salt;
}
const salt = generateSalt(16);
console.log('Соль (hex):', Array.from(salt).map(b => b.toString(16).padStart(2, '0')).join(''));
Соль (hex): 4a7f1c9e3d0b8a2f5c6e1d4a9b3f7c0e

3. Генерация случайного числа в заданном диапазоне без смещения (безопасный аналог Math.random). Этот метод избегает смещения, которое может возникнуть при использовании операций по модулю.

Пример javascript
function getRandomIntInRange(min, max) {
    const range = max - min + 1;
    const bytesNeeded = Math.ceil(Math.log2(range) / 8);
    const maxValidValue = 256 ** bytesNeeded - (256 ** bytesNeeded % range);
    let randomValue;
    const randomArray = new Uint8Array(bytesNeeded);
    do {
        crypto.getRandomValues(randomArray);
        randomValue = randomArray.reduce((acc, byte, index) => {
            return acc + byte * (256 ** index);
        }, 0);
    } while (randomValue >= maxValidValue);
    return min + (randomValue % range);
}
// Генерация числа от 1 до 1000 включительно
console.log(getRandomIntInRange(1, 1000));
573

4. Нестандартное использование: заполнение массива случайными значениями с последующей сортировкой для создания уникальной последовательности.

Пример javascript
function createShuffledIndexArray(length) {
    // Создаем массив индексов [0, 1, 2, ..., length-1]
    const indices = new Uint32Array(length);
    for (let i = 0; i < length; i++) indices[i] = i;
    // Создаем массив случайных значений той же длины
    const randomValues = new Uint32Array(length);
    crypto.getRandomValues(randomValues);
    // Сортируем индексы на основе случайных значений
    const indicesArray = Array.from(indices);
    indicesArray.sort((a, b) => {
        const indexA = indicesArray.indexOf(a);
        const indexB = indicesArray.indexOf(b);
        return randomValues[indexA] - randomValues[indexB];
    });
    return indicesArray;
}
console.log(createShuffledIndexArray(10));
[7, 3, 9, 0, 2, 8, 5, 1, 6, 4]

5. Имитация подбрасывания монеты с использованием одного бита.

Пример javascript
function flipCoin() {
    const array = new Uint8Array(1);
    crypto.getRandomValues(array);
    // Используем только младший бит
    return (array[0] & 1) === 0 ? 'Орел' : 'Решка';
}
console.log(flipCoin());
Решка

JS crypto.getRandomValues function comments

En
Crypto.getRandomValues Generates cryptographically random values