Как создать криптографически безопасные случайные числа в javascript?
Безопасные случайные числа в javascript?
Ответ 1
Вы можете, например, использовать перемещение мыши в качестве семени для случайных чисел, считывать время и положение мыши всякий раз, когда происходит событие onmousemove, передавать данные в функцию отбеливания, и у вас будет случайный случай первого класса. Хотя убедитесь, что пользователь переместил мышь достаточно, прежде чем использовать данные.
Изменить: я сам немного поработал с концепцией, создав генератор паролей, я бы не стал гарантировать, что моя функция отбеливания безупречна, но, будучи постоянно перегруженным, я уверен, что это много для работы: ebusiness. hopto.org/generator.htm
Edit2: теперь он работает со смартфонами, но только отключив сенсорную функциональность, пока собрана энтропия. Android не будет работать должным образом любым другим способом.
Ответ 2
В WHATWG было обсуждено добавление этого объекта window.crypto. Вы можете прочитать обсуждение и проверить предлагаемый API и ошибка webkit (22049).
Просто протестируйте следующий код в Chrome, чтобы получить случайный байт:
(function(){
var buf = new Uint8Array(1);
window.crypto.getRandomValues(buf);
alert(buf[0]);
})();
Ответ 3
В порядке, я думаю, ваши лучшие ставки:
- window.crypto.getRandomValues или window.msCrypto.getRandomValues
- Функция случайных слов библиотеки sjcl (http://crypto.stanford.edu/sjcl/)
- Генератор случайных чисел библиотеки 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 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 является плохим, но, по крайней мере, немного менее плохим, если это не обязательно при загрузке каждой страницы.
Ответ 4
Используйте 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(..)
, хотя.
Обратите внимание, что API window.crypto
также может генерировать ключи прямо, что может быть лучшим вариантом.
Ответ 5
Возможно, вы захотите попробовать http://sourceforge.net/projects/clipperzlib/ Он имеет реализацию Fortuna, который является криптографически защищенным генератором случайных чисел. (Взгляните на src/js/Clipperz/Crypto/PRNG.js). Похоже, что мы также используем мышь как источник случайности.
Ответ 6
чтобы получить криптографическое строгое число из диапазона [0, 1)
(аналогично Math.random()
), используйте crypto:
let random = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;
console.log( random() );
Ответ 7
Прежде всего, вам нужен источник энтропии. Например, перемещение мыши, пароля или любого другого. Но все эти источники очень далеки от случайных и гарантируют вам 20 бит энтропии, а редко больше. Следующим шагом, который вам нужно предпринять, является использование механизма, такого как "KDF на основе паролей", это затруднит анализ данных с помощью случайных событий.
Ответ 8
Много лет назад вам пришлось реализовать свой собственный генератор случайных чисел и заполнить его энтропией, собранной с помощью движения мыши и информации о времени. Это была эпоха флогистона JavaScript-криптографии. В эти дни у нас есть window.crypto
для работы.
Если вам нужно случайное целое число, random-number-csprng - отличный выбор. Он безопасно генерирует серию случайных байтов, а затем преобразует их в непредвзятое случайное целое число.
const randomInt = require("random-number-csprng");
(async function() {
let random = randomInt(10, 30);
console.log('Your random number: ${random}');
})();
Если вам нужно случайное число с плавающей запятой, вам нужно сделать немного больше работы. Однако, как правило, безопасная случайность - это целочисленная проблема, а не проблема с плавающей запятой.