/dev/random

/dev/random はUnix系オペレーティングシステム (OS) における擬似デバイスの一種であり、乱数生成器として機能する。デバイスドライバその他の情報源から集めた環境ノイズを利用して、真の乱数性を得るのが目的である。全てのUnix系OSが /dev/random およびそれに類する機能を実装しているわけではない。また、それぞれの実装が、同じように振舞うわけでもない。このような擬似デバイスを実装した最初のOSはLinuxであった。

Linux 
このようなOSレベルの乱数用デバイスを実装した最初のOSカーネルが Linux であった。設計にあたっては、いかなる生成法（暗号学的ハッシュ関数など）にも脆弱性が発見され得る可能性があるという仮定を置いており、そのような脆弱性に耐性を持つよう設計されている。

この実装では、エントロピープールにおけるノイズのビット数の予測を常に保持する。このエントロピープールから乱数を生成する。/dev/random から読み出すと、エントロピープール内のノイズビット数予測から乱数バイト列のみを返す。/dev/random は、ワンタイムパッドや鍵など、高度な無作為性を必要とする場合に使われる。エントロピープールが空の場合、/dev/random から読み出そうとするとされ、環境ノイズの収集がなされるまで待たされる。

これは、真の乱数生成器となることを意図したもので、可能な限り最も無作為なデータから実際のエントロピーを抽出しようとしたものである。また、長期間あるいは高度な保護のための暗号鍵の生成に使用することを意図していた。

/dev/random と対をなす /dev/urandom ("unlocked" random source) も存在する。こちらは内部プールを再利用することで擬似乱数的な乱数ビット列を生成する。すなわち、/dev/urandom へのアクセスはブロックされることがないが、/dev/random に比べると、真の乱数ではなく擬似乱数的に生成されている。ただし、暗号論的擬似乱数生成器として機能することを意図して、一般的な擬似乱数生成器ではなく、暗号論的擬似乱数生成器を使用している。

/dev/random に書き込むことも可能である。これによりユーザーがプールに乱数データを混合させることが可能となる。たとえ書き込んだデータが乱数でなくとも害はない。というのも、エントロピー予測を増加させるioctlが必要であり、こちらは特権ユーザーでないと発行できない。現在のエントロピー量とエントロピープールの大きさは /proc/sys/kernel/random/ で得られる。

2006年3月に Gutterman らが発表した Linux の乱数生成器の暗号論的分析では、いくつかの弱点が指摘されている。その中でも最も重大な問題は、ルーターやディスクレスクライアントといった組み込みシステムや Live CD システムではブート状態が予測可能であり、環境ノイズから供給される利用可能なエントロピーが限られている点である。不揮発性メモリを持つシステムについては、シャットダウン時に乱数生成器の状態をセーブし、次回のブート時にそれを利用することを推奨している。例えばルーターでは主要なエントロピー源はネットワークトラフィックだが、この論文ではリブートをまたいで状態をセーブすることで、ルーターがサービスを開始した時点から「全てのネットワークトラフィックを潜在的攻撃者が盗み聞きする」か、ルーターの内部状態に直接アクセスする必要性を生じさせるとした。特に無線LANのルーターでは、そのネットワークトラフィックは遠隔から気づかれずに盗み聞きでき、データの暗号化のための鍵を乱数生成器で生成していることから、非常に重要である。

getrandom 
Linuxカーネル3.17で、システムコールとしてgetrandomが追加された。これは/dev/randomまたは/dev/urandomからデータを読み出すことと同じ機能を提供するシステムコールである。デフォルトでは/dev/urandom相当であり、オプションで/dev/random相当の動作も選択できる。

/dev/randomや/dev/urandomはデバイスファイルであるため、使用する際にはopenシステムコールで開く（ファイル記述子を割り当てる）必要がある。そのため、ファイル記述子が限界まで使用済みの状態では、新たにファイルを開けないため、これら乱数の読み出しも不可能になる。これはリソース枯渇攻撃に該当する。このため、システムコールとしての同機能が追加されることとなった。

FreeBSD 
FreeBSDでは、以前は Linux のような実装だったが、を使って擬似乱数列を提供する実装になっている。Linux の /dev/random とは異なり、FreeBSD の /dev/random は決してブロックしない。つまり Linux の /dev/urandom に似ており、エントロピープールではなく暗号論的擬似乱数生成器として機能することを意図している（FreeBSD では /dev/urandom は random へのシンボリックリンクである）。

攻撃者が内部状態を知らない場合、擬似乱数生成器であっても十分にセキュアであり、しかもエントロピープールよりもわかりやすい。エントロピープールによる実装は完璧に実装すれば完全にセキュアとなるが、エントロピー予測が過大だとうまく設定された擬似乱数生成器よりも弱くなる。攻撃者は場合によってはエントロピーの大部分を制御できる。例えば、ディスクレスサーバの場合、環境ノイズの多くはネットワークに由来するため、中間者攻撃に対して脆弱となる可能性がある。

他のシステム 
Unix系では、/dev/random と /dev/urandom は Solaris、Mac OS X、NetBSD、OpenBSD、Tru64 UNIX 5.1B、AIX 5.2、HP-UX 11i v2 にもある。

かつてのOpenBSDには、/dev/arandom、/dev/prandom、/dev/srandomも存在した。

Unix系以外では、Microsoft Windows NT では、似たような機能として ksecdd.sys が提供されているが、\Device\KsecDD というスペシャルファイルから読み込んでもUnix系と同様の動作はしない。暗号論的擬似乱数列を生成する方法として明記されているのは CryptGenRandom と RtlGenRandom である。

EGD 
EGD (Entropy Gathering Daemon) というソフトウェアは、/dev/random をサポートしていないUnix系システムでよく使われる。ユーザー空間で動作するデーモンであり、高品質の乱数データを提供する。OpenSSL、GNU Privacy Guard、Apache HTTP Server などの場合、/dev/random がないシステムでは EGD を利用できる。

実装としては EGD や prngd があり、各種情報源から擬似乱数的エントロピーを収集し、偏りを除去して暗号的品質を高め、Unixドメインのソケット経由（/dev/egd-pool がよく使われる）やTCPソケット経由でアクセス可能にする。エントロピー収集は子プロセスを定期的にforkして行い、頻繁に変化し予測できないシステムの各種属性（CPU、I/O、ネットワーク、ログファイルの内容、一時ディレクトリの内容など）を調べる。

EGD と乱数データを必要とする他のプログラムとのやりとりは単純なプロトコルで行う。クライアントはEGDソケットと接続し、先頭のオクテットが次のようなコマンドとなっている要求を送る。
 command 0: 現在利用可能なエントロピー量を問い合わせる。EGD はブロックすることなく提供可能な乱数バイト数をビッグエンディアンの4バイト数値としたものを返す。
 command 1: ブロックせずに乱数バイト列を得る。要求メッセージの第2バイトで乱数バイト列のバイト数を指定する（1から255）。要求されたぶんの乱数バイトがない場合、ブロックせずに提供できるぶんだけの乱数バイト列を返す（0バイトの場合もある）。応答メッセージの先頭バイトが返せた乱数バイト数、その直後に実際の乱数バイト列が続く。
 command 2: ブロックしつつ乱数バイト列を得る。要求メッセージの第2バイトで乱数バイト列のバイト数を指定する。要求されただけのエントロピーがない場合、十分な収集が行われるのを待つ。command 1 とは異なり、応答メッセージは先頭から乱数バイト列になっており、その長さは常に要求メッセージで指定されたものと同じである。
 command 3: エントロピーの更新。クライアントからEGD内部のプールに加えるエントロピーを提供する。コマンドの次の2バイトが16ビットのビッグエンディアンの整数と解釈され、供給する乱数ビット数を示す。第4バイトはその後に続く実際のデータの長さをバイト数で示す。EGDはこれを内部プールに混合し、応答メッセージは返さない。

関連項目 
 UNIX哲学
 /dev/null
 /dev/zero
 ハードウェア乱数生成器
 暗号論的擬似乱数生成器

脚注

参考文献 
 random(7): Linuxのman page
 CryptGenRandom
 RtlGenRandom

乱数
UNIX