安全が必要なプログラムは、攻撃者が推定できない「ランダムな」数(乱数)を さまざまな場面で生成しなければいけません。 たとえばランダムな数には、セッション鍵を含む公開もしくは秘密鍵や対称鍵、 さまざまなプロトコルで使用している nonce(その時だけ有効な情報)や初期 ベクトル(IV)、salt 等が該当します。 理想を言えば、乱数は真にランダムであるデータを元にすべきです。そのような 値には、放射線崩壊(ガイガー・カウンターの雑音を正確に計測)や大気の雑音、 電気回路の熱雑音があります。 コンピュータには、本物の乱数生成器として機能するハードウェア部品を搭載する ものもあります。利用できるものなら利用してください。
しかし、たいていのコンピュータには真に乱数を発生するハードウェアはついて いません。そこで乱数を発生させる方法が必要になるケースがほとんどです。発生 させる方法は、攻撃者が予想できない程度にランダムである仕組みが必要になります。 普通 3 つの仕組みが必要になります。
「推測不可能な」状態。低レベルのデバイス(キー入力やディスク・ドライブの アームのジッタ(ゆれ)等)の変化を計測することで実現します。攻撃者はこれを 制御できません。
暗号用に強化した擬似乱数発生器(PRNG)。これは内部状態を使って「ランダム」 な数を発生します。
大きなビット数(シードと結果として使われた値の両方)。 使える値がわずかなら、強力な PRNG を持っていても無駄です。理由は、攻撃者が 総当たり攻撃をかけやすくなるからです。 必要になるビット数は環境にもよりますが、暗号鍵としても利用されているので、 経験上、この鍵にもこのルールを適用します。 対称鍵(とその結果)は、少なくとも 112 ビット(3DES)を使用しています。128 ビット 使えば、多少ましになり、160 ビット以上ならより安全です。
PRNG が本当に危険なのは、コンピュータ言語のライブラリの大半に、擬似乱数発生器 (PRNG)が備わっている点にあります。これはセキュリティ用には不適切です。 繰り返しましょう。 標準的な乱数発生器をセキュリティ用に利用しないでください。 標準的な PRNG ライブラリはシミュレータやゲーム向け等に使われるもので、 鍵生成のようなセキュリティ向けのランダムさを十分に持ち合わせて いません。 暗号化していない PRNG ライブラリは、「線形合同法を用いた発生器」系が多く、 「次の」ランダムな値は「(aX+b)?od?」(X は以前の値)として計算 されます。 線形合同法を用いた発生器として優れていれば、高速で有効な統計的特性 を持ち、目的とするところにぴったり当てはまります。 そのような PRNG の問題点は、攻撃者が先々の値を簡単に推論できる点にあります (ランダムに現れたとしても)。 乱数を素早く生成する二次生成器や三次生成器のようなその他のアルゴリズムも やられてしまいます[Schneier 1996]。 つまり、安全が必要なアプリケーションでは、暗号的に強固な PRNG を利用して、乱数 を生成しなければいけません。一般的な乱数ライブラリでは十分ではありません。
鍵用に真の乱数を正しく生成できないと、問題がいろいろ発生します。Kerberos や X Window System、NFS のセキュリティホールがそれです[Venema 1996]。
できるだけ、システムに用意されているサービスを使うべきです(一般的には オペレーティングシステムが用意しているもの)。そのようなサービスは、 安全な乱数を提供できるように特に設計して作られているからです。 たとえば、Linux カーネル(1.3.30 から)は乱数生成器を持っていて、セキュリティ用 に十分対応できます。 この乱数生成器は、周囲で発生するノイズをデバイスドライバや他の情報源から 収集して、エントロピー・プールに収めます。 /dev/random にアクセスするとエントロピー・プールにあるノイズから推定 されたビット数の範囲でだけ、ランダムな値が返されてきます(エントロピー・ プールが空の場合は、周囲からノイズが集まってくるまで、呼び出しをブロック します)。 /dev/urandom でアクセスして、大きな値を要求すると、エントロピー・プール が使い果たされても値が返ってきます。 乱数を暗号化の目的で利用するなら(たとえばキーの生成のため)、/dev/random を 使ってください。 BSD系 システムも /dev/random を持っています。 Solaris は SUNWski パッケージで /dev/random を用意しています。 ハードウェアの乱数生成器が利用可能なら、ドライバをインストールしてかわりに 利用してください。 さらに詳しい情報は、システムにあるオンラインマニュアルの random(4)を参照 してください。
システムによっては、真にランダムな結果を得るのに、他の手段を捜さなければ いけないものもあります。 Unix ライクなシステムで可能な方法の 1 つに Entropy Gathering Daemon (EGD)が あります。このデーモンはシステムの動作を監視して、それをハッシュしてから乱数 にします。このデーモンは、 http://www.lothar.com/tech/crypto から取得できます。 PRNG の出力として、暗号化ハッシュ機能(たとえば、SHA-1)の利用も検討してもよい と思います。 ハッシュアルゴリズムを使えば、PRNG の出力が推測できるようになったとしても、 攻撃者は、さらにハッシュ機能も片づけなければならないからです。
自分で強力な PRNG を実装しなければならないなら、暗号的に強固な(かつ特許に抵触 しない) PRNG である Yarrow アルゴリズムを採用するのが良いでしょう。Yarrow に ついては http://www.counterpane.com/yarrow.html でさらに知ることができます。 PRNG には他にも便利に使えるものがありますが、広く利用されているものには既知 の弱点を持つものがあり、アプリケーションによっては問題になる場合も考えられます。 PRNG を自分で実装する前に [Kelsey 1998] や [McGraw 2000a]のような文献を 調べてください。 IETF RFC 1750 も調べた方が良いでしょう。 【訳註:IETF RFC 1750 の日本語訳は、 http://www.ipa.go.jp/security/rfc/RFC1750JA.html にあります】