web-dev-qa-db-ja.com

/ dev / randomのddが異なるファイルサイズを与えるのはなぜですか?

Ubuntuシステムで次のコマンドを実行しています。

dd if=/dev/random of=Rand bs=1K count=2

しかし、実行するたびに、サイズの異なるファイルができてしまいます。どうしてこれなの?ランダムなデータで満たされた特定のサイズのファイルを生成するにはどうすればよいですか?

28
Daniel

ddの特異な動作とLinuxの_/dev/random_の特異な動作の組み合わせを観察しています。ちなみに、どちらも仕事に適したツールであることはめったにありません。

Linuxの_/dev/random_は、データを控えめに返します。これは、疑似乱数ジェネレータのエントロピーが非常に速い速度で消滅するという仮定に基づいています。新しいエントロピーの収集は遅いため、_/dev/random_は通常、一度に数バイトのみを放棄します。

ddは、最初はテープデバイスで動作することを目的とした古い、気難しいプログラムです。 1kBの1ブロックを読み取るように指示すると、1ブロックを読み取ろうとします。読み取りが1024バイト未満を返す場合は、それだけで十分です。したがって、_dd if=/dev/random bs=1K count=2_は2つのread(2)呼び出しを行います。 _/dev/random_から読み取っているので、2つのread呼び出しは通常、利用可能なエントロピーに応じて異なる数の数バイトのみを返します。参照 ddがデータのコピーに適しているのはいつですか?(または、read()とwrite()が部分的である場合)

OSインストーラーまたはクローンを設計しているのでない限り、Linuxでは_/dev/random_を使用しないでください。常に_/dev/urandom_を使用してください。 urandom manページは誤解を招く可能性があります。 _/dev/urandom_は、実際には暗号化に適しています。長期間有効なキーを生成する場合にも適しています。 _/dev/urandom_の唯一の制限は、十分なエントロピーを指定する必要があることです。 Linuxディストリビューションは通常、再起動間のエントロピーを保存するため、十分なエントロピーがない可能性があるのは、フレッシュインストール時のみです。エントロピーは実際には衰えません。詳細については、 / dev/urandomのRandはログインキーに対して安全ですか? および / dev/randomエントロピープールをフィードしますか? を参照してください。

ddのほとんどの使用法は、headtailなどのツールでよりよく表現されます。 2kBのランダムバイトが必要な場合は、次を実行します。

_head -c 2k </dev/urandom >Rand
_

古いLinuxカーネルでは、

_dd if=/dev/urandom of=Rand bs=1k count=2
_

なぜなら、_/dev/urandom_は、要求されたバイト数を喜んで返したからです。しかし、カーネル3.16以降、これは当てはまりません 現在は32MBに制限されています

一般に、ddを使用して固定バイト数を抽出する必要があり、その入力が通常のファイルまたはブロックデバイスからのものでない場合は、バイトごとに読み取る必要があります:_dd bs=1 count=2048_。

RHEL 5ボックスのman 4 randomから:

/ dev/randomデバイスは、読み取られると、エントロピープール内のノイズの推定ビット数内のランダムバイトのみを返します。

そのマシンで213バイトのファイルを取得します。ランダムに男4に戻る:

読み取られると、/ dev/urandomデバイスは要求されたバイト数を返します。

dd if=/dev/urandom of=Rand bs=1K count=2の呼び出しごとに2048バイトを取得します

違いは、dd if=/dev/random ...の呼び出しの間にマシンが生成するエントロピーの量が原因であると私は結論付けます

11
Bruce Ediger

ddがデータをドロップするのはなぜですか? ...Gillesddに関するこの魅力的な質問を投げかけました:
ddがデータのコピーに適しているのはいつですか(または、read()とwrite()が部分的である場合)
これはその質問からの抜粋です:

* ... ddに誤りをつけることは難しくありません。たとえば、このコードを試してください:**
yes | dd of=out bs=1024k count=10
、出力ファイルのサイズを確認します(10MBをはるかに下回る可能性があります)。


(質問の最後にある)私のコメントは別として、このようなものは見るのが繰り返しです...ファイル$trndでバイトをキャッチします。私は任意にbs = 8を選択しました

マウスを動かして、速度が上がるのを見てください。
コンピュータがアイドル状態(AFKでネットワークアクティビティがない)で、エントロピープールを使い果たした後、2時間かかりました1192バイトのみを収集するのに12分、その時点でキャンセルしました。

次に、マウスを連続的に動かして、比較的短い115秒同じバイト数を収集します。

これは、エントロピーの収集がCPU速度ベースではなく、ランダムイベントベースであり、私のUbuntuシステムがマウスの1つを使用していることをかなり明確に示していますその重要なランダム因子。

get=2048
trnd=/tmp/$USER.rnd; >"$trnd"
while (( $(wc -c <"$trnd") < $get )) ;do
    dd if=/dev/random bs=8 count=1 2>/dev/null >>"$trnd"
    echo -n "itt: $((i+=1))  ct: "; wc -c <"$trnd"
done
truncate -s $get "$trnd"
echo -e "\nfinal count: "; wc -c <"$trnd"
5
Peter.O

dd is isdesignedfor block-これは通常、必要に応じて可変サイズの入力から読み取るのに最適なツールですimmediatelyddは現在の読み取りを将来のwrite()にバッファリングしないため(ただし、 ibs)よりも大きいobsを使用して、そのように明示的に構成しますが、代わりにwrite()が読み取るすべてのものがread()になるとすぐに(およびオプションでそれを処理します)

ここにいくつかの重要な definitions があります:

  • ibs=expr
    • 入力ブロックサイズをexprでバイト単位で指定します(デフォルトは512)
  • obs=expr
    • exprで出力ブロックサイズをバイト単位で指定します(デフォルトは512)
  • bs=expr
    • 入力と出力の両方のブロックサイズをexprバイトに設定し、ibs=obs=を置き換えます。 syncnoerror、およびnotrunc以外の変換が指定されていない場合、各入力ブロックは、短いブロックを集約せずに単一のブロックとして出力にコピーされます。

つまり、ibsobsを一緒にbsとして定義すると、ibsが優先されますが、それ以外の場合、具体的にはobsまたはcbsはそうします。

以下は、ibsが最も重要な例です。 /dev/randomプールがいっぱいになるまでの時間を追跡したい場合は、このようなことをするかもしれません...

dd "ibs=$size" conv=sync "count=$lmt" \ 
    if=/dev/random of="$somefile"

ddであるため、if=のターゲットが読み取り可能である限り、常にalwaysは同じサイズの出力ファイルになります。 synchronizeはnullで読み込まれたブロックをブロックします。つまり、read()$((size=10))回の入力ブロックに対してdd$((count=5)) sを実行し、read()ファイルが2バイトを返す場合、次に、8バイト、12バイト、2バイト、4バイトのように、ddは次のような出力ファイルに書き込みます

 2 read bytes 8NULs \
 8 read bytes 2NULs \
10 read bytes 0NULs \
 4 read bytes 6NULs \
 4 read bytes 6NULs

...ddは、デフォルトでは遅延しないためです。したがって、インストリームを追跡して他のプロセスの書き込みを区切る必要がある場合は、ddが最適です。

通常のファイルに一定量のデータを書き込むだけの場合は、ここで行った他のステートメントとは逆に、これにddを使用することもできます-かなり簡単ですが、1つ以上必要です。信頼できるブロッキングfactor

たとえば、次の場合:

{   dd ibs="$size" obs="${size}x$block_factor" |
    dd bs="${size}x$blockfactor" "count=$lmt"
}  <infile >outfile

...最初のddは、パイプ間のすべてのwrite()に対して少なくとも1つのibs="$size"出力ブロックを満たすために必要な数のobs="${size}x$block_factor"入力ブロックをバッファリングしますそして2番目のdd。これは、2番目のddcount="$lmt"を使用して出力を確実に制限できることを意味します。これは、最初に作成するすべてのwrite()がそのI/Oブロックサイズと一致するためです-無条件最初のddread()を何回実行する必要があるか。

そしてthatddを使用してパイプやその他のタイプの特殊ファイルを確実に読み取る方法です-ほんの少しの計算で。

1
mikeserv