Як створити криптографічно захищені випадкові числа в javascript?
Як створити криптографічно захищені випадкові числа в javascript?
Відповіді:
Ви можете, наприклад, використовувати рух миші як насіння для випадкових чисел, зчитувати час і положення миші, коли трапляється подія onmousemove, подавати ці дані до функції відбілювання, і у вас буде під рукою кілька випадкових випадків першого класу. Хоча переконайтеся, що користувач досить перемістив мишу перед тим, як використовувати дані.
Редагувати: Я сам трохи погрався з концепцією, створивши генератор паролів, я б не гарантував, що моя функція відбілювання бездоганна, але, постійно пересіваючись, я майже впевнений, що цього достатньо для роботи: ebusiness.hopto.org /generator.htm
Edit2: Зараз це начебто працює зі смартфонами, але лише відключаючи функцію дотику, поки ентропія зібрана. Інший спосіб Android не працюватиме належним чином.
.password
span
тегом, щоб полегшити копіювання / вставлення / маніпулювання. Наприклад, в даний час, якщо я скопіюю та вставлю згенеровані рядки, вони будуть вставлені як один довгий рядок.
У WHATWG обговорювали питання щодо додавання цього до об’єкта window.crypto. Ви можете прочитати обговорення та перевірити запропонований API та помилку webkit (22049).
Щойно перевірив наступний код у Chrome, щоб отримати випадковий байт:
(function(){
var buf = new Uint8Array(1);
window.crypto.getRandomValues(buf);
alert(buf[0]);
})();
window.crypto
на window.msCrypto
.
Для того, я думаю, що ваші найкращі ставки:
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 - це погано, але принаймні трохи менше, якщо це не обов’язково при кожному завантаженні сторінки.
random16byteHex.advance(Math.floor(event.keyCode/4));
надалі пропускає випадкові числа вперед на кілька мілісекунд. Це зробило б випадкові випадки використання iaac, що використовуються в цій програмі браузера, залежати від вводу користувача та швидкості обладнання / браузера, так що важко вгадати.
touchmove
( тягнути # 151 ) та devicemotion
( тягнути # 79 ).
Використовуйте 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 також може генерувати ключі прямо , що може бути кращим варіантом.
щоб отримати криптографічне сильне число з діапазону [0, 1)
(подібного до Math.random()
), використовуйте крипто :
let random = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;
console.log( random() );
Можливо, ви захочете спробувати http://sourceforge.net/projects/clipperzlib/ У ньому є реалізація Fortuna, яка є криптографічно захищеним генератором випадкових чисел. (Погляньте на src / js / Clipperz / Crypto / PRNG.js). Здається, миша також використовується як джерело випадковості.
Перш за все, вам потрібно джерело ентропії. Наприклад, рух миші, пароля або будь-якого іншого. Але всі ці джерела дуже далекі від випадкових і гарантують вам 20 біт ентропії, рідко більше. Наступним кроком, який вам потрібно зробити, є використання такого механізму, як "KDF на основі пароля", що зробить обчислювально важким відрізнити дані від випадкових.
Багато років тому вам довелося застосувати власний генератор випадкових чисел і засіяти його ентропією, зібраною за допомогою руху миші та інформації про час. Це була ера Флогістона з криптографії JavaScript. Цими днями нам доводиться window.crypto
працювати.
Якщо вам потрібно випадкове ціле число , відмінним вибором є випадкове число-csprng . Він надійно генерує серію випадкових байтів, а потім перетворює її в неупереджене випадкове ціле число.
const randomInt = require("random-number-csprng");
(async function() {
let random = randomInt(10, 30);
console.log(`Your random number: ${random}`);
})();
Якщо вам потрібно випадкове число з плаваючою комою, вам доведеться виконати трохи більше роботи. Як правило, проте, захищена випадковість - це ціла проблема, а не проблема з плаваючою комою.