Рейтинг:0

CSPRNG в Javascript?

флаг cn

Я пытаюсь получить случайное, непредсказуемое довольно длинное число (± 20-25 цифр), используя Javascript (созданный клиентом пользователя) как можно быстрее и легче. Является ли это решение надежным, надежным и безопасным?

При открытии онлайн-страницы сохраняется 13-значная метка времени. Таймер определяет количество миллисекунд, прежде чем пользователь нажмет «ОК» (предположим, что он получил короткий текст для чтения или что-то еще). Коллекция из 100 невидимых «пикселей» (1 * 1 пиксель HTML-промежутка) создается со случайно фиксированными начальными цветами RGBA (A = 0 = прозрачность).

 пусть d = Date.now(); // временная метка 13 цифр
 пусть n = 100 // количество «пикселей» 
 пусть пиксели = ''

 для (i=0; i<n; i++) {
    пусть r = Math.floor(Math.random() * 256); 
    пусть g = Math.floor(Math.random() * 256); 
    пусть b = Math.floor(Math.random() * 256);
    пусть c = 'rgba('+r+','+g+','+b+',0)'
    пикселей += '<span id="pix'+i+'" style="background-color:'+c+'"></span>'
 }

Как только это будет сделано, мы случайным образом изменим цвет каждого «пикселя» каждую сотую секунды.

 пусть changeColor = setInterval (функция () {
    для (i=0; i<n; i++) {
        пусть r = Math.floor(Math.random() * 256); 
        пусть g = Math.floor(Math.random() * 256); 
        пусть b = Math.floor(Math.random() * 256); 
        пусть c = 'rgba('+r+','+g+','+b+',0)'
        document.getElementById('pix'+i).style.backgroundColor = c
    }
 },10);

Когда пользователь нажимает «ОК», функция останавливается, определяется случайный пиксель и находятся его значения RGB.

пусть x = Math.floor (Math.random () * n); // 39
пусть px = window.getComputedStyle(document.getElementById('pix'+x),null).backgroundColor
пусть rgb = px.match(/\d+/g); // пикс 39 = [21,13,152]

Затем мы умножаем каждое значение RGB на x * случайный коэффициент [от 1 до 5]:

пусть r = rgb[0]*(x*Math.floor(Math.random() * 5)+1), // 21 * 39 * 2 = 1638
    g = rgb[1]*(x*Math.floor(Math.random() * 5)+1), // 13 * 39 * 1 = 507
    b = rgb[2]*(x*Math.floor(Math.random() * 5)+1) // 152 * 39 * 4 = 23712

Добавляя x + таймер + случайный фрагмент метки времени, мы получаем:

пусть t = Date.now()-d; // таймер по клику
пусть p = Math.floor(Math.random() * 4)+3;    
let z = d.toString().substr(-p) // последнее значение временной метки xx (3->7)

пусть val = x+''+r+g+b+''+t+z // 39 1368 507 23712 1348 55601

Затем случайным образом перемешиваем результат:

функция перемешивания (а) {
  пусть r = a.length, temp, rand;
  в то время как (0 !== г) {
    rand = Math.floor(Math.random() * r);
    г -= 1;
    темп = а[р];
    а[г] = а[ранд];
    а [ранд] = темп;
  }
  вернуть а; // 39136850723712134855601 -> 25851963017738613021534
}

  Тесты -> консоль
  17:22:34 пикс #39 = [21,13,152] 9348234523267751239843
  17:22:42 пикс #39 = [21,13,152] 109715237240854257137
  17:23:02 пикс #39 = [21,13,152] 100889146450039658553439

Если нам нужен более длинный результат (50, 100 цифр), мы можем создать 500 «пикселей» и случайным образом выбрать 10 из них вместо одного. Или добавьте значение энтропии (движение мыши на экране: https://www.grc.com/r&d/js.htm) к полученному значению. Что вы думаете?

Eugene Styer avatar
флаг dz
Из: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random: Примечание. Math.random() не предоставляет криптографически безопасные случайные числа. Не используйте их ни для чего, связанного с безопасностью. Вместо этого используйте Web Crypto API, а точнее метод window.crypto.getRandomValues().
Maarten Bodewes avatar
флаг in
Проблема с этой схемой в том, что Math.random() не предоставляет случайные числа; обычно он генерируется с использованием 32-битного начального числа, которое легко предсказать. Таким образом, единственный ввод, который кажется совершенно случайным, — это время между началом вычислений и нажатием [OK] пользователем. О, и вы включаете `Date()`, что совсем не случайно. Я полагаю, насколько это случайно, зависит больше от системы, чем от чего-либо еще. По крайней мере, я ожидаю, что кто-то, кто может запрограммировать скрипт для запуска расчета в определенное время и почти мгновенно, может заставить его быть очень неслучайным.
Maarten Bodewes avatar
флаг in
[Это было бы гораздо более случайным] (https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)
флаг ph
Использование цветных пикселей не обеспечивает никакой функциональности, кроме сохранения этих значений в массиве.
Рейтинг:1
флаг fr

Math.random не является криптографически безопасным PRNG. Например, Firefox использует генератор на основе XorShift, который выдаст все свое состояние всего за несколько вызовов. Следовательно, здесь вы не создаете случайные пиксели; вы просто выбираете значения на основе того же предыдущего семени.

MDN описывает функция Web Cryptography API для генерации криптографически безопасных случайных чисел. Если вы вместо этого работаете в Node.js, он поставляется с встроенные функции, которые делают то же самое. Они предназначены для реализации CSPRNG, обычно системного, который вам следует использовать, если вы не уверены, что вам нужно что-то еще. Они подойдут почти для всех криптографических нужд, и использование системы CSPRNG настоятельно рекомендуется большинством криптографов.

Если вам нужно что-то воспроизводимое, вы можете использовать что-то вроде ChaCha20 с ключом и одноразовым номером, сгенерированным из системного CSPRNG, или HMAC-DRBG с SHA-2 или SHA-3. Однако в большинстве ситуаций в этом нет необходимости, и по возможности лучше избегать реализации собственной криптографии в пользу известных, надежных реализаций, поэтому, если вам это действительно нужно, вам лучше использовать известную реализацию.

Wolden avatar
флаг cn
Спасибо за ответ и комментарии. Я согласен со слабостью Math.random, но помимо принципиальных позиций, делает ли он эти полученные результаты предсказуемыми и, следовательно, небезопасными. Если да, то почему и как? Спасибо за помощь в понимании, я всего лишь новичок в криптографии ;-)
Wolden avatar
флаг cn
как показано в моих последних 3-х строках (tests->console), после остановки функции определяются временная метка и пиксель. Я много раз нажимал кнопку OK, пока не нашел 3 результата для одного и того же пикселя (#39): с одинаковыми значениями RGB я получаю 3 очень разных результата. Являются ли они предсказуемыми (то есть в предсказуемом «списке возможных результатов»)?
bk2204 avatar
флаг fr
Вероятно, они достаточно предсказуемы, чтобы этот подход подвергался грубой силе. То, что это «выглядит случайным», не означает, что это непредсказуемо. Я не собираюсь проводить полный криптоанализ этого подхода, потому что я думаю, что использование системного CSPRNG, очевидно, лучше и является логичным выбором, но если вы используете `Math.random` в качестве случайного источника, где вам нужен CSPRNG, я запросить CVE для вашего программного обеспечения.
Wolden avatar
флаг cn
Спасибо за пояснения :-)
Рейтинг:0
флаг cn

Я использовал выше 6 раз функцию Math.random(), один раз, чтобы получить значение 0-> 255 (r, g, b), один, чтобы получить значение 0-> 100 (число пикселей), и некоторые другие для получить меньшие значения (т.е. 3-> 5 для метки времени)

Значение 0->255 (r,g,b) теперь берется из

    пусть rand = новый Uint8Array(3); // 3 значения 0 -> 255
    window.crypto.getRandomValues ​​(ранд);
    пусть г = ранд[0]; 
    пусть g = rand[1]; 
    пусть б = ранд[2];

и значение 0->100 (номер пикселя) из

    пусть пикс = новый Uint8Array (1);
    window.crypto.getRandomValues ​​(пиксель);
    пусть v = Math.floor(pix[0]/2.55); // значение 0->100

Как вы думаете, после того как я заменил все функции Math.random() этими новыми реализациями, они стали более безопасными и надежными/устойчивыми к атакам?

Этот вопрос на других языках:

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.