Je veux utiliser /dev/random
o /dev/urandom
en C. Comment puis-je le faire ? Je ne sais pas comment les manipuler en C, si quelqu'un le sait, dites-le moi. Merci.
Réponses
Trop de publicités?En général, il est préférable d'éviter d'ouvrir des fichiers pour obtenir des données aléatoires, en raison du nombre de points d'échec de la procédure.
Sur les distributions Linux récentes, l'option getrandom
peut être utilisé pour obtenir des nombres aléatoires crypto-sécurisés, et il ne peut pas échouer. si GRND_RANDOM
es no spécifié comme un drapeau et la quantité lue est au maximum de 256 octets.
À partir d'octobre 2017, OpenBSD, Darwin et Linux (avec -lbsd
) ont maintenant tous une implémentation de arc4random
qui est crypto-sécurisé et qui ne peut pas échouer. Cela en fait une option très intéressante :
char myRandomData[50];
arc4random_buf(myRandomData, sizeof myRandomData); // done!
Sinon, vous pouvez utiliser les dispositifs aléatoires comme s'il s'agissait de fichiers. Vous lisez à partir d'eux et vous obtenez des données aléatoires. J'utilise open
/ read
ici, mais fopen
/ fread
fonctionnerait tout aussi 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
}
}
Vous pouvez lire de nombreux autres octets aléatoires avant de fermer le descripteur de fichier. /dev/urandom ne bloque jamais et remplit toujours autant d'octets que vous l'avez demandé, sauf si l'appel système est interrompu par un signal. Il est considéré comme cryptographiquement sûr et devrait être votre périphérique aléatoire de référence.
/dev/random est plus délicat. Sur la plupart des plateformes, il peut renvoyer moins d'octets que ce que vous avez demandé et il peut bloquer s'il n'y a pas assez d'octets disponibles. Cela rend la gestion des erreurs plus complexe :
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);
}
Zneak est 100% correcte. Il est également très courant de lire un tampon de nombres aléatoires qui est légèrement plus grand que ce dont vous aurez besoin au démarrage. Vous pouvez alors remplir un tableau en mémoire, ou les écrire dans votre propre fichier pour les réutiliser plus tard.
Une mise en œuvre typique de ce qui précède :
typedef struct prandom {
struct prandom *prev;
int64_t number;
struct prandom *next;
} prandom_t;
Cela devient plus ou moins comme une bande qui ne fait qu'avancer et qui peut être magiquement réapprovisionnée par un autre fil selon les besoins. Il existe un lot de services qui fournissent des fichiers volumineux ne contenant rien d'autre que des nombres aléatoires générés par des générateurs beaucoup plus puissants, tels que.. :
- La désintégration radioactive
- Comportement optique (photons frappant un miroir semi-transparent)
- Bruit atmosphérique (pas aussi fort que les précédents)
- Des fermes de singes intoxiqués tapant sur des claviers et déplaçant des souris (plaisanterie)
N'utilisez pas d'entropie "pré-emballée" pour les graines cryptographiques. au cas où cela n'irait pas sans dire. Ces ensembles sont parfaits pour les simulations, pas bien du tout pour générer des clés et autres.
Sans se préoccuper de la qualité, si vous avez besoin d'un grand nombre de chiffres pour quelque chose comme une simulation Monte-Carlo, il est préférable de les rendre disponibles d'une manière qui ne bloque pas le read().
Cependant, n'oubliez pas que le caractère aléatoire d'un nombre est aussi déterminant que la complexité impliquée dans sa génération. /dev/random
y /dev/urandom
sont pratiques, mais pas aussi puissants que l'utilisation d'un HRNG (ou le téléchargement d'un gros dump depuis un HRNG). Il convient également de noter que /dev/random
recharges via entropie Il peut donc bloquer pendant un certain temps, selon les circonstances.
La réponse de zneak le couvre simplement, cependant la réalité est plus compliquée que cela. Par exemple, vous devez vous demander si /dev/{u}random est vraiment le périphérique de nombres aléatoires en premier lieu. Un tel scénario peut se produire si votre machine a été compromise et que les périphériques ont été remplacés par des liens symboliques vers /dev/zero ou un fichier aléatoire. Si cela se produit, le flux aléatoire est maintenant complètement prévisible.
La méthode la plus simple (au moins sous Linux et FreeBSD) est d'effectuer un appel ioctl sur le périphérique qui ne réussira que si le périphérique est un générateur aléatoire :
int data;
int result = ioctl(fd, RNDGETENTCNT, &data);
// Upon success data now contains amount of entropy available in bits
Si cette opération est effectuée avant la première lecture du dispositif aléatoire, il y a de fortes chances que vous ayez le dispositif aléatoire. Donc, la réponse de @zneak peut être étendue pour être :
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);
Le blog Insane Coding a couvert ceci, et d'autres pièges il n'y a pas si longtemps ; je recommande vivement de lire l'article en entier. Je dois reconnaître que c'est de là que cette solution a été tirée.
Modifié pour ajouter (2014-07-25)...
Par coïncidence, j'ai lu la nuit dernière que dans le cadre du L'effort de LibReSSL Linux semble obtenir une GetRandom() syscall. Au moment où nous écrivons ces lignes, nous n'avons aucune idée de la date à laquelle elle sera disponible dans une version générale du noyau. Cependant, ce serait l'interface préférée pour obtenir des données aléatoires cryptographiquement sécurisées car elle élimine tous les pièges que l'accès via les fichiers fournit. Voir aussi la LibReSSL application possible .