web-dev-qa-db-ja.com

JavaScriptで乱数を保護しますか?

Javascriptで暗号的に安全な乱数を生成するにはどうすればよいですか?

75
Kyle

たとえば、マウスの動きを乱数のシードとして使用し、onmousemoveイベントが発生するたびに読み出し時間とマウス位置を使用し、そのデータをホワイトニング関数にフィードすると、いくつかのファーストクラスランダムが手元にあります。ただし、データを使用する前に、ユーザーがマウスを十分に動かしたことを確認してください。

編集:パスワードジェネレーターを作成することで、この概念を少し試してみましたが、ホワイトニング機能が完璧であることを保証するわけではありませんが、絶えず再シードされているので、ebusiness.hopto.orgには十分だと確信しています。 /generator.htm

Edit2:スマートフォンで機能するようになりましたが、エントロピーが収集されている間はタッチ機能を無効にします。 Androidは他の方法では適切に動作しません。

23
aaaaaaaaaaaa

これをwindow.cryptoオブジェクトに追加することについて、WHATWGで議論がありました。 ディスカッション を読んで、 提案されたAPI およびwebkitのバグ(22049)を確認してください。

次のコードをテストしました Chromeで ランダムバイトを取得します:

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

順番に、あなたの最善策は次のとおりだと思います:

  1. window.crypto.getRandomValuesまたはwindow.msCrypto.getRandomValues
  2. SjclライブラリのrandomWords関数( http://crypto.stanford.edu/sjcl/
  3. 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ライブラリにどのような影響があるかを理解しているように見える人はまだいませんが、普遍的にそれを避けています。

私が投稿したコードを改善する方法の1つは、isaac乱数ジェネレーターの状態をlocalStorageに保存することです。そのため、ページが読み込まれるたびに再シードされません。 Isaacはランダムシーケンスを生成しますが、暗号化の目的上、シードは非常に重要です。 Math.randomを使用したシーディングは悪いですが、すべてのページの読み込みでなくてもかまいませんが、少なくとも少し悪くはありません。

27
ZeroG

_window.crypto.getRandomValues_ を次のように使用します。

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

これは 最新のすべてのブラウザーでサポートされています で、オペレーティングシステムのランダムジェネレーターを使用します(例 _/dev/urandom_ )。 IE11との互換性が必要な場合は、接頭辞付きの実装viavar crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..)を使用する必要があります。

_window.crypto_ APIは 完全にキーを生成 も使用できることに注意してください。これはより良いオプションです。

11
phihag

http://sourceforge.net/projects/clipperzlib/ を試してみたいと思うかもしれません。これには Fortuna の実装があり、これは暗号的に安全な乱数ジェネレータです。 (src/js/Clipperz/Crypto/PRNG.jsをご覧ください)。マウスをランダム性のソースとしても使用しているようです。

4
ameer

範囲_[0, 1)_(Math.random()に類似)から暗号の強い数を取得するには、 crypto を使用します。

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

console.log( random() );_
4

まず、エントロピーのソースが必要です。たとえば、マウス、パスワード、またはその他の動き。しかし、これらのソースはすべてランダムではなく、20ビットのエントロピーを保証しますが、めったにそれ以上ではありません。次のステップは、「パスワードベースのKDF」のようなメカニズムを使用することです。これにより、データをランダムに区別するのが計算上困難になります。

1
user2674414