Wie verwende ich /dev/random oder urandom in C?

Lesezeit: 8 Minuten

Benutzeravatar von stojance
Standhaftigkeit

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.

  • 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

Benutzeravatar von zneak
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

Benutzeravatar von Dustin Kirkland
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

Benutzeravatar von Tronic
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 verwenden std::random_device obwohl es eine gute Wahl ist, es zu verwenden std::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


Benutzeravatar von Tim Post
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.

Benutzeravatar von Chris J
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. Laufen uname -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. Laufen uname -a in einem Terminal, um Ihre Kernel-Version zu überprüfen.

    – erpert

    17. Januar 2018 um 18:01 Uhr

1419120cookie-checkWie verwende ich /dev/random oder urandom in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy