2 points par GN⁺ 2024-05-08 | 1 commentaires | Partager sur WhatsApp
  • Go 1.22 remplace la source aléatoire par défaut de math/rand et math/rand/v2 par un générateur cryptographiquement robuste, ce qui réduit fortement l’impact des erreurs lorsqu’on utilise math/rand là où crypto/rand aurait dû être employé
  • L’ancien générateur de Go 1 était un registre à décalage à rétroaction linéaire utilisant un état de 607 uint64, si bien qu’en observant seulement 607 sorties, il est possible de reconstruire les valeurs passées et futures
  • Le PCG-DXSM de math/rand/v2 améliore la qualité statistique des nombres aléatoires et la taille de l’état, mais ne garantit toujours pas l’imprévisibilité requise pour des valeurs secrètes
  • Le nouveau ChaCha8Rand utilise une graine de 32 octets, un rekeying toutes les 16 blocs et un état de 300 octets par cœur, et il est appliqué à math/rand/v2, à une partie de math/rand et aux graines de hachage des maps
  • Le coût en performances reste limité : ChaCha8Rand est plus lent que le générateur de Go 1, mais jamais de plus d’un facteur 2, et sur un serveur classique l’écart ne dépasse pas 3 ns, ce qui fait que le gain en sécurité l’emporte dans la plupart des programmes

Les nouveaux choix par défaut pour l’aléatoire dans Go 1.22

  • Go 1.22 change les valeurs par défaut de math/rand et math/rand/v2 pour utiliser un générateur pseudo-aléatoire cryptographiquement robuste
  • L’objectif est de réduire les dégâts lorsque des développeurs utilisent par erreur math/rand là où crypto/rand est nécessaire
  • Les API aléatoires de Go se répartissent traditionnellement en deux catégories
    • math/rand : des nombres aléatoires statistiques utilisés pour les simulations, l’échantillonnage, le calcul numérique, les algorithmes aléatoires non cryptographiques, le fuzzing, le mélange et le backoff exponentiel
    • crypto/rand : des nombres aléatoires cryptographiques pour les clés, les jetons et autres cas nécessitant de l’imprévisibilité

Pourquoi l’aléatoire statistique ne suffit pas

  • Un générateur statistique peut suffire à de nombreux usages non cryptographiques s’il passe les tests statistiques de base
  • Mais un observateur connaissant l’algorithme peut souvent prédire la suite s’il voit suffisamment de sorties
  • srand et rand d’Unix V3 sont une forme ancienne qui a influencé ensuite le C et les API aléatoires de nombreux langages
    • L’état est initialisé avec une graine entière unique
    • La valeur suivante est calculée avec un générateur congruentiel linéaire (LCG)
    • Comme l’état interne est simple, une seule sortie peut suffire à calculer facilement les valeurs futures
  • Avec un LCG, on peut choisir les constantes pour parcourir toutes les sorties possibles avant répétition, mais les bits de poids faible ont la faiblesse de se répéter sur des cycles courts

Structure et faiblesses du générateur Go 1

  • Le générateur math/rand de Go 1 appartient à la famille des registres à décalage à rétroaction linéaire
  • Son état interne est une slice vec de 607 uint64
    • vec[606] est le « tap »
    • vec[334] est le « feed »
    • Pour produire la valeur suivante, le générateur additionne tap et feed pour produire x, stocke x à la position feed, puis le renvoie
  • L’implémentation réelle ne déplace pas toute la slice, elle recule seulement les positions tap et feed pour réduire le coût
    • Produire la valeur suivante demande deux soustractions, deux additions conditionnelles, deux chargements, une addition et un stockage
  • Comme la valeur renvoyée est un élément du vecteur d’état interne, la lecture de 607 sorties expose l’état complet
    • Il suffit ensuite de remplir le même vec et d’exécuter l’algorithme pour prédire les valeurs futures
    • En exécutant l’algorithme à l’envers, il est aussi possible de reconstituer les valeurs passées
  • Le générateur Go 1 n’était pas destiné à la sécurité, et la qualité des nombres produits dépend aussi de l’initialisation de vec

Ce que PCG améliore, et ce qu’il ne résout pas

  • math/rand/v2 adopte PCG de Melissa O’Neill comme générateur statistique plus moderne
  • Le PCG de Go repose sur un LCG 128 bits et réduit l’état 128 bits en une sortie 64 bits via une fonction scramble
  • Lors des discussions autour de la proposition, Go a retenu une variante de scramble basée sur la multiplication, proposée par O’Neill
    • Cette forme est appelée PCG-DXSM
    • Numpy utilise aussi cette forme de PCG
  • PCG a un état bien plus petit que le générateur Go 1
    • Générateur Go 1 : 607 uint64
    • PCG : deux uint64
  • PCG est moins sensible à l’état initial et passe divers tests statistiques, mais il ne garantit pas l’imprévisibilité
    • PCG-XSL-RR est inversible
    • Il ne serait pas surprenant que PCG-DXSM le soit aussi
  • Pour générer des valeurs secrètes, il faut donc un autre générateur que PCG

Aléatoire cryptographique et rôle du système d’exploitation

  • L’aléatoire cryptographique doit rester pratiquement imprévisible même pour un observateur qui connaît la méthode de génération et a vu de nombreuses sorties passées
  • Les protocoles cryptographiques, les clés secrètes, le commerce moderne et la vie privée en ligne en dépendent
  • En pratique, c’est le système d’exploitation qui fournit l’aléa
    • Il collecte de la variabilité depuis des dispositifs physiques comme la souris, le clavier, le disque ou les timings réseau
    • Plus récemment, il exploite aussi le bruit électrique mesuré directement par le CPU
  • Une fois qu’il a accumulé suffisamment d’aléa, par exemple au moins 256 bits, le système d’exploitation produit une longue séquence pseudo-aléatoire à l’aide d’un hachage ou d’un algorithme cryptographique
  • Historiquement, on utilisait surtout des fichiers de périphérique comme /dev/random, mais les systèmes d’exploitation modernes fournissent désormais des appels système dédiés
  • Le crypto/rand de Go masque ces différences entre OS et expose l’interface unifiée rand.Read

Conception de ChaCha8Rand

  • Le nouveau générateur ChaCha8Rand de Go 1.22 est une forme légèrement modifiée du chiffre de flux ChaCha de Daniel J. Bernstein
  • ChaCha est largement connu sous la forme ChaCha20, utilisée notamment dans TLS et SSH
  • Too Much Crypto de Jean-Philippe Aumasson considère également la variante à 8 tours, ChaCha8, comme sûre, et ChaCha8 est environ 2,5 fois plus rapide
  • Pour utiliser ChaCha8 comme rand.Source, ChaCha8Rand n’applique pas le XOR du bloc généré avec une entrée, mais utilise directement le flux comme suite aléatoire
    • Cela revient à chiffrer ou déchiffrer des données entièrement nulles

Modifications propres à ChaCha8Rand

  • ChaCha8Rand utilise une graine de 32 octets comme clé ChaCha8
  • ChaCha8 produit des blocs de 64 octets, calculés en traitant chaque bloc comme 16 uint32
  • Une implémentation classique peut calculer 4 blocs en parallèle via SIMD, mais lorsqu’on veut les utiliser avec un XOR en entrée, il faut ensuite désentrelacer les blocs interleaved
    • ChaCha8Rand définit directement ces blocs interleaved comme flux aléatoire, ce qui évite le coût de ce réordonnancement
  • Dans l’étape finale de ChaCha8, certaines valeurs sont ajoutées à chaque uint32
    • La moitié correspond au matériau de clé et l’autre moitié à des constantes connues
    • ChaCha8Rand ne réadditionne pas ces constantes connues, ce qui supprime la moitié des additions finales
  • Tous les 16 blocs générés, les 32 derniers octets sont utilisés comme clé des 16 blocs suivants
    • Ce rekeying apporte une forme de sécurité persistante vers l’avant
    • Même si l’état mémoire complet du générateur fuit, on ne peut reconstituer que les valeurs produites depuis le dernier rekeying, pas les valeurs plus anciennes
  • Go publie la spécification C2SP de ChaCha8Rand et des cas de test, afin que d’autres implémentations puissent partager la même reproductibilité que l’implémentation Go pour une même graine

Où cela s’applique dans la bibliothèque standard

  • Le runtime Go maintient un état ChaCha8Rand par cœur, initialisé avec un aléa cryptographique fourni par le système d’exploitation
    • La taille d’état est de 300 octets par cœur
    • Sur une machine à 16 cœurs, cela reste du même ordre que l’état unique partagé de 4 872 octets de l’ancien générateur Go 1
    • Cet état par cœur permet de produire des nombres aléatoires rapidement sans contention sur des verrous
  • Les fonctions de paquetage de math/rand/v2 utilisent toujours ChaCha8Rand
    • Par exemple : rand.N, rand.Float64
  • Les fonctions de paquetage de math/rand utilisent ChaCha8Rand tant que rand.Seed n’a pas été appelé
    • Par exemple : rand.Intn, rand.Float64
    • Si rand.Seed est appelé, il faut revenir à l’ancien générateur Go 1 pour préserver la compatibilité
  • Le runtime choisit aussi la graine de hachage des nouvelles maps avec ChaCha8Rand au lieu de l’ancien générateur basé sur wyrand
    • Si un attaquant connaît la fonction de hachage spécifique d’une implémentation de map, il peut préparer des entrées qui forcent un comportement en temps quadratique
    • Utiliser une graine par map, plutôt qu’une seule graine globale, évite aussi d’autres formes de dégénérescence
    • Il n’est pas totalement clair qu’un aléa cryptographique soit indispensable pour les graines de map, mais ce changement était simple et prudent
  • Le code qui a besoin d’une instance séparée de ChaCha8Rand peut créer directement rand.ChaCha8

Réduire l’impact des erreurs de sécurité

  • Go cherche à réduire ou supprimer les erreurs fréquentes ayant un impact sécurité afin d’aider à écrire du code sûr par défaut
  • Quand math/rand.Read a été déprécié dans Go 1.20, certains développeurs ont découvert qu’ils utilisaient math/rand à des endroits où crypto/rand était nécessaire, notamment pour générer du matériel de clé
  • Dans Go 1.20, ce type d’erreur constituait un problème de sécurité grave
    • Il fallait examiner où la clé était utilisée
    • Comment elle avait pu être exposée
    • Et si d’autres sorties aléatoires avaient donné à un attaquant des indices pour la dériver
  • Dans Go 1.22, la même erreur reste une erreur, mais elle a moins de chances de se transformer en catastrophe de sécurité
  • Il reste néanmoins préférable d’utiliser crypto/rand pour les valeurs secrètes
    • Le noyau du système d’exploitation protège mieux les valeurs aléatoires
    • Le noyau continue d’ajouter de la nouvelle entropie au générateur
    • L’implémentation du noyau a fait l’objet de plus de revues

Des cas qui n’ont pas l’air cryptographiques

  • Générer un UUID aléatoire peut sembler relever de math/rand, puisque l’UUID n’est pas en soi une valeur secrète
  • Mais si math/rand est initialisé avec l’heure courante, deux machines différentes exécutées au même moment peuvent produire les mêmes valeurs
    • Le risque augmente encore sur les systèmes où l’heure n’a qu’une précision à la milliseconde
  • Même avec l’auto-seeding basé sur l’entropie de l’OS introduit dans Go 1.20, la graine du générateur Go 1 n’est qu’un entier de 63 bits
    • Dans un programme qui crée un UUID au démarrage, le nombre possible de premiers UUID est donc limité à 2⁶³
    • Après environ 2³¹ UUID, le risque de collision apparaît
  • Le ChaCha8Rand de Go 1.22 est initialisé avec 256 bits d’entropie
    • Le nombre possible de premiers UUID est de 2²⁵⁶
    • Il n’y a plus à se soucier des collisions
  • La répartition aléatoire de requêtes d’un serveur frontend vers des serveurs backend peut aussi nécessiter un aléa imprévisible
    • Si un attaquant peut observer l’affectation et connaît un algorithme prédictible, il peut concentrer des requêtes coûteuses sur un backend précis
    • Avec le générateur Go 1, c’était rare mais possible
    • Avec Go 1.22, ce n’est plus un problème

Caractéristiques de performance

  • Les bénéfices de sécurité de ChaCha8Rand ont un petit coût, mais ses performances restent dans le même ordre de grandeur que le générateur Go 1 et PCG
  • Deux opérations sont comparées
    • Uint64 : renvoyer le prochain uint64 du flux aléatoire
    • N(1000) : renvoyer un nombre aléatoire dans l’intervalle [0, 1000)
  • Sur une puce x86 64 bits compilée avec GOARCH=386 pour une exécution en mode 32 bits, PCG est plus lent que ChaCha8Rand à cause de sa multiplication 128 bits
    • ChaCha8Rand utilise une arithmétique SIMD 32 bits
  • Sur certains systèmes, Go 1: Uint64 est plus rapide que PCG: Uint64, mais Go 1: N(1000) est plus lent que PCG: N(1000)
    • N(1000) dans Go 1 utilise deux divisions entières 64 bits pour ramener la valeur dans l’intervalle
    • N(1000) dans PCG et ChaCha8 utilise l’algorithme plus rapide de math/rand/v2, qui évite généralement les divisions
  • Globalement, ChaCha8Rand est plus lent que le générateur Go 1, mais jamais plus de 2 fois plus lent
  • Sur un serveur classique, l’écart ne dépasse pas 3 ns, et très peu de programmes feront de cette différence un goulot d’étranglement

Conclusion

  • Go 1.22 améliore la sécurité des programmes sans changement de code
  • L’idée centrale est de renforcer math/rand lui-même pour réduire un problème courant : l’utilisation accidentelle de math/rand à la place de crypto/rand
  • Il existe aussi des cas comme le paquet npm keypair, qui tente de générer des paires de clés RSA avec Math.random en JavaScript quand l’API Web Crypto n’est pas disponible
  • La sécurité d’un système ne peut pas reposer sur l’hypothèse que les développeurs ne feront jamais d’erreur
  • Le ChaCha8Rand de Go 1.22 montre qu’utiliser un générateur pseudo-aléatoire cryptographiquement robuste même pour de l’aléatoire « mathématique » peut offrir des performances compétitives face à d’autres générateurs

1 commentaires

 
GN⁺ 2024-05-08
Avis de Hacker News
  • Comme indiqué dans l’article, rclone a commis exactement cette erreur
    Lors d’un refactoring de code qui utilisait Read de crypto/rand, l’import a été modifié automatiquement, probablement mêlé à du code utilisant math/rand, et goimports l’a apparemment remplacé par math/rand
    Résultat : au lieu d’un générateur de nombres aléatoires sécurisé, rclone s’est retrouvé à utiliser un générateur déterministe initialisé avec l’heure, et personne ne l’a remarqué dans le diff :-(
    https://www.cvedetails.com/cve/CVE-2020-28924/
    Donc je suis très favorable à ce changement

    • Aïe, désolé. Comme goimports a été modifié en 2016 pour préférer crypto/rand, je ne suis pas sûr de ce qui s’est passé pendant le refactoring
      Peut-être que du code utilisant une API propre à math/rand s’est retrouvé dans le même fichier
      https://go-review.googlesource.com/24847
      Quoi qu’il en soit, c’est une bonne chose que ce genre de point soit clarifié
    • On m’a déjà signalé une vulnérabilité parce que quelqu’un croyait aussi que math/rand était utilisé. En réalité ce n’était pas le cas, il y avait juste confusion entre plusieurs fichiers, donc rien de grave, mais cela montre à quel point tout cela prête à confusion
      text/template et html/template sont similaires. Avec le recul, ce genre de masquage de noms de packages était une mauvaise idée
    • En cherchant "secure password generation golang", j’ai aussi vu que presque tous les exemples utilisent math/rand
      Pire encore, ils réinitialisent tous la seed avec l’heure courante juste avant de générer le mot de passe
      Je l’ai découvert après avoir repéré quelqu’un qui utilisait math/rand dans notre code, puis en cherchant d’où il avait pu copier cela
    • goimports a traité spécialement math/rand.Read et crypto/rand.Read presque depuis le début
      Mais le commit de 2016 https://github.com/golang/tools/commit/0835c735343e0d8e375f0... mentionne une période où "rand.Read" pouvait être interprété comme "math/rand"
      C’est peut-être à ce moment-là que cela s’est produit
    • Fournir un appel d’API portant un nom du genre "PredictableRand" ne semblerait pas si difficile
  • spacey l’avait aussi publié la semaine dernière sur https://news.ycombinator.com/item?id=40237491, mais ce post semble avoir été enterré à tort comme doublon de https://news.ycombinator.com/item?id=40224864
    Les deux billets du blog go.dev font partie de la même série, mais ils sont assez différents. Celui-ci porte sur des algorithmes efficaces de génération de nombres aléatoires sécurisés, tandis que le précédent portait sur la conception des API Go

  • Russell Cox produit régulièrement d’excellents billets techniques, propositions et travaux
    Si vous voulez améliorer la clarté de votre écriture et de votre pensée, commencer par Russell Cox est un bon point de départ

    • Sa série sur les automates finis et les expressions régulières m’a passionné pour ce domaine
      À l’époque, je ne savais même pas qui était Russ Cox, mais cette série d’articles était vraiment remarquable
      C’est probablement la ressource gratuite de meilleure qualité sur l’implémentation des expressions régulières ; ensuite viennent divers livres centrés sur les compilateurs, mais ils ne sont pas gratuits et ne se trouvent pas facilement sur le Web
    • Il réalise aussi de bonnes démos vidéo https://research.swtch.com/acme
  • Il m’est arrivé d’utiliser math/rand là où crypto/rand était indispensable
    Résultat : les premières versions de dnscrypt-proxy2 utilisaient des clés statiques
    La cause était une extension VSCode qui ajoutait automatiquement les imports. Dans tous les fichiers source nécessitant des nombres aléatoires sécurisés, j’avais importé crypto/rand explicitement et avec précaution, mais je l’avais oublié dans un fichier ; tout compilait et fonctionnait correctement, et je n’ai pas remarqué que l’extension avait silencieusement ajouté un import de math/rand dans ce fichier précis
    Depuis, j’importe crypto/rand avec l’alias cryptorand pour éviter qu’un mauvais rand soit auto-importé
    À noter que Zig utilise aussi un générateur de nombres aléatoires basé sur ChaCha8 et que, pour les opérations cryptographiques, l’utilisateur ne peut pas fournir son propre générateur : un générateur sûr est toujours utilisé. Pour les tests, certaines fonctions acceptent une seed explicite
    Pour les environnements contraints, la bibliothèque standard inclut aussi un générateur plus petit basé sur la permutation Ascon et la construction Reverie

    • Je ne sais pas exactement ce qui s’est passé dans votre cas, mais il est très possible que ce soit différent de ce que vous décrivez
      En 2016, goimports a été modifié pour préférer crypto/rand à math/rand (https://go-review.googlesource.com/24847), et c’était avant l’arrivée du support VSCode pour Go
    • Quelqu’un d’autre a dit la même chose. Franchement, la pratique consistant à ajouter automatiquement les imports me semble complètement étrange, et elle sape l’objectif même de séparer les noms dans des espaces de noms distincts
  • Même dans les années 2020, je me suis souvent demandé pourquoi les implémentations de nombres aléatoires par défaut de plusieurs langages de programmation utilisaient encore des générateurs rapides comme LFSR ou MT
    Il me semblerait préférable d’adopter une position conservatrice, en partant du principe que les gens ne savent pas s’ils ont besoin d’un générateur pseudo-aléatoire ou d’un générateur pseudo-aléatoire cryptographiquement sûr, de faire du second le choix par défaut, et de demander à ceux qui ont besoin du premier de le choisir explicitement

    • La nouvelle API orientée objet de PHP 8.2 pour l’aléatoire fait exactement cela
      Si le développeur ne choisit pas explicitement le moteur d’aléa à utiliser, il reçoit un générateur cryptographiquement sûr
      La partie difficile, désormais, est de convaincre les gens de migrer vers la nouvelle API. Plus encore, il n’est même pas simple de les faire passer de mt_rand(), qui utilise une instance globale de Mt19937, à random_int(), basé sur un CSPRNG et déjà disponible depuis PHP 7.0
      [1] https://www.php.net/releases/8.2/en.php#random_extension
    • J’ai récemment commencé à utiliser une nouvelle bibliothèque Go qui génère des ID aléatoires pour plusieurs composants d’une structure de données complexe
      Dans mon cas d’usage, il y avait des dizaines de milliers de composants, et le profilage a montré qu’une part importante du temps d’initialisation de la structure de données était passée dans Read() de crypto/rand, qui effectuait des appels système sur mon MacBook
      En patchant la bibliothèque pour qu’elle utilise Read() de math/rand, les performances se sont nettement améliorées
      Outre le fait que math/rand est plus rapide, je craignais aussi d’épuiser sans raison particulière le pool d’entropie du système. Dans ce cas, la seule raison pour laquelle les ID devaient être aléatoires était de pouvoir ajouter plus tard des composants après sérialisation/désérialisation de la structure de données, ce que je n’avais pas l’intention de faire
      Je ne sais pas exactement comment le moment du changement décrit dans ce billet recoupe mon expérience. Peut-être que j’utilisais une ancienne version de la bibliothèque et que, si aujourd’hui crypto/rand est en pratique quasiment indiscernable de math/rand, tant mieux :-)
    • L’un des meilleurs arguments en faveur d’un CSPRNG, ici ChaCha8, est que les benchmarks le placent à moins d’un facteur 2 de PCG
      La taille d’état reste relativement importante (64 octets contre 16), mais c’est bien mieux que mt19937 ou que l’ancien PRNG de Go
      Si un CSPRNG était beaucoup plus lent, comme c’est généralement le cas avec les CSPRNG classiques qui ne sont pas des variantes de ChaCha à nombre de tours réduit, il serait moins attrayant comme valeur par défaut
    • Quels seraient les autres cas où l’on a besoin du premier ? Je ne pense qu’à une graine fixe pour obtenir des résultats reproductibles, par exemple pour des tests ou de la vérification
      Il existe un autre petit facteur qui pousse les gens vers les PRNG même lorsqu’ils n’ont pas besoin de graine. Les API de CSPRNG incluent toujours une erreur à gérer, en cas d’échec d’appel système ou de manque d’entropie
      À quelle fréquence les lectures de crypto/rand échouent-elles réellement ? Combien faut-il lire pour épuiser l’entropie sur des systèmes modernes ? Je n’ai jamais vu d’échec même sur des milliards de requêtes, et dd fonctionne aussi très bien
      Je me demande si, pour la plupart des cas d’usage, une API de style Must/panic ne serait pas le bon choix par défaut
      Au passage, j’ai regardé le paquet secrets de Python (https://docs.python.org/3/library/secrets.html), et il n’y a aucune mention du fait qu’il puisse lever une exception. En pratique, est-ce que cela n’arrive tout simplement pas ?
    • J’aime l’approche selon laquelle « tous les nombres aléatoires du système devraient provenir d’un CSPRNG, sauf échappatoire explicite »
      On perd un peu en performances, mais on obtient une garantie bien plus forte : ne pas provoquer de catastrophe en utilisant le mauvais générateur de nombres aléatoires
      Il est dommage que, dans presque tous les langages, les développeurs doivent encore se soucier de cette arête vive
  • Pour ceux qui ne le savent pas, gosec et son extension golangci-lint signalent l’utilisation de math/rand
    https://github.com/securego/gosec/blob/d3b2359ae29fe344f4df5...

    • L’un des aspects que je préfère dans math/rand/v2, c’est de pouvoir l’utiliser en entreprise sans directives nolint ni discussion de PR qui s’ensuit
  • Je suis encore en train d’interpréter les recommandations sur la sécurité et les nouvelles options de la v2
    Le billet de blog utilise des phrases comme « il faut autre chose pour les valeurs secrètes », puis détaille l’aléa cryptographique, ChaCha8 et la façon dont il est ensemencé par l’aléa système, ce qui donne une impression très « sûre »
    Pourtant, la documentation du paquet dit ceci
    ... but it should not be used for security-sensitive work ... This package's outputs might be easily predictable regardless of how it's seeded. For random numbers suitable for security-sensitive work, see the crypto/rand package.
    Alors pourquoi le billet de blog donne-t-il l’impression que math/rand/v2 pourrait être utilisé pour des « valeurs secrètes » ?
    En bref, cela signifie-t-il que tout ce qui est sensible doit toujours utiliser crypto/rand, et que les améliorations décrites ici sont un filet de sécurité au cas où quelqu’un utiliserait math/rand/v2 de façon inappropriée ?

    • Oui. math/rand/v2 n’est pas optimal, mais l’utiliser par erreur là où il aurait fallu utiliser crypto/rand ne se transforme plus immédiatement en faille de sécurité critique
      Le texte dit aussi ceci
      Il reste préférable d’utiliser crypto/rand. Le noyau du système d’exploitation est mieux placé pour garder les valeurs aléatoires secrètes face à diverses attaques par observation, il ajoute continuellement de la nouvelle entropie au générateur, et il a fait l’objet de davantage d’examens. Mais utiliser math/rand par erreur n’est plus une catastrophe de sécurité
  • Même dans le pire benchmark, la nouvelle stratégie n’était qu’environ deux fois moins rapide qu’un générateur de nombres aléatoires non sécurisé, et la plupart des benchmarks étaient beaucoup plus proches
    Go trouve un bon équilibre entre sécurité et performances pour la bibliothèque standard et les applications construites par-dessus. Ce serait bien que d’autres écosystèmes suivent
    Si une application a besoin de nombres aléatoires rapides et non sécurisés, elle doit implémenter son propre générateur interne
    Mettre des nombres aléatoires non sécurisés à portée de main, c’est laisser traîner un outil pour se tirer une balle dans le pied qu’on pourrait ranger

    • Franchement, ça paraît pire
      Encourager les gens à supposer qu’une primitive "random" est cryptographiquement sûre favorise de mauvaises pratiques
      Rendre math/rand/v2 cryptographiquement sûr peut résoudre un problème, mais désormais quelque chose qui ne semble pas promettre de sécurité devient « acceptable »
      En général, les fonctions math/rand n’ont pas la convention d’être cryptographiquement sûres. Changer cela pour que du mauvais code fonctionne correctement par accident peut masquer les autres erreurs que nous pourrions commettre si nous faisons déjà ce genre d’erreur évidente
  • Le math/rand de Go 1 devrait plus précisément être appelé générateur de Fibonacci retardé additif
    La première présentation vient de l’article de Green, Smith et Klem
    [1] https://doi.org/10.1145/320998.321006

    • Il ne me semble pas que cet article mentionne la partie « retardé ». Ou alors je l’ai manquée
      Je connais aussi https://www.leviathansecurity.com/blog/attacking-gos-lagged-..., qui l’appelle également générateur de Fibonacci retardé
      Rob Pike et moi avons échangé par e-mail il y a quelques mois avec Don Mitchell, qui a écrit la version C originale du générateur de Go 1, pour lui demander comment il décrirait cet algorithme, et il a répondu : « d’après mes souvenirs, Jim et moi avons implémenté un générateur proche du LFSR de Marsaglia »
      Les deux descriptions, générateur de Fibonacci retardé et générateur de type LFSR, me semblent correctes selon le point de vue. Les deux conviennent, mais dans l’article nous avons choisi d’utiliser la description de l’auteur original
  • S’il fallait relever un petit défaut, il me semble qu’ici aléa statistique et générateur de nombres pseudo-aléatoires sont mélangés
    La définition Wikipédia de l’aléa statistique est : « une suite de nombres est dite statistiquement aléatoire lorsqu’elle ne présente aucun motif ni aucune régularité reconnaissable »
    Cette définition s’applique-t-elle aussi à un véritable générateur de nombres aléatoires (TRNG) ? Il faut l’espérer. Au moins à long terme ou à la limite. Sinon, ce n’est pas un TRNG
    Un TRNG doit produire, sur le long terme, « une suite de nombres sans motif ni régularité reconnaissable »
    On peut donc dire que l’aléa statistique ne désigne pas un PRNG, mais qu’il peut aussi s’appliquer à un TRNG
    Le problème vient sans doute du fait qu’il existe de nombreux tests d’aléa statistique destinés à vérifier qu’un PRNG possède une forme limitée d’aléa statistique
    Donc, pour identifier un PRNG, l’expression « générateur de nombres pseudo-aléatoires » aurait été plus appropriée que « aléa statistique ». Mais cela reste un tout petit défaut