La lecture de / dev / random ne produit aucune donnée


19

J'utilise souvent la commande

cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' | head --bytes 32

pour générer des mots de passe pseudo-aléatoires. Cela ne fonctionne pas avec /dev/random.

Plus précisément

  • cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' produit une sortie
  • cat /dev/random | strings --bytes 1 produit une sortie
  • cat /dev/random | strings --bytes 1 | tr -d '\n\t ' ne produit pas de sortie

NB: Lors de l'utilisation, /dev/randomvous devrez peut-être bouger la souris ou appuyer sur les touches (par exemple, ctrl, shift, etc.) pour générer l'entropie.

Pourquoi le dernier exemple ne fonctionne-t-il pas? A trune sorte de grand tampon interne qui se /dev/urandomremplit rapidement mais /dev/randompas?

PS J'utilise CentOS 6.5

cat /proc/version
Linux version 2.6.32-431.3.1.el6.x86_64 (mockbuild@c6b10.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Jan 3 21:39:27 UTC 2014

quelle est votre distribution, votre version du noyau? sur Cygwin les deux retournent des valeurs.
Kiwy

@Kiwy Voir modifier.
Aaron J Lang,

1
Tu le sais pwgen, en particulier pwgen -s?
MvG

2
Le -scommutateur les rend moins mémorables, plus véritablement aléatoires. @Boyd: makepasswd est- il largement disponible au-delà des distributions basées sur Debian? La façon dont je le vois, pwgen est disponible pour CentOS tout makepasswd n'est pas .
MvG

1
@BoydStephenSmithJr. Je suis d'accord avec @ MvG qui makepasswdn'est pas disponible sur ma plateforme, merci quand même
Aaron J Lang

Réponses:


27

Ce sera finalement.

Dans:

cat /dev/random | strings --bytes 1 | tr -d '\n\t '

cat ne tamponnera jamais, mais c'est quand même superflu car il n'y a rien à concaténer ici.

< /dev/random strings --bytes 1 | tr -d '\n\t '

stringscependant, comme sa sortie n'est pas plus longue, un terminal tamponnera sa sortie par des blocs (de quelque chose comme 4 ou 8 Ko) par opposition aux lignes lorsque la sortie va à un terminal.

Ainsi, il ne commencera à écrire sur stdout que lorsqu'il aura accumulé 4 Ko de caractères à produire, ce qui /dev/randomprendra un certain temps.

trla sortie va à un terminal (si vous l'exécutez à l'invite du shell dans un terminal), elle tamponnera donc sa sortie ligne par ligne. Parce que vous supprimez le \n, il n'aura jamais de ligne complète à écrire, donc à la place, il écrit dès qu'un bloc complet a été accumulé (comme lorsque la sortie ne va pas à un terminal).

Donc, il trest probable de ne rien écrire avant d' stringsavoir lu suffisamment de données /dev/randompour écrire 8 Ko (2 blocs peut-être beaucoup plus) de données (car le premier bloc contiendra probablement des caractères de nouvelle ligne ou de tabulation ou d'espace).

Sur ce système que j'essaie, je peux obtenir en moyenne 3 octets par seconde /dev/random(contre 12 Mo sur /dev/urandom), donc dans le meilleur des cas (les 4096 premiers octets /dev/randomsont tous imprimables), nous sommes parler 22 minutes avant de trcommencer à produire quoi que ce soit. Mais cela va probablement durer des heures (dans un test rapide, je peux voir stringsécrire un bloc tous les 1 à 2 blocs lus, et les blocs de sortie contiennent environ 30% de caractères de nouvelle ligne, donc je m'attends à ce qu'il ait besoin de lire au moins 3 blocs avant tra 4096 caractères à afficher).

Pour éviter cela, vous pouvez faire:

< /dev/random stdbuf -o0 strings --bytes 1 | stdbuf -o0 tr -d '\n\t '

stdbuf est une commande GNU (également trouvée sur certains BSD) qui modifie la mise en mémoire tampon stdio des commandes via une astuce LD_PRELOAD.

Notez qu'au lieu de strings, vous pouvez utiliser tr -cd '[:graph:]'ce qui exclura également les tabulations, les retours à la ligne et les espaces.

Vous pouvez également corriger les paramètres régionaux pour Céviter d'éventuelles surprises futures avec les caractères UTF-8.


wow explication impressionnante.
Kiwy

2
Incroyable! Grande explication et solution. J'ai toujours utilisé cat«inutilement» parce que je n'ai jamais aimé rediriger stdin à la fin d'un pipeline, maintenant je peux «enregistrer un processus» et avoir toujours des commandes lisibles. Ma solution finale était< /dev/random stdbuf -o0 tr -Cd '[:graph:]' | stdbuf -o0 head --bytes 32
Aaron J Lang

@AaronJLang, bon point sur [:graph:]. J'avais oublié celui-là.
Stéphane Chazelas

@AaronJLang, vous n'avez pas besoin du stdbuffor head -c32sauf si vous voulez lui permettre d'écrire les données dès qu'il les a (comme en plusieurs morceaux au lieu d'un morceau de 32 octets dès qu'il les a)
Stéphane Chazelas

2
À mon avis, / dev / urandom est amplement suffisant pour l'usage de l'auteur. Si quelqu'un était curieux de savoir comment, spécifiquement, urandom fonctionne par rapport à aléatoire, je suggérerais de lire les commentaires en haut du pilote dans drivers / char / random.c de l'arborescence des sources du noyau. Les commentaires mentionnent une analyse du PRNG et de sa mise en œuvre. Espérons que cet article répondra à la question "à quel point l'andandom est-il plus ou moins aléatoire par rapport à l'aléatoire?" Disponible ici: eprint.iacr.org/2012/251.pdf
etherfish

5

La génération de nombres aléatoires pour de nombreuses applications de sécurité nécessite une entropie suffisante - l'entropie mesure à quel point le caractère aléatoire est imprévisible. Un processeur déterministe ne peut pas générer d'entropie, donc l'entropie doit provenir de l'extérieur - soit d'un composant matériel avec un comportement non déterministe, soit d'autres facteurs suffisamment difficiles à reproduire, tels que le timing des actions de l'utilisateur (c'est là que le mouvement de la souris entre). Une fois l'entropie suffisante disponible, la cryptographie peut être utilisée pour générer un flux pratiquement illimité de nombres aléatoires.

Linux fonctionne en accumulant l'entropie dans un pool, puis en utilisant la cryptographie pour produire des nombres aléatoires acceptables à la fois par /dev/randomet /dev/urandom. La différence est qu'il /dev/randomapplique un calcul d'entropie extrêmement conservateur qui réduit l'estimation de l'entropie dans le pool pour chaque octet qu'il génère, /dev/urandomsans se soucier de la quantité d'entropie dans le pool.

Si l'estimation de l'entropie dans le pool est trop faible, les /dev/randomblocs jusqu'à ce que plus d'entropie puisse être accumulée. Cela peut gravement paralyser la vitesse à laquelle /dev/randompeut produire une sortie. C'est ce que vous observez ici. Cela n'a rien à voir avec tr; mais stringslit la sortie avec mise en mémoire tampon, il doit donc lire une mémoire tampon complète (quelques Ko) /dev/randomjuste pour produire au moins un octet d'entrée.

/dev/urandomest parfaitement acceptable pour générer une clé cryptographique , car l'entropie ne diminue en fait d'aucune manière perceptible. (Si vous continuez à faire fonctionner votre machine plus longtemps que l'univers n'a existé, vous ne pouvez pas négliger ces considérations, mais sinon vous êtes bon.) Il n'y a qu'un seul cas où ce /dev/urandomn'est pas bon, qui est sur un système fraîchement installé qui n'a pas 'ai pas encore eu le temps de générer l'entropie, ou un système fraîchement démarré qui démarre à partir d'un support en lecture seule.

L'élimination stringsde votre chaîne de démarrage accélérera probablement votre processus. Ci tr- dessous filtrera les caractères non imprimables:

</dev/random LC_ALL=C tr -dc '!-~'

Mais vous pouvez l'utiliser /dev/urandomici , tant que vous prenez soin de ne pas générer de mots de passe sur un système qui n'a pas eu le temps d'accumuler une entropie suffisante. Vous pouvez vérifier le niveau du pool d'entropie de Linux dans /proc/sys/kernel/random/entropy_avail(si vous utilisez /dev/random, la figure dans ce fichier sera conservatrice, peut-être très bien).


1

Vous devez utiliser /dev/urandompour obtenir des nombres aléatoires (pseudo) de haute qualité, et /dev/randomuniquement lorsque vous avez absolument besoin de nombres aléatoires vraiment imprévisibles. Un attaquant ne disposant pas des ressources de la NSA aura beaucoup de mal à se fissurer /dev/urandom(et n'oubliez pas la cryptographie des tuyaux en caoutchouc ). Le noyau remplit un tampon d'octets "vraiment aléatoires", c'est ce qui /dev/randomdonne. Malheureusement, la vitesse à laquelle ceux-ci sont générés est faible, donc lire beaucoup à partir de /dev/random va décrocher en attendant le hasard.

Vous pourriez envisager d'utiliser random.org ou son générateur de mot de passe , ou l'un des nombreux, nombreux générateurs de mot de passe aléatoires qui flottent autour, consultez par exemple cette page pour quelques conseils en ligne de commande (pas que je recommanderais tous , mais ils devraient vous donner des idées), ou vous pouvez utiliser quelque chose comme mkpasswd(1)(ici sur Fedora 19 expect-5.45-8.fc19.x86_64).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.