Безопасные случайные числа в JavaScript? - PullRequest
76 голосов
/ 03 ноября 2010

Как генерировать криптографически безопасные случайные числа в javascript?

Ответы [ 7 ]

59 голосов
/ 31 мая 2011

На WHATWG обсуждалась возможность добавления этого в объект window.crypto.Вы можете прочитать обсуждение и проверить предложенный API и ошибку webkit (22049).

Просто протестировал следующий код в Chrome , чтобыполучить случайный байт:

(function(){
  var buf = new Uint8Array(1);
  window.crypto.getRandomValues(buf);
  alert(buf[0]);
})();
27 голосов
/ 06 октября 2013

В порядке, я думаю, ваши лучшие ставки следующие:

  1. window.crypto.getRandomValues ​​или window.msCrypto.getRandomValues ​​
  2. Функция randomWords библиотеки sjcl (* 1007)* Генератор случайных чисел библиотеки isaac (который заполняется Math.random, поэтому не особо криптографически защищен) (https://github.com/rubycon/isaac.js)

window.crypto.getRandomValues ​​был реализован в Chrome дляв настоящее время, а также относительно недавно в Firefox. К сожалению, Internet Explorer 10 и более ранние версии не реализуют эту функцию. В IE 11 есть window.msCrypto, который выполняет то же самое. У sjcl есть отличный генератор случайных чисел, созданный из движений мыши, новсегда есть вероятность, что либо мышь не будет двигаться достаточно для посева генератора, либо пользователь находится на мобильном устройстве, где нет движения мыши, поэтому я рекомендую использовать запасной вариант, в котором вы все еще можете получитьнебезопасное случайное число, если нет выбора. Вот как я справляюсьсделайте так:

function GetRandomWords (wordCount) {
    var randomWords;

    // First we're going to try to use a built-in CSPRNG
    if (window.crypto && window.crypto.getRandomValues) {
        randomWords = new Int32Array(wordCount);
        window.crypto.getRandomValues(randomWords);
    }
    // Because of course IE calls it msCrypto instead of being standard
    else if (window.msCrypto && window.msCrypto.getRandomValues) {
        randomWords = new Int32Array(wordCount);
        window.msCrypto.getRandomValues(randomWords);
    }
    // So, no built-in functionality - bummer. If the user has wiggled the mouse enough,
    // sjcl might help us out here
    else if (sjcl.random.isReady()) {
        randomWords = sjcl.random.randomWords(wordCount);
    }
    // Last resort - we'll use isaac.js to get a random number. It's seeded from Math.random(),
    // so this isn't ideal, but it'll still greatly increase the space of guesses a hacker would
    // have to make to crack the password.
    else {
        randomWords = [];
        for (var i = 0; i < wordCount; i++) {
            randomWords.push(isaac.rand());
        }
    }

    return randomWords;
};

Для этой реализации вам нужно будет включить sjcl.js и isaac.js, и обязательно запустите сборщик энтропии sjcl, как только ваша страница загрузится:

sjcl.random.startCollectors();

sjcl - это BSD и GPL с двойной лицензией, тогда как isaac.js - это MIT, поэтому совершенно безопасно использовать любой из них в любом проекте.Как упоминалось в другом ответе, clipperz - это еще один вариант, однако по какой-то причудливой причине он лицензируется в соответствии с AGPL.Я еще не видел никого, кто, по-видимому, понимает, какое значение это имеет для библиотеки JavaScript, но я бы универсально избегал этого.

Один из способов улучшить код, который я разместил, может состоять в сохранении состояниягенератор случайных чисел isaac в localStorage, поэтому он не перезапускается при каждой загрузке страницы.Исаак сгенерирует случайную последовательность, но для целей криптографии семя очень важно.Заполнение с помощью Math.random - это плохо, но, по крайней мере, немного менее плохо, если это не обязательно при каждой загрузке страницы.

23 голосов
/ 03 ноября 2010

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

Редактировать: я сам немного поиграл с концепцией, создав генератор паролей, я не гарантирую, что моя функция отбеливаниябезупречный, но постоянно повторяющийся, я почти уверен, что этого достаточно для работы: ebusiness.hopto.org/generator.htm

Edit2: теперь это вроде работает со смартфонами, но только при отключении сенсорной функциональности во времяэнтропия собрана.Android не будет работать должным образом.

11 голосов
/ 06 декабря 2015

Используйте window.crypto.getRandomValues, например:

var random_num = new Uint8Array(2048 / 8); // 2048 = number length in bits
window.crypto.getRandomValues(random_num);

Это поддерживается во всех современных браузерах и использует генератор случайных чисел операционной системы (например, /dev/urandom). Если вам нужна совместимость с IE11, вы должны использовать их префиксную реализацию через var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..).

Обратите внимание, что window.crypto API также может генерировать ключи напрямую , что может быть лучшим вариантом.

4 голосов
/ 03 ноября 2010

Вы можете попробовать http://sourceforge.net/projects/clipperzlib/ Он имеет реализацию Fortuna , которая является криптографически безопасным генератором случайных чисел. (Посмотрите на src / js / Clipperz / Crypto / PRNG.js). Похоже, что мышь используется как источник случайности.

2 голосов
/ 26 марта 2019

для получения криптографического строгого числа из диапазона [0, 1) (аналогично Math.random()) используйте crypto :

let random = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;

console.log( random() );
1 голос
/ 02 августа 2014

Прежде всего, вам нужен источник энтропии.Например, движение мышью, паролем или любым другим.Но все эти источники очень далеки от случайных и гарантируют вам 20 бит энтропии, редко больше.Следующий шаг, который вам нужно сделать, - это использовать механизм типа «KDF на основе пароля», который в вычислительном отношении усложнит различие данных со случайными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...