Ich möchte benutzen /dev/random
oder /dev/urandom
in C. Wie kann ich das machen? Ich weiß nicht, wie ich sie in C behandeln kann, wenn jemand weiß, bitte sagen Sie mir, wie. Vielen Dank.
Wie verwende ich /dev/random oder urandom in C?
Standhaftigkeit
zneak
Im Allgemeinen ist es eine bessere Idee, das Öffnen von Dateien zu vermeiden, um zufällige Daten zu erhalten, da das Verfahren viele Fehlerquellen enthält.
Bei neueren Linux-Distributionen ist die getrandom
Systemaufruf kann verwendet werden, um kryptosichere Zufallszahlen zu erhalten, und es kann nicht fehlschlagen wenn GRND_RANDOM
ist nicht als Flag angegeben und die gelesene Menge beträgt höchstens 256 Bytes.
Seit Oktober 2017 sind OpenBSD, Darwin und Linux (mit -lbsd
) haben jetzt alle eine Implementierung von arc4random
das ist kryptosicher und das kann nicht fehlschlagen. Das macht es zu einer sehr attraktiven Option:
char myRandomData[50];
arc4random_buf(myRandomData, sizeof myRandomData); // done!
Andernfalls können Sie die zufälligen Geräte verwenden, als wären sie Dateien. Sie lesen von ihnen und erhalten zufällige Daten. Ich benutze open
/read
hier aber fopen
/fread
würde genauso gut funktionieren.
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
}
}
Sie können viele weitere zufällige Bytes lesen, bevor Sie den Dateideskriptor schließen. /dev/urandom blockiert niemals und füllt immer so viele Bytes aus, wie Sie angefordert haben, es sei denn, der Systemaufruf wird durch ein Signal unterbrochen. Es gilt als kryptografisch sicher und sollte Ihr bevorzugtes Zufallsgerät sein.
/dev/random ist kniffliger. Auf den meisten Plattformen kann es weniger Bytes zurückgeben, als Sie angefordert haben, und es kann blockieren, wenn nicht genügend Bytes verfügbar sind. Dies macht die Geschichte der Fehlerbehandlung komplexer:
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);
}
-
@karim: Bitte lese niemals alle Bytes aus /dev/random. Einfach nicht. Dein Programm ist das wohl nicht nur Benutzer auf dem System, der zufällige Bytes benötigt.
– Zan Luchs
25. Februar 2011 um 22:40 Uhr
-
@zneak, sorry, ich habe vergessen, dass Beiträge hier bearbeitet werden können. Danke für die Information. Ihre letzte Änderung hat nur eine Überprüfung beim Lesen anstelle einer Schleife hinzugefügt. Ich habe es geändert, um eine Schleife zu verwenden, sodass der Code jetzt entsprechend blockiert.
– Morgen
26. Oktober 2013 um 2:31 Uhr
-
@morrog Overeager-Rezensenten haben es abgelehnt, also habe ich die Änderungen manuell vorgenommen. Tut mir leid, dass Sie dafür nicht gutgeschrieben werden.
– zneak
26. Oktober 2013 um 22:01 Uhr
-
@CodesInChaos, ich bin Zitieren der Linux-Manpage: “Wenn Sie sich nicht sicher sind, ob Sie /dev/random oder /dev/urandom verwenden sollen, dann möchten Sie wahrscheinlich letzteres verwenden. Als allgemeine Regel sollte /dev/urandom für alles außer langlebigem GPG verwendet werden/ SSL/SSH-Schlüssel.”
– zneak
26. Oktober 2013 um 22:09 Uhr
-
@zneak Betonung auf langlebig denn für diese schadet es nicht, besonders paranoid zu sein. Für die normale Krypto-Nutzung
/dev/urandom
ist gut.– CodesInChaos
26. Oktober 2013 um 22:51 Uhr
Dustin Kirkland
Es gibt oben andere genaue Antworten. Ich musste a verwenden FILE*
streamen aber. Hier ist, was ich getan habe …
int byte_count = 64;
char data[64];
FILE *fp;
fp = fopen("/dev/urandom", "r");
fread(&data, 1, byte_count, fp);
fclose(fp);
-
Ein int kann direkt gelesen werden, indem man einfach den int-Zeiger in einen char-Zeiger umwandelt.
fread((char*)(&myInt),sizeof(myInt),1,fp)
– Azeem Bande-Ali
25. Mai 2013 um 18:50 Uhr
-
@AzeemBande-Ali: Warum verwendest du nicht stattdessen fread((int*)(&myInt),sizeof(myInt),1,fp)? Ich meine eine Umwandlung in int* ?
– Larry
30. Mai 2014 um 15:20 Uhr
-
In keinem Fall sollte eine Umwandlung in C-Code verwendet werden, fread() nimmt ein void *, also tun Sie einfach fread(&myInt, … );
– Nr
2. Januar 2015 um 21:12 Uhr
-
Warum brauchst du
byte_count
? Es ist unbenutzt.– RechnerFeline
9. August 2017 um 23:01 Uhr
-
@CalculatorFeline Der byte_count hier ist etwas verwirrend, op wollte vielleicht ursprünglich, dass jeder Index die gleiche Bytelänge hat, aber das konnte nicht …
– LinconFive
19. März 2020 um 6:51 Uhr
Tronik
Öffnen Sie einfach die Datei zum Lesen und lesen Sie dann die Daten. In C++11 möchten Sie vielleicht verwenden std::random_device
die plattformübergreifenden Zugriff auf solche Geräte bietet.
-
Anscheinend
std::random_device
hat es nicht in den 2011er Standard geschafft. Es erscheint in der Entwurf N3797.– Keith Thompson
2. Januar 2015 um 19:31 Uhr
-
Sieht aus wie
std::random_device
tat am Ende in C++11 schaffen.– legends2k
26. Juni 2015 um 14:14 Uhr
-
Das Problem ist das
std::random_device
ist in C ++ und nicht in C, und das OP hat gefragt, wie es verwendet werden soll/dev/random
oder/dev/urandom
nicht wie zu verwendenstd::random_device
obwohl es eine gute Wahl ist, es zu verwendenstd::random_device
und es hat Vorteile, es ist einfach nicht das, wonach das OP gefragt hat– Nfagie Yansaneh
8. August 2017 um 9:20 Uhr
Tim Post
Zneak hat zu 100% recht. Es ist auch sehr üblich, einen Puffer mit Zufallszahlen zu lesen, der etwas größer ist als das, was Sie beim Start benötigen. Sie können dann ein Array im Speicher füllen oder sie zur späteren Wiederverwendung in Ihre eigene Datei schreiben.
Eine typische Implementierung des oben Gesagten:
typedef struct prandom {
struct prandom *prev;
int64_t number;
struct prandom *next;
} prandom_t;
Dies wird mehr oder weniger zu einem Band, das sich einfach fortbewegt und bei Bedarf auf magische Weise durch einen anderen Faden aufgefüllt werden kann. Es gibt ein viel von Dienstleistungen die große Datei-Dumps von nichts als Zufallszahlen liefern, die mit viel stärkeren Generatoren generiert werden, wie zum Beispiel:
- Radioaktiver Zerfall
- Optisches Verhalten (Photonen treffen auf einen halbdurchlässigen Spiegel)
- Atmosphärisches Rauschen (nicht so stark wie oben)
- Farmen von berauschten Affen, die auf Tastaturen tippen und sich bewegende Mäuse (Scherz)
Verwenden Sie keine „vorgefertigte“ Entropie für kryptografische Seeds, falls das nicht selbstverständlich ist. Diese Sets sind gut für Simulationen, gar nicht gut zum Generieren von Schlüsseln und dergleichen.
Unabhängig von der Qualität, wenn Sie viele Zahlen für so etwas wie eine Monte-Carlo-Simulation benötigen, ist es viel besser, sie so verfügbar zu haben, dass read() nicht blockiert wird.
Denken Sie jedoch daran, dass die Zufälligkeit einer Zahl ebenso deterministisch ist wie die Komplexität, die zu ihrer Erzeugung gehört. /dev/random
und /dev/urandom
sind praktisch, aber nicht so stark wie die Verwendung eines HRNG (oder das Herunterladen eines großen Dumps von einem HRNG). Auch das ist erwähnenswert /dev/random
füllt sich über Entropie aufso dass es je nach Umständen eine ganze Weile blockieren kann.
Chris J
Die Antwort von zneak deckt es einfach ab, aber die Realität ist komplizierter. Zum Beispiel müssen Sie überlegen, ob /dev/{u}random überhaupt das Zufallszahlengerät ist. Ein solches Szenario kann auftreten, wenn Ihr Computer kompromittiert wurde und die Geräte durch symbolische Links zu /dev/zero oder einer Sparse-Datei ersetzt wurden. In diesem Fall ist der Zufallsstrom jetzt vollständig vorhersehbar.
Der einfachste Weg (zumindest unter Linux und FreeBSD) besteht darin, einen ioctl-Aufruf auf dem Gerät auszuführen, der nur erfolgreich ist, wenn das Gerät ein Zufallsgenerator ist:
int data;
int result = ioctl(fd, RNDGETENTCNT, &data);
// Upon success data now contains amount of entropy available in bits
Wenn dies vor dem ersten Lesen des Zufallsgeräts durchgeführt wird, besteht eine faire Chance, dass Sie das Zufallsgerät haben. Die Antwort von @zneak kann also besser folgendermaßen erweitert werden:
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);
Der Insane Coding-Blog deckte diese und andere Fallstricke ab nicht so lange her; Ich empfehle dringend, den gesamten Artikel zu lesen. Ich muss ihnen Anerkennung zollen, woher diese Lösung gezogen wurde.
Bearbeitet, um hinzuzufügen (2014-07-25) …
Zufälligerweise habe ich das gestern Abend als Teil der gelesen LibReSSL-AufwandLinux scheint eine zu bekommen GetRandom() Systemaufruf. Zum Zeitpunkt des Schreibens gibt es kein Wort darüber, wann es in einer allgemeinen Kernel-Veröffentlichung verfügbar sein wird. Dies wäre jedoch die bevorzugte Schnittstelle, um kryptografisch sichere Zufallsdaten zu erhalten, da sie alle Fallstricke beseitigt, die der Zugriff über Dateien bietet. Siehe auch LibReSSL mögliche Umsetzung.
-
Ein Angreifer mit genug Power, um /dev/random oder /dev/urandom durch etwas anderes zu ersetzen, hat normalerweise auch genug Power, um ein Kernel-Modul zu laden, um jeden Versuch zu vermasseln, den Sie unternehmen, um festzustellen, ob es sich um ein zufälliges Gerät handelt oder nicht.
– zneak
2. Januar 2015 um 20:39 Uhr
-
Das Manpage sagt
getrandom()
wurde in Kernel 3.17 eingeführt. Stock Ubuntu 16.04 hat es also ab dem 17.01.2018 nicht. Laufenuname -a
in einem Terminal, um Ihre Kernel-Version zu überprüfen.– erpert
17. Januar 2018 um 18:01 Uhr
-
Ein Angreifer mit genug Power, um /dev/random oder /dev/urandom durch etwas anderes zu ersetzen, hat normalerweise auch genug Power, um ein Kernel-Modul zu laden, um jeden Versuch zu vermasseln, den Sie unternehmen, um festzustellen, ob es sich um ein zufälliges Gerät handelt oder nicht.
– zneak
2. Januar 2015 um 20:39 Uhr
-
Das Manpage sagt
getrandom()
wurde in Kernel 3.17 eingeführt. Stock Ubuntu 16.04 hat es also ab dem 17.01.2018 nicht. Laufenuname -a
in einem Terminal, um Ihre Kernel-Version zu überprüfen.– erpert
17. Januar 2018 um 18:01 Uhr
Lesen Sie diesen sehr informativen Artikel über einige häufige Vorbehalte bei diesem Weg zur (Pseudo-)Zufälligkeit: insanecoding.blogspot.fi/2014/05/…
– appas
17. Juni 2015 um 12:19 Uhr