Javascriptで暗号学的に強力な疑似乱数(または真の乱数)を生成する良い方法はありますか?
重要な要件:a.comのJavaScriptがいくつかの乱数を生成する場合、他の誰もそれらの乱数を予測することはできません。たとえば、evil.comのJavaScriptは、a.comが取得した乱数を予測できないはずです。
この主題について私が知っていることの要約。これは私が自分の研究で見つけたものです:
すべてのブラウザは、疑似乱数を生成するためのライブラリ呼び出しとしてMath.random()
を提供しています。残念ながら、それは暗号品質の乱数を提供せず、上記の要件を満たしていません。私が見たブラウザでは、Math.random()
は暗号化されていないPRNGを使用しており、その内部状態は複数のサイトで共有されています。したがって、evil.comはMath.random()
を何度も呼び出し、PRNGの内部状態を回復し、Math.random()
を呼び出したときにa.comが取得した乱数を推測できます。また、非暗号品質のPRNGを使用するため、a.comがMath.random()
を使用してランダムキーとランダムIVを生成し、IVを公開すると、PRNGの内部状態を推測できる場合があります( IV)から、キーを回復します。したがって、Math.random()
はすぐに使用できます。
JavaScriptで暗号化を行うことを検討する研究論文を見つけました。彼らのコード Stanford Javascript Crypto Library は公開されています。暗号強度の疑似乱数が含まれています。
ただし、これには大きな制限があるようです。私が紙を正しく読んでいる場合、疑似乱数が適切にシードされるまでに、サイトとのユーザーの対話に10〜40秒かかります。さらに、各サイトは最初からやり直す必要があります。a.comにSJCLライブラリが含まれている場合、a.comのスクリプトは、ユーザーがa.comサイトと対話するのを(通常)10〜40秒待つ必要があるようです。 a.comが暗号品質の乱数を生成できるようになる前。これはかなり重要な制限です。
ここに彼らの論文があります:
古典的なエッセイ Javascript暗号化は有害と見なされます は、Javascriptで暗号強度の乱数を取得するための適切な方法がないことを、Javascriptで安全な暗号化を行うための主要な障壁として言及しています。エッセイはいくつかの明白なアプローチを考慮し、なぜそれらに欠陥があるのかを説明します。
肝心なことは、私が妥当な解決策を知らないということです。私が見つけたオプションはすべてかなり問題があるようです。しかし、それらの論文やエッセイが書かれてから数年が経ち、ウェブ技術は急速に変化する可能性があります。誰かがこの問題の良い解決策を知っていますか?
このための実験的なAPIがあります: window.crypto.getRandomValues 。
それはでサポートされています
Opera 12はこのAPIをサポートしていませんが、Math.Random
は安全です。
Operaはwindow.crypto.getRandomValues()をまだ実装していません。ただし、私たちのMath.Random()は暗号的に安全なランダムジェネレーターを使用しています。注意深く使用すると(呼び出しごとに53ビットのエントロピーしか返さないことに注意)、それを使用してjava.scriptバージョンのwindow.crypto.getRandomValues()を実装できます。これは、コード内のいくつかの適切なコメントとともに、Operaでのみ行うようにしてください。
http://lists.w3.org/Archives/Public/public-webcrypto/2013Jan/0063.html
Webのコンテキストでは、Javascriptは信頼できるWebサーバー(つまり、変更されたコードを送信することにより、非常に厄介な能力をすでに持っているWebサーバー)によって提供されます。あなたはそれを信頼し続け、そのサーバーからランダムなシードを要求するかもしれません、セカンダリAjax呼び出しで、または単にサーバーにランダムなシードをJavascriptコードに直接含めるようにすることで、これは数行の問題です/ PHP code。のようなもの:
_<script src="theJavascriptCode.js"></script>
<?php
$randblob = bin2hex(openssl_random_pseudo_bytes(16));
echo "<script>init_PRNG(\"$randblob\")</script>"
?>
_
JavaScriptコードには、適切なPRNG実装を含めることができ、init_PRNG()
関数を介してシードされます。
(ただし、ずさんなインテグレーターに対する安全性は難しいかもしれません。Javascriptだけでは、そのシードが実際には強力なPRNGから提供されたものであり、弱いものやハードコーディングされたサーバー側から提供されたものではないことを簡単にテストすることはできません。)
残念ながら、ブラウザは強力な乱数を生成するのに十分なエントロピーを提供していません。それは常にユーザビリティの妥協になると思います。
seedrandom.js (BSDライセンス)を見てみます。それはRC4に基づいており、非常に人気があるようです。かなり単純なAPIを使用して、独自のソースからエントロピーをプラグインできます。私はそれを1度だけ使用したことがあり、セキュリティプルーフを実際に調べたことはありませんが、他の多くのソリューションよりも簡単で高速です。
私の追加のエントロピーソースは次のとおりです。
mt_Rand()
およびmicrotime()
出力のハッシュまた、ネットワーク経由でいくつかのAjax呼び出しの時間を計り、それらのタイミングをプールに追加することもできます。
それが実際にどれだけのエントロピーを生み出したかはわかりませんが、ユーザーに迷惑をかけずに手に入れたいと思っていただけの量でした。
Javascript Crypto Library に含まれるFortuna実装を試すこともできます(AGPL 3ライセンス)。
( Clipperz によって作成された、オンラインパスワードマネージャー、私は共同創設者です)