En cherchant des solutions à l'épuisement du pool d'entropie sur les machines virtuelles, je suis tombé sur un projet intéressant appelé haveged
, qui est basé sur l'algorithme HASGE (Collecte et expansion de l'entropie volatile HArdware). Cela fait une affirmation assez fantastique.
HAVEGE est un générateur de nombres aléatoires qui exploite les modifications des états matériels du CPU interne (caches, prédicteurs de branche, TLB) comme source d'incertitude. Lors d'une phase d'initialisation, le compteur de cycles d'horloge matériel du processeur est utilisé pour rassembler une partie de cette entropie: des dizaines de milliers de bits imprévisibles peuvent être rassemblés en moyenne par appel de système d'exploitation.
Si cela produit vraiment une entropie de haute qualité presque illimitée sur les machines virtuelles sans tête, elle devrait être incluse dans chaque distribution de serveur par défaut! Et pourtant, certaines personnes ont exprimé des inquiétudes.
"Au fond, [HAVEGE] utilise des informations de synchronisation basées sur le temporisateur haute résolution du processeur (l'instruction RDTSC). Cette instruction peut être virtualisée, et certains hôtes de machines virtuelles ont choisi de désactiver cette instruction, renvoyant des 0 ou des résultats prévisibles."
(Source: Avis de sécurité PolarSSL 2011-02 sur polarssl.org).
De plus, les tests NIST et ENT populaires donneront parfois à haveged
un PASS même s'il est intentionnellement mal configuré et ne produit pas réellement de nombres aléatoires!
J'ai remplacé la macro "HARDTICKS" dans HAVEGE par la constante 0 (zéro) plutôt que de lire le compteur d'horodatage du processeur. Cela a immédiatement échoué au test de hasard. Cependant, lorsque j'ai utilisé la constante 1 (un) à la place, le test ent a réussi. Et même nist a presque réussi avec un seul test manqué sur les 426 tests exécutés. (Source: Évaluation de l'aléatoire HAVEGE sur engbloms.se).
haveged
dans une machine virtuelle?( Avertissement: Je ne prétends certainement pas que HAVEGE est à la hauteur de ses prétentions. Je n'ai pas vérifié leur théorie ou leur mise en œuvre.)
Pour obtenir l'aléatoire, HAVEGE et les systèmes similaires se nourrissent "d'événements physiques", et en particulier du timing des événements physiques. De tels événements incluent des occurrences d'interruptions matérielles (qui, à leur tour, rassemblent des données sur les frappes de touches, les mouvements de la souris, les paquets Ethernet entrants, le temps pour un disque dur de terminer une demande d'écriture ...). HAVEGE prétend également se nourrir de tous les types de cache manquants qui se produisent dans un CPU (cache L1, cache L2, TLB, prédiction de branche ...); le comportement de ces éléments dépend de ce que le processeur a fait au cours des quelques milliers de cycles d'horloge précédents, il y a donc un potentiel de "hasard". Cela dépend de la possibilité de mesurer l'heure actuelle avec une grande précision (pas nécessairement une précision), c'est là que l'instruction rdtsc
entre en jeu. Il renvoie le contenu actuel d'un compteur interne qui est incrémenté à chaque cycle d'horloge, il offre donc une précision inférieure à la nanoseconde.
Pour un système de machine virtuelle, il y a trois choix concernant cette instruction:
Si le gestionnaire VM choisit la première solution, alors rdtsc
a toute la précision nécessaire et devrait fonctionner aussi bien que sur une machine physique, dans le but de rassembler entropie à partir d'événements matériels. Cependant, comme il s'agit d'une machine virtuelle, il s'agit d'une application sur le système hôte; elle n'obtient pas tout le temps le CPU. Du point de vue du système d'exploitation invité utilisant rdtsc
, il semble que son processeur ait été "volé" occasionnellement: deux instructions successives rdtsc
, nominalement séparées par un seul cycle d'horloge, peuvent signaler une augmentation du compteur de plusieurs millions . En bref, lorsque rdtsc
est simplement appliqué sur le matériel, le système d'exploitation invité peut l'utiliser pour détecter la présence d'un hyperviseur.
La deuxième solution vise à rendre l'émulation plus "parfaite" en maintenant un compteur de cycle virtuel par VM, qui garde une trace des cycles réellement alloués à cette VM. L'avantage est que rdtsc
, du point de vue de l'invité, ne présentera plus l'effet "cycles volés". L'inconvénient est que cette émulation est effectuée en déclenchant et en piégeant une exception de processeur, ce qui augmente le coût de l'opcode rdtsc
de quelques dizaines de cycles d'horloge (cela dépend de la marque du processeur; certains exécutent rdtsc
en moins de 10 cycles, les autres utilisent 60 ou 70 cycles) à plus de mille de cycles. Si l'invité essaie de faire beaucoup de rdtsc
(comme HAVEGE aura tendance à le faire), alors il ralentira à une analyse. De plus, le code de gestion des exceptions perturbera la mesure; au lieu de mesurer la synchronisation des événements matériels, le code mesurera le temps d'exécution du gestionnaire d'exceptions, ce qui peut éventuellement réduire la qualité du caractère aléatoire extrait.
La troisième solution (désactiver rdtsc
) empêchera simplement HAVEGE de renvoyer un bon caractère aléatoire. Puisqu'il utilise en interne un PRNG , la sortie peut toujours tromper les outils d'analyse statistique, car il y a une énorme différence entre "paraître aléatoire" et "être imprévisible" ( les outils d'analyse statistique suivent le chemin du "look random", mais la sécurité cryptographique repose sur l'imprévisibilité).
Le manuel VirtualBox affirme que VirtualBox, par défaut, suit la première méthode (rdtsc
est autorisé sans condition et appliqué directement sur le matériel), mais peut être configuré pour appliquer la deuxième solution (qui vous ne voulez pas, dans ce cas).
Pour tester ce que fait votre VM, vous pouvez essayer ce petit programme (compiler avec gcc -W -Wall -O
sous Linux; le -O
est important):
#include <stdio.h>
#if defined(__i386__)
static __inline__ unsigned long long rdtsc(void)
{
unsigned long long int x;
__asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (x));
return x;
}
#Elif defined(__x86_64__)
static __inline__ unsigned long long rdtsc(void)
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}
#endif
int
main(void)
{
long i;
unsigned long long d;
d = 0;
for (i = 0; i < 1000000; i ++) {
unsigned long long b, e;
b = rdtsc();
e = rdtsc();
d += e - b;
}
printf("average : %.3f\n", (double)d / 1000000.0);
return 0;
}
Sur une machine non virtuelle, avec le "vrai" rdtsc
, cela rapportera une valeur entre 10 et 100, selon la marque du CPU. Si la valeur rapportée est 0 ou si le programme plante, alors rdtsc
est désactivé. Si la valeur est en milliers, alors rdtsc
est émulé, ce qui signifie que la collecte d'entropie peut ne pas fonctionner aussi bien que prévu.
Notez que même obtenir une valeur entre 10 et 100 n'est pas une garantie que rdtsc
n'est pas émulé, car le gestionnaire VM, tout en conservant son compteur virtuel, peut lui soustraire le temps nécessaire à l'exécution du gestionnaire d'exceptions. En fin de compte, vous devez vraiment avoir un bon aperçu du manuel et de la configuration de votre gestionnaire VM.
Bien sûr, toute la prémisse de HAVEGE est discutable. Pour toute sécurité pratique, vous avez besoin de quelques bits "réels aléatoires", pas plus de 200, que vous utilisez comme graine dans un PRNG sécurisé cryptographiquement . Le PRNG produira des gigaoctets de pseudo-alea indiscernables du vrai hasard, et c'est assez bon pour toutes les fins pratiques.
Insister pour revenir au matériel pour chaque bit ressemble à une nouvelle éclosion de cette idée défectueuse qui voit l'entropie comme une sorte d'essence, que vous brûlez lorsque vous la regardez.
Sur l'avis polarssl: Une réponse technique détaillée peut être trouvée dans la source Debian la plus récente:
Le résumé est le suivant: polarssl! = Haveged! = HAVEGE
Sur les expériences de l'émulateur embloms.se:
La suite de tests haveged
, NIST
et ent
, vérifie qu'une génération source a produit un RNG fonctionnel. Des tests d'exécution sont requis pour vérifier le fonctionnement factice dans un environnement virtuel. C'est un ajout assez récent à avoir forgé.
Sur les tests statistiques:
Supposons que vous ayez un hardware RNG
, a TRNG
, comment savez-vous qu'il n'est pas cassé? Le matériel se casse. L'organisme allemand de normalisation a une spécification qui traite de ce problème, AIS31
. Cette approche est adoptée par haveged. Une discussion (biaisée) sur les normes pour le GNR telles qu'elles s'appliquent à la falsification peut être trouvée à
http://www.issihosts.com/haveged/ais31.html
La non-prévisibilité de HAVEGE
est exactement le même mécanisme que celui observé dans les logiciels d'analyse comparative. Ce n'est pas dû à la dérive de la minuterie, mais à l'agrégation des comportements asynchrones dans un processeur moderne. Peu importe que les variations de performances proviennent d'un échec de cache ou d'une tranche de temps fournie à un autre processeur. La précision de la minuterie n'a pas d'importance tant qu'elle est "adéquate". Comment est-ce déterminé? Par la sortie. Par conception (ou peut-être plus de conception) /dev/random
est insensible aux mauvaises données d'entrée. La seule façon de renverser la conception est de mentir sur l'entropie ajoutée au pool d'entropie. Les versions les plus récentes de haveged effectuent une estimation d'entropie au moment de l'exécution sur la sortie générée pour garantir que la sortie est cohérente avec un TRNG idéal.
Résumé: haveged
la sortie est indiscernable d'un TRNG
selon les tests utilisés par l'organisme de normalisation allemand pour certifier TRNG
. Si ce n'est pas le cas, haveged
s'arrêtera.
( Mise à jour , grâce à gwuertz l'auteur/mainteneur actuel de haveged
, j'ai raté la séparation entre HAVEGE
et haveged
.)
haveged
est une implémentation distincte de la méthode HAVEGE pour générer des nombres aléatoires, elle est actuelle, maintenue et documentée ici: http://www.issihosts.com/haveged/ (et non utilise plus libhavege directement).
HAVEGE
n'est pas très actuel (2006), bien que quelqu'un ait corrigé plus récemment (2009) pour la vitesse et l'exactitude. Je serais prudent car il ne documente pas sa méthode, ne mentionne pas les machines virtuelles et, comme indiqué, s'appuie (fortement) sur RDTSC
(ou l'équivalent de la plate-forme). (Le code source me fait aussi frissonner, mais c'est assez subjectif.)
Je soutiendrai que l'hôte VM ne devrait pas être involontairement fuite d'un état dans les invités, donc il ne devrait pas être considéré comme une bonne source d'entropie lors de l'utilisation de cette méthode.
Une meilleure approche sous Linux est rng-tools avec le pilote virtio-rng paravirtualisé rng (c'est-à-dire permettre à un invité d'accéder à l'entropie collectée par l'hôte, éliminant ainsi de nombreux problèmes potentiels les clients voient des événements "aléatoires"), ou vous pouvez trouver Entropy Broker plus utile. Sur les puces Intel récentes, vous pouvez également exposer les instructions RDRAND aux invités, en contournant le problème.
Cet article (de discours de hpa à LinuxCon Europe 2012 ) est une lecture utile: http: // lwn. net/Articles/525459 / , il traite également de HAVEGE
/haveged
(bien que la distinction ne soit pas claire ici non plus).
Voir les réponses à cette question pour quelques réflexions sur la façon de déterminer le manque de caractère aléatoire: Quelles statistiques peuvent être utilisées pour identifier les données pseudo-aléatoires?