Zufallszahlen in Javascript sichern?


80

Wie generiere ich kryptografisch sichere Zufallszahlen in Javascript?


3
Was genau meinst du mit "kryptografisch"? Verwenden Sie Math.random (), um eine Zufallszahl zwischen 0 und 1 zurückzugeben. Es ist technisch pseudozufällig, da es keine (einfache) Möglichkeit gibt, echte Zufallszahlen zu generieren.
Logic Artist

26
Ich denke, die Frage ist nach einem Zufallszahlengenerator, der für die Kryptographie geeignet ist. Z.B. Das von vielen Sprachen standardmäßig implementierte Modulo-RND wäre nicht geeignet.
Winwaed


18
@Logic Artist - Nein, Math.random ist nicht kryptografisch sicher. Kryptografisch sicher ist ein Standardbegriff, der bedeutet, dass der Wert selbst für einen Gegner, der bereit ist, viel Zeit und Energie zu investieren, um ihn vorherzusagen oder von zufällig zu unterscheiden, unvorhersehbar ist.
DW

Antworten:


24

Sie können beispielsweise die Mausbewegung als Startwert für Zufallszahlen verwenden, die Zeit und die Mausposition jedes Mal auslesen, wenn das Ereignis "Onmousemove" eintritt, diese Daten einer Bleaching-Funktion zuführen und Sie haben einen erstklassigen Zufall zur Hand. Stellen Sie jedoch sicher, dass der Benutzer die Maus ausreichend bewegt hat, bevor Sie die Daten verwenden.

Bearbeiten: Ich habe selbst ein bisschen mit dem Konzept gespielt, indem ich einen Passwortgenerator erstellt habe. Ich würde nicht garantieren, dass meine Bleaching-Funktion einwandfrei ist, aber ich bin mir ziemlich sicher, dass es genug für den Job ist, wenn ich ständig neu gesät werde: ebusiness.hopto.org /generator.htm

Edit2: Es funktioniert jetzt irgendwie mit Smartphones, aber nur durch Deaktivieren der Touch-Funktionalität, während die Entropie erfasst wird. Android funktioniert auf andere Weise nicht richtig.


11
Hier ist eine Kryptobibliothek mit einer BSD-Lizenz und einem Zufallszahlengenerator: crypto.stanford.edu/sjcl
aaaaaaaaaaaa

Dies scheint die Anforderungen des OP zu erfüllen.
Präsident James K. Polk

SJCL (die Stanford Crypto Library) scheint eine ausgezeichnete Wahl zu sein. Sie haben ein veröffentlichtes Papier, das detailliert beschreibt, wie sie kryptografisch zufällige Zahlen erzeugen, und ihr Ansatz sieht solide und gut durchdacht aus.
DW

Ich habe einen Vorschlag eBusiness: Fügen Sie ein Trennzeichenfeld hinzu, das dazu führt, dass diese Zeichenfolge zwischen die einzelnen .password spanTags eingefügt wird , um das Kopieren / Einfügen / Bearbeiten zu vereinfachen. Wenn ich derzeit beispielsweise die generierten Zeichenfolgen kopiere und einfüge, werden sie als eine lange Zeichenfolge eingefügt.
Trusktr

Beachten Sie, dass dies auf einer mobilen Plattform nicht funktioniert, da keine Maus vorhanden ist. Daher benötigen Benutzer dieser Funktion eine Fallback-Zufallszahlenquelle.
Matt Eskridge

61

Bei WHATWG wurde diskutiert, dies dem window.crypto-Objekt hinzuzufügen. Sie können die Diskussion lesen und den vorgeschlagenen API- und Webkit-Fehler (22049) überprüfen.

Habe gerade den folgenden Code in Chrome getestet , um ein zufälliges Byte zu erhalten:

(function(){
  var buf = new Uint8Array(1);
  window.crypto.getRandomValues(buf);
  alert(buf[0]);
})();


Es funktioniert in IE 11 , wenn Sie ersetzen window.cryptomit window.msCrypto.
Michael Kropat

28

In Ordnung, ich denke, Ihre besten Wetten sind:

  1. window.crypto.getRandomValues ​​oder window.msCrypto.getRandomValues
  2. Die randomWords-Funktion der sjcl-Bibliothek ( http://crypto.stanford.edu/sjcl/ )
  3. Der Zufallszahlengenerator der isaac-Bibliothek (der von Math.random erstellt wurde, also nicht wirklich kryptografisch sicher ist) ( https://github.com/rubycon/isaac.js )

window.crypto.getRandomValues ​​ist seit einiger Zeit in Chrome und vor relativ kurzer Zeit auch in Firefox implementiert. Leider implementieren Internet Explorer 10 und früher die Funktion nicht. IE 11 hat window.msCrypto, was dasselbe bewirkt. sjcl verfügt über einen großen Zufallszahlengenerator, der aus Mausbewegungen erstellt wurde. Es besteht jedoch immer die Möglichkeit, dass sich die Maus nicht ausreichend bewegt hat, um den Generator zu erstellen, oder dass sich der Benutzer auf einem mobilen Gerät befindet, auf dem überhaupt keine Mausbewegung erfolgt. Daher empfehle ich einen Fallback-Fall, in dem Sie immer noch eine nicht sichere Zufallszahl erhalten können, wenn Sie keine andere Wahl haben. So habe ich damit umgegangen:

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;
};

Sie müssen sjcl.js und isaac.js für diese Implementierung einschließen und den sjcl-Entropiekollektor starten, sobald Ihre Seite geladen ist:

sjcl.random.startCollectors();

sjcl ist BSD und GPL mit zwei Lizenzen, während isaac.js MIT ist. Daher ist es absolut sicher, beide in jedem Projekt zu verwenden. Wie in einer anderen Antwort erwähnt, ist Clipperz eine weitere Option, die jedoch aus irgendeinem bizarren Grund unter der AGPL lizenziert ist. Ich habe noch niemanden gesehen, der zu verstehen scheint, welche Auswirkungen dies auf eine JavaScript-Bibliothek hat, aber ich würde es allgemein vermeiden.

Eine Möglichkeit, den von mir veröffentlichten Code zu verbessern, besteht darin, den Status des isaac-Zufallszahlengenerators in localStorage zu speichern, damit er nicht jedes Mal neu gesetzt wird, wenn die Seite geladen wird. Isaac wird eine zufällige Sequenz erzeugen, aber für Kryptographiezwecke ist der Keim von entscheidender Bedeutung. Das Seeding mit Math.random ist schlecht, aber zumindest etwas weniger schlecht, wenn es nicht unbedingt bei jedem Laden einer Seite auftritt.


Ich habe diesen Ansatz unter github.com/simbo1905/srp-6a-demo/blob/master/srp/Client/lib/… verfolgt , um eine zufällige 128-Hex-Zahl zu erstellen. Es Benutzer window.crypto sonst isaac. Wenn isaac verwendet werden muss, wird der Generator beim Laden aufgeladen, indem Zufälle für 0,1 s übersprungen werden. Das Texteingabefeld onkeyup in dient auch random16byteHex.advance(Math.floor(event.keyCode/4));dazu, Zufallszahlen für einige Millisekunden weiter zu überspringen. Das würde dazu führen, dass die in dieser Browser-App verwendeten isaac-Zufälle von Benutzereingaben und der Hardware- / Browsergeschwindigkeit abhängen, was sehr schwer zu erraten ist.
Simbo1905

1
@ZeroG In Bezug auf Ihre Kommentare über SJCL: „Es gibt immer eine Chance , dass entweder die Maus nicht ausreichend , den Generator auf Saatgut verschoben hat, oder dass der Benutzer auf einem mobiles Gerät ist , wo es keine Bewegung der Maus ist auch immer“ . Es funktioniert jetzt gut auf Mobilgeräten, da die Entropie jetzt von touchmove( Pull # 151 ) und devicemotion( Pull # 79 ) gesammelt wird .
TachyonVortex

1
es scheint, dass sjcl bereits window.crypto verwendet
Ales

14

Verwenden Sie window.crypto.getRandomValueswie folgt:

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

Dies wird in allen modernen Browsern unterstützt und verwendet den Zufallsgenerator des Betriebssystems (z /dev/urandom. B. ). Wenn Sie IE11-Kompatibilität benötigen, müssen Sie deren vorangestellte Implementierung über verwenden var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..).

Beachten Sie, dass die window.cryptoAPI auch Schlüssel direkt generieren kann , was möglicherweise die bessere Option ist.


Ich denke, Sie meinten Uint8Array (überprüfen Sie die Rechtschreibung)
Flyingkiwi

1
Ist "Schlüssellänge" hier der richtige Begriff? Und lauten die Schlüssellängen nicht auf Bits?
Indolering

1
Wie verwende ich window.crypto.getRandomValues, wenn ich Zufallszahlen in einem bestimmten Bereich generieren möchte, z. B. 4000-64000, und jedes Mal 1 Zufallszahl benötige?
Sid

2
@Sid Das klingt nach einer hervorragenden Frage. Fragen Sie es !
Phihag

2
@phihag: schon getan, bisher keine Antworten. stackoverflow.com/questions/41437492/…
Sid

6

Verwenden Sie Krypto , um eine kryptografisch starke Zahl aus dem Bereich [0, 1)(ähnlich Math.random()) zu erhalten :

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

console.log( random() );


4

Vielleicht möchten Sie http://sourceforge.net/projects/clipperzlib/ ausprobieren. Es enthält eine Implementierung von Fortuna , einem kryptografisch sicheren Zufallszahlengenerator. (Schauen Sie sich src / js / Clipperz / Crypto / PRNG.js an.) Es scheint, dass die Maus auch als Quelle der Zufälligkeit verwendet wird.


Weitere Informationen zur Bibliothek finden Sie hier clipperz.com/open_source/javascript_crypto_library
ameer

1
Gute Antwort, leider ist es unter der AGPL lizenziert, was meiner Meinung nach nicht mit meinem Projekt kompatibel ist.
Kyle

Ab meinem 2. Mai 2014 wechselte Clipperz von AGPL zu BSD auf Commit c9f12e87c7ac88e4612de4d1d70df7c53f77e2ad
GGG

1

Zunächst benötigen Sie eine Entropiequelle. Zum Beispiel die Bewegung der Maus, des Passworts oder eines anderen. Aber all diese Quellen sind alles andere als zufällig und garantieren Ihnen 20 Entropiebits, selten mehr. Der nächste Schritt, den Sie ausführen müssen, ist die Verwendung des Mechanismus wie "Passwortbasiertes KDF". Dadurch wird es rechnerisch schwierig, Daten von zufälligen zu unterscheiden.


0

Vor vielen Jahren mussten Sie Ihren eigenen Zufallszahlengenerator implementieren und ihn mit Entropie ausstatten, die durch Mausbewegungen und Timing-Informationen gesammelt wurde. Dies war die Phlogiston-Ära der JavaScript-Kryptographie. In diesen Tagen müssen wir window.cryptomit arbeiten.

Wenn Sie eine zufällige Ganzzahl benötigen , ist random-number-csprng eine gute Wahl. Es generiert sicher eine Reihe von zufälligen Bytes und konvertiert sie dann in eine unverzerrte zufällige Ganzzahl.

const randomInt = require("random-number-csprng");
(async function() {
    let random = randomInt(10, 30);
    console.log(`Your random number: ${random}`);
})();

Wenn Sie eine zufällige Gleitkommazahl benötigen, müssen Sie etwas mehr arbeiten. Im Allgemeinen ist die sichere Zufälligkeit jedoch ein ganzzahliges Problem, kein Gleitkommaproblem.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.