2 points par GN⁺ 2024-05-08 | 1 commentaires | Partager sur WhatsApp
  • Dans Go 1.22, les packages existants math/rand et le nouveau package math/rand/v2 ont été modifiés pour utiliser un générateur de nombres aléatoires cryptographiquement sûr. Cela permet d’offrir une meilleure qualité d’aléa et de réduire fortement les dégâts potentiels lorsque des développeurs utilisent par erreur math/rand à la place de crypto/rand.

Différence entre aléa statistique et aléa cryptographique

  • L’aléa statistique convient à la simulation, à l’échantillonnage, à l’analyse numérique, aux algorithmes aléatoires non cryptographiques, aux tests aléatoires, au mélange des entrées, au random exponential backoff, etc.
  • Même une formule mathématique très simple et facile à calculer fonctionne suffisamment bien pour ce type d’usages. Mais un observateur qui connaît l’algorithme utilisé peut, après avoir vu un certain nombre de valeurs, prédire la séquence suivante.
  • L’aléa cryptographique, lui, doit en pratique rester totalement imprévisible, même si un certain nombre de valeurs générées auparavant ont été observées.
  • Les protocoles cryptographiques sûrs, les clés secrètes, le commerce moderne et la confidentialité en ligne dépendent fortement de l’aléa cryptographique.

Le générateur math/rand de Go 1

  • Il utilise une méthode de type Linear-feedback shift register (LFSR).
  • Son problème est que son état interne est entièrement exposé sous la forme d’un vecteur de 607 uint64.
  • Si l’on lit 607 valeurs du générateur, tout l’état est révélé et les valeurs suivantes peuvent être prédites.

Le générateur PCG de math/rand/v2

  • Il utilise l’algorithme PCG de Melissa O'Neill. Il s’agit d’un LCG 128 bits avec post-traitement.
  • L’état complet tient dans un seul nombre de 128 bits, et la mise à jour consiste en une multiplication et une addition sur 128 bits.
  • Dans Go, conformément à la proposition de O'Neill, une fonction de scramble basée sur la multiplication est utilisée à la place de l’approche fondée sur XOR afin de mélanger les bits plus agressivement.
  • Il demande plus de calculs que le générateur de Go 1, mais nécessite beaucoup moins de mémoire pour stocker son état, est moins sensible aux valeurs d’état initiales, et réussit aussi des tests statistiques que d’autres générateurs échouent à passer.
  • Mais PCG n’est toujours pas imprévisible pour autant.

Aléa cryptographique

  • En fin de compte, le système d’exploitation doit collecter de la véritable entropie à partir du bruit de dispositifs physiques.
  • Une fois assez d’aléa collecté (256 bits ou plus), on peut l’étendre avec un hash cryptographique ou un algorithme de chiffrement afin de produire une suite aléatoire de longueur arbitraire.
  • Le package crypto/rand de Go abstrait les différences entre ces interfaces des systèmes d’exploitation et fournit la même interface, rand.Read.

Le générateur ChaCha8Rand

  • Un nouveau générateur construit en adaptant le chiffrement de flux ChaCha de DJB.
  • Il utilise ChaCha8, la version à 8 tours.
  • Une seed de 32 octets est utilisée comme clé ChaCha8. Toutes les 16 blocks, les 32 derniers octets des blocks générés servent de clé pour les 16 blocks suivants, ce qui fournit la forward secrecy.
  • math/rand/v2 comme rand.Float64, rand.N, etc., utilisent toujours ce générateur.
  • math/rand utilise aussi ce générateur. En revanche, si rand.Seed est appelé, il utilise le générateur de Go 1.
  • Le runtime utilise lui aussi ChaCha8Rand pour choisir la seed de hachage des nouvelles maps.

Correction des erreurs de sécurité

  • En renforçant math/rand, Go 1.22 rend les programmes plus sûrs sans modification du code.
  • Par exemple, si Read de math/rand est utilisé par erreur pour générer une clé ou un usage similaire, c’était une faille de sécurité grave dans Go 1.20, alors que dans Go 1.22 cela reste simplement une erreur.
  • Même pour des usages qui ne « ressemblent pas » à de la crypto, comme la génération d’UUID ou l’équilibrage de charge d’un serveur frontend, l’utilisation de ChaCha8Rand est bien plus robuste que le générateur de Go 1.

Performances

  • ChaCha8Rand offre des performances globalement comparables à celles du générateur de Go 1 ou de PCG.
  • Sur du code 32 bits, ChaCha8Rand est plus rapide que PCG, qui nécessite une multiplication 128 bits.
  • Grâce aux algorithmes de math/rand/v2 qui évitent la division 64 bits, ChaCha8Rand ou PCG peuvent aussi être plus rapides que le générateur de Go 1 sur des opérations N(1000).
  • Globalement, 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.

L’avis de GN⁺

  • L’adoption de ChaCha8Rand dans Go 1.22 est un exemple remarquable d’amélioration au niveau du langage, qui augmente fortement la sécurité tout en minimisant la baisse de performances. Il est particulièrement marquant de voir des erreurs fréquentes des développeurs neutralisées à la source, au niveau du langage lui-même.
  • Comme le texte le souligne, ce type d’erreur n’est pas propre à Go et se retrouve souvent dans d’autres langages. La sécurité d’un système ne devrait pas dépendre des erreurs des développeurs ; d’autres langages devraient donc eux aussi évoluer, comme Go, vers l’utilisation de générateurs pseudo-aléatoires cryptographiquement robustes même pour les nombres aléatoires dits « mathématiques ».
  • En revanche, ChaCha8Rand ne convient pas à des primitives cryptographiques comme crypto_box ou xchacha20poly1305. Pour ce type d’usage, il faut toujours utiliser directement crypto/rand.
  • Le fait que le runtime Go utilise désormais aussi ChaCha8Rand pour choisir la seed de hachage des maps est un peu surprenant. Il n’est pas certain qu’un aléa cryptographique soit absolument nécessaire pour une seed de hachage, mais cela met en évidence la conscience sécurité de l’équipe de développement, qui cherche à éliminer d’emblée des possibilités d’attaque potentiellement pénibles.
  • Maintenant que la qualité de math/rand, package standard fourni au niveau du langage, s’est améliorée, il est probable qu’on l’utilise plus souvent directement dans les applications. Les projets qui utilisaient jusqu’ici une bibliothèque séparée de génération aléatoire à cause de la prédictibilité de math/rand devraient bénéficier de ce changement.

1 commentaires

 
GN⁺ 2024-05-08
Avis Hacker News

En résumé, voici les points principaux :

  • Dans Go 1.20, la fonction Read du package math/rand a été dépréciée, et des cas d’utilisation incorrecte à la place de crypto/rand ont été observés. Cela conduit à l’erreur consistant à utiliser un générateur de nombres aléatoires déterministe vulnérable du point de vue de la sécurité.
  • Remplacer le générateur aléatoire par défaut de Go par un CSPRNG (générateur pseudo-aléatoire cryptographiquement sûr) est une meilleure approche pour la sécurité. Il est préférable de ne choisir explicitement un PRNG que lorsqu’il est réellement nécessaire.
  • Des outils d’analyse statique comme gosec ou golangci-lint émettent des avertissements concernant l’utilisation de math/rand.
  • Le package math/rand/v2 utilise le chiffrement ChaCha8 et est initialisé avec l’entropie du système, ce qui donne une impression de « sécurité », mais il reste inadapté aux tâches sensibles du point de vue de la sécurité. Pour cela, il faut utiliser crypto/rand.
  • Le math/rand de Go 1 peut être considéré plus précisément comme un additive lagged Fibonacci generator.
  • Le nouveau math/rand, même dans le pire des cas, atteint environ la moitié de la vitesse de l’ancien générateur non sécurisé, et dans la plupart des benchmarks, la différence était presque nulle. Go semble trouver un bon équilibre entre sécurité et performance dans sa bibliothèque standard.
  • Cette approche est perçue comme plus favorable aux développeurs, car elle évite des erreurs comparables à celles de java.util.Random en Java.
  • Des questions ont été soulevées sur la raison du choix de ChaCha8 et sur le fait de ne pas utiliser à la place un chiffrement par blocs prenant en charge l’accélération matérielle, comme AES-GCM.