¿Cómo usar / dev / random o urandom en C?

Quiero usar /dev/random o /dev/urandom en C. ¿Cómo puedo hacerlo? No sé cómo puedo manejarlos en C, si alguien sabe, por favor dígame cómo. Gracias.

En general, es una mejor idea evitar abrir archivos para obtener datos aleatorios, debido a la cantidad de puntos de falla que hay en el procedimiento.

En las distribuciones recientes de Linux, la getrandom sistema getrandom se puede utilizar para obtener números aleatorios criptográficos, y no puede fallar si GRND_RANDOM no se especifica como un indicador y la cantidad de lectura es como máximo de 256 bytes.

A partir de octubre de 2017, OpenBSD, Darwin y Linux (con -lbsd ) ahora tienen una implementación de arc4random que es cripto-segura y que no puede fallar. Eso lo hace una opción muy atractiva:

 char myRandomData[50]; arc4random_buf(myRandomData, sizeof myRandomData); // done! 

De lo contrario, puede usar los dispositivos aleatorios como si fueran archivos. Lees de ellos y obtienes datos aleatorios. Estoy usando open / read aquí, pero fopen / fread funcionaría igual de bien.

 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 } } 

Puede leer muchos más bytes aleatorios antes de cerrar el descriptor de archivo. / dev / urandom nunca bloquea y siempre rellena todos los bytes que haya solicitado, a menos que la señal del sistema interrumpa la llamada. Se considera criptográficamente seguro y debe ser su dispositivo aleatorio de acceso.

/ dev / random es más quisquilloso. En la mayoría de las plataformas, puede devolver menos bytes de los que ha pedido y puede bloquear si no hay suficientes bytes disponibles. Esto hace que la historia de manejo de errores sea más compleja:

 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); } 

Hay otras respuestas precisas arriba. Sin embargo, necesitaba usar un flujo FILE* . Esto es lo que hice …

 int byte_count = 64; char data[64]; FILE *fp; fp = fopen("/dev/urandom", "r"); fread(&data, 1, byte_count, fp); fclose(fp); 

Simplemente abra el archivo para leer y luego lea los datos. En C ++ 11 es posible que desee usar std::random_device que proporciona acceso multiplataforma a dichos dispositivos.

Zneak es 100% correcto. También es muy común leer un buffer de números aleatorios que es un poco más grande que lo que necesitarás al inicio. A continuación, puede completar una matriz en la memoria, o escribirlos en su propio archivo para su posterior reutilización.

Una implementación típica de lo anterior:

 typedef struct prandom { struct prandom *prev; int64_t number; struct prandom *next; } prandom_t; 

Esto se asemeja más o menos a una cinta que simplemente avanza, que puede reponerse mágicamente con otro hilo, según sea necesario. Hay muchos servicios que proporcionan volcados de archivos grandes de nada más que números aleatorios que se generan con generadores mucho más potentes, como:

  • Desintegración radioactiva
  • Comportamiento óptico (fotones golpeando un espejo semitransparente)
  • Ruido atmosférico (no tan fuerte como el anterior)
  • Granjas de monos intoxicados escribiendo en teclados y moviendo ratones (bromeando)

No use entropía ‘preenvasada’ para semillas criptográficas , en caso de que no sea necesario. Esos conjuntos están bien para simulaciones, no son nada buenos para generar claves y cosas así.

No se preocupe por la calidad, si necesita muchos números para algo parecido a una simulación de monte carlo, es mucho mejor tenerlos disponibles de una manera que no cause que read () bloquee.

Sin embargo, recuerde, la aleatoriedad de un número es tan determinista como la complejidad involucrada en generarlo. /dev/random y /dev/urandom son convenientes, pero no tan fuertes como usar un HRNG (o descargar un volcado grande de un HRNG). También vale la pena señalar que /dev/random vuelve a llenar a través de la entropía , por lo que puede bloquearse durante bastante tiempo según las circunstancias.

La respuesta de zneak lo cubre simplemente, sin embargo, la realidad es más complicada que eso. Por ejemplo, debe considerar si / dev / {u} al azar realmente es el dispositivo de número aleatorio en primer lugar. Tal escenario puede ocurrir si su máquina se ha visto comprometida y los dispositivos han sido reemplazados por enlaces simbólicos a / dev / zero o un archivo disperso. Si esto sucede, la secuencia aleatoria ahora es completamente predecible.

La forma más simple (al menos en Linux y FreeBSD) es realizar una llamada ioctl en el dispositivo que solo tendrá éxito si el dispositivo es un generador aleatorio:

 int data; int result = ioctl(fd, RNDGETENTCNT, &data); // Upon success data now contains amount of entropy available in bits 

Si esto se realiza antes de la primera lectura del dispositivo aleatorio, entonces hay una buena apuesta de que tienes el dispositivo aleatorio. Entonces, la respuesta de @ zneak puede extenderse para ser:

 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); 

El blog de Insane Coding lo cubrió, y otras trampas no hace tanto tiempo; Recomiendo leer el artículo completo. Tengo que dar crédito a su origen de donde se extrajo esta solución.

Editado para agregar (2014-07-25) ...
Coincidentalmente , leí anoche que, como parte del esfuerzo LibReSSL , Linux parece estar obteniendo un syscall de GetRandom () . Como al momento de escribir, no hay noticias de cuándo estará disponible en una versión general del kernel. Sin embargo, esta sería la interfaz preferida para obtener datos aleatorios criptográficamente seguros, ya que elimina todas las trampas que proporciona el acceso a través de archivos. Ver también la posible implementación de LibReSSL.