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.
¿Cómo usar /dev/random o urandom en C?
estojancia
zneak
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 de Linux recientes, el getrandom
La llamada al sistema se puede usar para obtener números aleatorios criptoseguros y no puede fallar. si GRND_RANDOM
es no especificado como un indicador y la cantidad de lectura es de 256 bytes como máximo.
A partir de octubre de 2017, OpenBSD, Darwin y Linux (con -lbsd
) ahora todos tienen una implementación de arc4random
que es criptoseguro y que no puede fallar. Eso lo convierte en 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. Los lees 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 del archivo. /dev/urandom nunca bloquea y siempre completa tantos bytes como haya solicitado, a menos que la llamada al sistema sea interrumpida por una señal. Se considera criptográficamente seguro y debe ser su dispositivo aleatorio de acceso.
/dev/random es más meticuloso. En la mayoría de las plataformas, puede devolver menos bytes de los que solicitó y puede bloquear si no hay suficientes bytes disponibles. Esto hace que la historia del 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);
}
-
@karim: nunca lea todos los bytes de /dev/random. Simplemente no lo hagas. Su programa probablemente no es el solamente usuario en el sistema que necesita bytes aleatorios.
– Zan Lince
25 de febrero de 2011 a las 22:40
-
@zneak, lo siento, olvidé que las publicaciones se pueden editar aquí. Gracias por hacérmelo saber. Su última modificación solo agregó un control de lectura, en lugar de un bucle. Lo modifiqué para usar un bucle, por lo que el código ahora se bloqueará correctamente.
– Morrog
26 de octubre de 2013 a las 2:31
-
Los revisores de @morrog Overeager lo rechazaron, así que hice los cambios manualmente. Lo siento, no te lo acreditan.
– zneak
26/10/2013 a las 22:01
-
@CodesInChaos, soy citando la página de manual de Linux: “Si no está seguro de si debe usar /dev/random o /dev/urandom, entonces probablemente quiera usar este último. Como regla general, /dev/urandom debe usarse para todo excepto GPG de larga duración/ Claves SSL/SSH”.
– zneak
26/10/2013 a las 22:09
-
@zneak Énfasis en longevo ya que para esos no está de más ser extra paranoico. Para uso criptográfico normal
/dev/urandom
está bien.– CodesInChaos
26/10/2013 a las 22:51
polvo kirkland
Hay otras respuestas precisas arriba. Necesitaba usar un FILE*
corriente, sin embargo. 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);
-
Un int se puede leer directamente simplemente lanzando el puntero int a un puntero char.
fread((char*)(&myInt),sizeof(myInt),1,fp)
– Azeem Bande-Ali
25 mayo 2013 a las 18:50
-
@AzeemBande-Ali: ¿Por qué no usa fread((int*)(&myInt),sizeof(myInt),1,fp) en su lugar? Me refiero a un lanzamiento a int * ?
– Larry
30 mayo 2014 a las 15:20
-
En ningún caso se debe usar una conversión en el código C, fread() toma un void *, así que solo haz fread(&myInt, … );
– nos
2 de enero de 2015 a las 21:12
-
Por qué lo necesitas
byte_count
? Está sin usar.– CalculadoraFelina
9 de agosto de 2017 a las 23:01
-
@CalculatorFeline El byte_count aquí es un poco confuso, op tal vez inicialmente quería que cada índice tuviera la misma longitud de bytes, pero esto no pudo hacer …
– LincolnFive
19 de marzo de 2020 a las 6:51
Trónico
Simplemente abra el archivo para leer y luego lea los datos. En C++ 11 es posible que desee utilizar std::random_device
que proporciona acceso multiplataforma a dichos dispositivos.
-
Parece que
std::random_device
no llegó al estándar de 2011. Sí aparece en el Borrador N3797.–Keith Thompson
02/01/2015 a las 19:31
-
Parece
std::random_device
hizo convertirlo en C++ 11 al final.– leyendas2k
26 de junio de 2015 a las 14:14
-
el problema es que
std::random_device
está en C ++ y no en C, y el OP preguntó cómo usar/dev/random
o/dev/urandom
no como usarstd::random_device
aunque es una buena opción para usarstd::random_device
y tiene beneficios, simplemente no es lo que pidió el OP– Nfagie Yansaneh
8 de agosto de 2017 a las 9:20
mensaje de tim
Zneak es 100% correcto. También es muy común leer un búfer de números aleatorios que es un poco más grande que lo que necesitará al inicio. Luego puede llenar una matriz en la memoria o escribirlos en su propio archivo para reutilizarlos más adelante.
Una implementación típica de lo anterior:
typedef struct prandom {
struct prandom *prev;
int64_t number;
struct prandom *next;
} prandom_t;
Esto se vuelve más o menos como una cinta que simplemente avanza y que mágicamente se puede reponer con otro hilo según sea necesario. Hay un lote de 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 que golpean un espejo semitransparente)
- Ruido atmosférico (no tan fuerte como el anterior)
- Granjas de monos intoxicados tecleando en teclados y moviendo ratones (es broma)
No use entropía ‘preempaquetada’ para semillas criptográficas, en caso de que eso no sea evidente. Esos conjuntos están bien para simulaciones, no está bien en absoluto para generar claves y tal.
Sin preocuparse por la calidad, si necesita muchos números para algo como una simulación de monte carlo, es mucho mejor tenerlos disponibles de una manera que no provoque que read() se bloquee.
Sin embargo, recuerde, la aleatoriedad de un número es tan determinista como la complejidad que implica 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
recargas a través de la entropíapor lo que puede bloquearse durante bastante tiempo dependiendo de las circunstancias.
cris j
La respuesta de zneak lo cubre de manera simple, sin embargo, la realidad es más complicada que eso. Por ejemplo, debe considerar si /dev/{u}random realmente es el dispositivo de números aleatorios en primer lugar. Tal escenario puede ocurrir si su máquina se ha visto comprometida y los dispositivos se reemplazaron con enlaces simbólicos a /dev/zero o un archivo disperso. Si esto sucede, el flujo aleatorio ahora es completamente predecible.
La forma más sencilla (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 apuesta justa de que tiene el dispositivo aleatorio. Entonces, la respuesta de @ zneak se puede ampliar mejor 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 codificación insana cubrió esto y otras trampas no hace tanto tiempo; Recomiendo encarecidamente leer el artículo completo. Tengo que dar crédito a su lugar de donde se extrajo esta solución.
Editado para agregar (2014-07-25)…
Coincidentemente, leí anoche que como parte de la Esfuerzo de LibReSSLLinux parece estar recibiendo una ObtenerAleatorio() llamada al sistema. En el momento de escribir este artículo, no se sabe 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. Véase también LibReSSL posible implementación.
-
Un atacante con suficiente poder para reemplazar /dev/random o /dev/urandom con otra cosa, normalmente también tiene suficiente poder para cargar un módulo del kernel para arruinar cada intento que haga para determinar si es un dispositivo aleatorio o no.
– zneak
02/01/2015 a las 20:39
-
los página man dice
getrandom()
se introdujo en el núcleo 3.17. Entonces, el stock Ubuntu 16.04 no lo tiene a partir del 2018-01-17. Correruname -a
en una terminal para verificar la versión de su kernel.– eraperto
17 de enero de 2018 a las 18:01
-
Un atacante con suficiente poder para reemplazar /dev/random o /dev/urandom con otra cosa, normalmente también tiene suficiente poder para cargar un módulo del kernel para arruinar cada intento que haga para determinar si es un dispositivo aleatorio o no.
– zneak
02/01/2015 a las 20:39
-
los página man dice
getrandom()
se introdujo en el núcleo 3.17. Entonces, el stock Ubuntu 16.04 no lo tiene a partir del 2018-01-17. Correruname -a
en una terminal para verificar la versión de su kernel.– eraperto
17 de enero de 2018 a las 18:01
Consulte este artículo muy informativo sobre algunas advertencias comunes de tomar esta ruta hacia la (pseudo) aleatoriedad: insanecoding.blogspot.fi/2014/05/…
– appas
17 de junio de 2015 a las 12:19