- 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
Avis Hacker News
En résumé, voici les points principaux :
Readdu packagemath/randa été dépréciée, et des cas d’utilisation incorrecte à la place decrypto/randont é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é.gosecougolangci-lintémettent des avertissements concernant l’utilisation demath/rand.math/rand/v2utilise 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 utilisercrypto/rand.math/randde Go 1 peut être considéré plus précisément comme un additive lagged Fibonacci generator.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.java.util.Randomen Java.