アナログの「実世界」の測定を行うことは、通常、エントロピー(別名実ランダムデータ)の優れたソースです。アナログソースには常に、「収集」できる予測できないノイズが重畳されています。ただし、前述のように、測定データに偏りがないことはめったにありません。
アナログ電気測定はまた、例えばセンサーの飽和を引き起こすことによって、制御不能な影響または外部からの攻撃にさえも多かれ少なかれ影響を受けやすい可能性があります。EMIも測定に干渉する可能性があります。通話中に回線のかなり近くに配置された通常の携帯電話は、アナログ信号に大混乱をもたらす可能性があります。
バイアス
バイアスのない、均一に分布した高エントロピーの数は、一般に必要なものです。これは、それらのプロパティ(値ではない)がある程度正規化されているため、より確実に予測できるためです。
たとえば、10ビットの分解能でアナログ入力を測定する場合、理想的には、測定から収集された数値の範囲は0〜1024のすべての値をカバーし、各値はその範囲の他の値と同じ周波数(または確率)で発生します。
実際には、これらの値は、多くの場合、(多かれ少なかれ)正規分布(ガウス分布)であり、いくつかの特徴的な標準偏差、たとえばサンプルあたり約500@10ビットの平均値の周りにあります。
バイアス除去
したがって、目的のプロパティ(上記を参照)を持つランダム値を生成するには、いくつかのバイアス除去を行う必要があります。ある種のランダム性抽出器が必要です。
(一方向)ハッシュ関数や暗号化アルゴリズムなどの暗号化関数を使用すると、通常、目的の結果も簡単に生成されます。ただし、これにはコストがかかります。これらの関数の「混合」は設計上非常に強力であるため、変換後のソースデータの品質(=ランダム性)を判断することは不可能です。ハッシュされた場合、{1,2,3,4,5 ...}のような最も単純な決定論的な値のシーケンスでさえ、「ランダム」ではありませんが、すべての統計的ランダムネステストに合格する可能性が最も高いデータを生成します。すべて。
µCでのエントロピーの生成
タイミング
マイクロコントローラー環境では、めったに考えられないエントロピーの良いソースは、イベントのタイミングです。高速タイマーを使用すると、非同期イベントに応答してタイマー値を読み取ることにより、真のエントロピーを収集できます。実行中のタイマーとは相関関係のないこのようなイベントは、ユーザーによるボタンの押下、別の(サブ)システムまたはICによって開始された通信の開始、または基本的にµC(または任意の同期サブシステム)自体。
実際、エントロピーは2つの独立したクロックソースから収集することもできます。たとえば、一方のクロックのタイミングサイクルによってもう一方のクロックを経由します。これにより、µCの機能に応じて、Atmel AVR µC(Arduinoで使用される)にいくつかの非常に興味深い可能性が開かれます。
ほとんどのAVRにはEEPROMメモリが内蔵されています。このメモリへの書き込み操作は、メインシステムクロックとは独立した専用タイマーによって計時されます(-報告によると、これが当てはまらない可能性があることが測定で示されたチップ(タイプではありません!)がいくつかあります)(編集:一部のAVRでは注意してください、ATTiny25 / 45/85たとえば、EEPROMタイミングは内部RCオシレータから取得されるため、このオシレータがシステムクロックソースとしても選択されている場合、エントロピーを収集することはできません) ; これは、メインクロックソース(内部R / Cと外部水晶/共振器)に依存する場合があります。したがって、メインシステムクロックに対してEEPROMへの書き込みにかかる時間には、ある程度の(真にランダムな)ジッターが予想されます。これも高速タイマー/カウンターで測定できます。
新しいAVRには、ウォッチドッグタイマーがハードウェアリセットの代わりにソフトウェア割り込みを生成できるようにする機能があります。ウォッチドッグタイマーは、独自の独立したクロックソースによって制御されるように設計されており、測定可能な相対ジッターを生成します。
多くのAVRには、リアルタイム測定の精度を向上させるために、外部の32kHz水晶から専用のタイマー/カウンターをクロックする機能があります。この外部水晶は、メインクロックとは無関係のイベントのもう1つのソースです。(さもなければ、そもそも余分な水晶は役に立たないでしょう...)
後者は、比較的高い帯域幅の可能性を約束しているようです。各32kHzクロックサイクルのタイミングをシステムタイマーで大幅に高速化し(現在のAVR @ 20 MHzで600倍以上を達成できます)、控えめに1ビットのみを想定する場合測定あたりのエントロピーの量が増えると、これにより1秒あたり32000ビット以上のエントロピーが発生します。これは、µCが単独で消費するよりもはるかに多くなります。
編集:その間、私は32kHzタイマーアプローチのいくつかの簡単なテストを実施しました、そして短期間の結果はかなり低品質のようです。サンプルごとに生成されるエントロピーの上限は非常に低いようですが、多かれ少なかれ規則的な位相シフトに起因する非自明なパターンについてサンプルをテストしたことはありません。この結果は、私のDUTのメインクロックが外部クリスタルによって駆動されていたためである可能性があります。外部クリスタルは、限られた時間範囲で観察した場合、32kHzクォーツと同等の周波数で安定していると予想されます。2つのサンプルを取得する間の時間(分?)を延長すると、おそらく非常に低い帯域幅で、良好なエントロピーが返されます。(Nb:
編集#2:私のDUT(ATmega1284)の内部RC発振器は、かなりの周波数ジッター(数kHz / s)を生成するようです。この発振器で実行すると、外部の32kHz水晶振動子でタイミングをとると、実際にかなりのエントロピー(kBits / s)が生成されるようです。
ちょっとした実験で、私は最近、前者の2つの方法を調査しました。私のDUTでは、EEPROMのタイミングは一般的にWDTよりも有利です。
EEPROM書き込みのタイミングは、書き込み操作ごとに約4.82ビットのエントロピーを生成しましたが、ウォッチドッグタイマーは周波数的にはより安定しているようで、ウォッチドッグタイムアウトごとに約3.92ビットを生成します。さらに、EEPROMの書き込み時間は、WDTの分布がやや非対称で、多くの収差があるように見えるガウス分布の方がはるかにスムーズに見えます。
Nb:単一のエントロピー測定に対して複数の「ランダム」イベントを集約すると、実際に取得されるエントロピーが低下する可能性があります。ソースの高速でランダムな変動は、互いに部分的に補償し、平均値からの偏差が小さい結果値を生成する可能性があります。したがって、たとえば、タイミングの代わりに、1リアルタイム秒(RTCクリスタルの32kサイクル)で、同時に32kタイミング(クリスタルの各サイクルに1つ)を取ることで、はるかに多くのエントロピーが期待できます。
初期化されていないRAM
Avr-gccでコンパイルされたアプリケーションは通常、ユーザーコードを実行する前に、オンチップRAM全体を0x00にクリアしますmain()
。コードを初期.init
セクションに配置すると、gccの初期化ルーチンによって上書きされる前に、初期化されていない生のRAMコンテンツにアクセスできます。
RAMの物理ストレージセル(ビット)のわずかな変動と、真のランダム熱雑音(およびその他の影響)に応じて、電力がチップに(再)適用されたときに、すべてのセルが同じ既知の状態に初期化されるわけではありません。電源投入直後のチップのRAMの内容を何らかの機能と組み合わせると、後で使用するためにかなりの量のエントロピーが生成される可能性があります。-これの欠点は、電源をしばらくオフにしてから再びオンにした場合にのみ確実に機能することです。通常のチップリセット、ハードウェア、ソフトウェア、または外部信号によって、RAMの以前のコンテンツを保持するため、(常に)エントロピーの適切なソースではありません。ただし、かなり複雑なアプリケーションでは、リセット時のシステム全体(RAM)の状態を予測することはほとんどできないため、とにかくリセット直後にエントロピーが収集される可能性があります。
帯域幅の要件
エントロピーソースの品質は、その帯域幅とアプリケーションによるエントロピーの使用の帯域幅に関連して確認する必要があります。エントロピー収集の方法によっては、数秒間に1ビットを超えるエントロピーが生成されない場合がありますが、他の方法(実際にはµCではない...)では100 kbit/s以上が生成される場合があります。
既存のエントロピーから新しいエントロピーをアルゴリズムで「作成」することはできないことに注意する必要があります。-1ビットのエントロピーを2ビットのエントロピーに計算で変換することはできません。
したがって、(平均で)同時にエントロピーソースから収集されたものよりも多くの(実際の)エントロピーを時間単位ごとに消費することはできません。
提案
強力な乱数が必要な場合、新しいエントロピーが利用可能になるたびに収集されたエントロピーを使用してPRNGを(再)シードし、 1つ以上の実際のエントロピーのソースを強力なPRNGと組み合わせるのは珍しいことではありません。
PRNGを使用すると、エントロピーソースが実際に同時に提供するよりもはるかに基本的に予測不可能なデータを生成できます。
特殊な種類のPRNGとして、暗号暗号関数を使用できます。この場合、エントロピーを使用して暗号のキーを初期化および更新します。
Linux/dev/urandom
は一般的にこの方法で実装されます。
結論
上で説明したように、一般的なマイクロコントローラーで真の乱数を生成することは非常に可能です。他のすべてのエントロピーソースについては、エントロピーソースによって提供される生の数値を分析して、それらに含まれる実際のエントロピーの量と、時間単位ごとに生成されるエントロピーの量を分析して、ソースがユースケースかどうか。
真のエントロピーソースと強力なPRNGの組み合わせは、一般的に実装されているアプローチであり、マイクロコントローラーでも使用する必要があります。
編集:
PRNGアプローチは、暗号化キーの生成に最適な選択ではない場合があります。そのためには、安全なキーを生成するために真にランダムなビットのみを使用する必要があります。この量のエントロピーの収集には時間がかかる場合がありますが(おそらく数秒)、キーの生成は通常µCであまり頻繁に実行されないため、これは十分に許容できる場合があります。(負荷の高いサーバーでは、1秒あたり数百以上のSSL(HTTPS)接続が発生します。これはまったく別の問題になります...)
キー生成に適した高品質の高エントロピービットストリームを生成するには、上記のようなランダム性抽出器を使用する必要があります。
(一方、ソースの出力のエントロピーの量を測定または推定できる場合は、キーの長さを係数でスケーリングし(bitlength of key)/(entropy per bit sampled)
、エントロピーソースからの生の低エントロピーデータを直接使用して、この長いキーを生成できます。これにより、元の長さの完全にランダムなキーと同じ全体的なエントロピーが得られます。ただし、これが実際に行われるかどうかは、暗号がさまざまな長さのキーを処理する方法によって異なります。)