Cで/dev/random
または/dev/urandom
を使用したいのですが、どうすればよいですか?誰かが私に方法を教えてください知っていれば、私はCでそれらをどのように扱うことができるかわかりません。ありがとうございました。
一般に、手順に障害点がいくつあるため、ランダムなデータを取得するためにファイルを開かないようにすることをお勧めします。
最近のLinuxディストリビューションでは、 getrandom
システムコールを使用して暗号化された安全な乱数を取得でき、失敗することはありませんifGRND_RANDOM
はnotフラグとして指定され、読み取り量は最大256バイトです。
2017年10月現在、OpenBSD、Darwin、およびLinux(-lbsd
)現在、すべてに arc4random
これは暗号セキュアであり、失敗することはありません。それは非常に魅力的なオプションになります:
char myRandomData[50];
arc4random_buf(myRandomData, sizeof myRandomData); // done!
それ以外の場合は、ランダムデバイスをファイルのように使用できます。それらから読み取り、ランダムなデータを取得します。ここではopen
/read
を使用していますが、fopen
/fread
も同様に機能します。
int randomData = open("/dev/urandom", O_RDONLY);
if (randomData < 0)
{
// something went wrong
}
else
{
char myRandomData[50];
ssize_t result = read(randomData, myRandomData, sizeof myRandomData);
if (result < 0)
{
// something went wrong
}
}
ファイル記述子を閉じる前に、さらに多くのランダムバイトを読み取ることができます。/dev/urandomは、システムコールがシグナルによって中断されない限り、ブロックすることはなく、要求したバイト数を常に埋めます。暗号的に安全であると考えられており、あなたの頼りになるランダムなデバイスでなければなりません。
/ dev/randomの方が細かいです。ほとんどのプラットフォームでは、要求したよりも少ないバイトを返すことができ、十分なバイトが利用できない場合はブロックできます。これにより、エラー処理のストーリーがより複雑になります。
int randomData = open("/dev/random", O_RDONLY);
if (randomData < 0)
{
// something went wrong
}
else
{
char myRandomData[50];
size_t randomDataLen = 0;
while (randomDataLen < sizeof myRandomData)
{
ssize_t result = read(randomData, myRandomData + randomDataLen, (sizeof myRandomData) - randomDataLen);
if (result < 0)
{
// something went wrong
}
randomDataLen += result;
}
close(randomData);
}
上記の他の正確な答えがあります。ただし、FILE*
ストリームを使用する必要がありました。私がやったことは...
int byte_count = 64;
char data[64];
FILE *fp;
fp = fopen("/dev/urandom", "r");
fread(&data, 1, byte_count, fp);
fclose(fp);
読み取り用にファイルを開いてから、データを読み取ります。 C++ 11では、std::random_device
このようなデバイスへのクロスプラットフォームアクセスを提供します。
Zneak は100%正しいです。また、起動時に必要なものよりわずかに大きい乱数のバッファを読み取ることも非常に一般的です。その後、メモリに配列を追加するか、後で再利用するために独自のファイルに配列を書き込むことができます。
上記の典型的な実装:
typedef struct prandom {
struct prandom *prev;
int64_t number;
struct prandom *next;
} prandom_t;
これは多かれ少なかれ、必要に応じて別のスレッドによって魔法のように補充することができるテープのようになります。 lot of services があり、次のようなはるかに強力なジェネレーターで生成された乱数以外の大きなファイルダンプを提供します。
暗号化シードに「事前にパッケージ化された」エントロピーを使用しない、言うまでもありません。これらのセットはシミュレーションに適しています。まったくうまくありませんキーなどを生成します。
品質に関係なく、モンテカルロシミュレーションのようなものに多くの数値が必要な場合は、read()がブロックされない方法で利用できるようにする方がはるかに良いです。
ただし、数値のランダム性は、その生成に伴う複雑さと同じように決定的であることを忘れないでください。 /dev/random
および/dev/urandom
は便利ですが、HRNGを使用する(またはHRNGから大きなダンプをダウンロードする)ほど強力ではありません。 /dev/random
エントロピー経由で補充 なので、状況に応じてかなりの時間ブロックすることができます。
zneakの答えはそれを簡単にカバーしていますが、現実はそれよりも複雑です。例えば、そもそも/ dev/{u} randomが実際に乱数デバイスであるかどうかを考慮する必要があります。このようなシナリオは、マシンが侵害され、デバイスが/ dev/zeroまたはスパースファイルへのシンボリックリンクに置き換えられた場合に発生する可能性があります。これが発生した場合、ランダムストリームは完全に予測可能になります。
最も単純な方法(少なくともLinuxおよびFreeBSDの場合)は、デバイスがランダムジェネレーターである場合にのみ成功するデバイスでioctl呼び出しを実行することです。
int data;
int result = ioctl(fd, RNDGETENTCNT, &data);
// Upon success data now contains amount of entropy available in bits
ランダムデバイスの最初の読み取りの前にこれが実行される場合、ランダムデバイスを持っているという公正な賭けがあります。 @zneakの答えは次のように拡張することができます。
int randomData = open("/dev/random", O_RDONLY);
int entropy;
int result = ioctl(randomData, RNDGETENTCNT, &entropy);
if (!result) {
// Error - /dev/random isn't actually a random device
return;
}
if (entropy < sizeof(int) * 8) {
// Error - there's not enough bits of entropy in the random device to fill the buffer
return;
}
int myRandomInteger;
size_t randomDataLen = 0;
while (randomDataLen < sizeof myRandomInteger)
{
ssize_t result = read(randomData, ((char*)&myRandomInteger) + randomDataLen, (sizeof myRandomInteger) - randomDataLen);
if (result < 0)
{
// error, unable to read /dev/random
}
randomDataLen += result;
}
close(randomData);
Insane Codingブログ これと他の落とし穴をカバー 少し前;記事全体を読むことを強くお勧めします。このソリューションがどこから引き出されたのかを評価しなければなりません。
追加するために編集(2014-07-25)...
偶然にも、昨夜、 LibReSSLの取り組み の一部として、Linuxが GetRandom() syscallを取得しているようだと読みました。これを書いている時点では、カーネルの一般リリースでいつ利用可能になるのかという言葉はありません。ただし、これは、ファイルを介したアクセスが提供するすべての落とし穴を排除するため、暗号的に安全なランダムデータを取得するための優先インターフェースです。 LibReSSL 可能な実装 も参照してください。