La vulnérabilité de Libsodium
(00f.net)- Une erreur de validation incorrecte de points sur la courbe Edwards25519 a été découverte dans la fonction bas niveau
crypto_core_ed25519_is_valid_point()de libsodium - Cette fonction est censée vérifier qu’un point appartient au groupe cryptographique principal, mais elle laisse passer à tort certains points faisant partie d’un ordre mixte (sous-groupe)
- La cause est une erreur de code dans la validation interne des coordonnées : seul X=0 était vérifié, tandis que la vérification Y=Z était omise, ce qui pouvait conduire à traiter des points invalides comme valides
- Dans la version corrigée, les deux conditions (X=0, Y=Z) sont désormais vérifiées, et les versions 1.0.20 et antérieures ou les versions publiées avant le 30 décembre 2025 sont concernées
- L’API de haut niveau (
crypto_sign_*) n’est pas affectée, et l’utilisation du groupe Ristretto255 est recommandée pour des raisons de sécurité et de performance
Présentation du projet libsodium
- libsodium est un projet lancé il y a 13 ans, dont l’objectif est de rendre la cryptographie simple à utiliser grâce à une API épurée
- Il est conçu pour permettre aux utilisateurs d’effectuer uniquement des opérations de haut niveau, sans avoir à connaître les algorithmes internes
- Le projet accorde une grande importance à la préservation de la compatibilité de l’API, et conserve jusqu’à aujourd’hui une cohérence fondée sur l’API de NaCl
- Certains utilisateurs emploient directement des fonctions bas niveau au-delà des limites indiquées dans la documentation, ce qui conduit de plus en plus à utiliser la bibliothèque comme une boîte à outils cryptographique
Cause du bug découvert
- Fonction en cause :
crypto_core_ed25519_is_valid_point()- Elle doit rejeter les points qui n’appartiennent pas au groupe principal (d’ordre L) sur la courbe Edwards25519
- Cependant, une partie des points d’ordre mixte (2L, 4L, 8L, etc.) passe la validation
- En interne, pour vérifier l’ordre d’un point, la fonction multiplie celui-ci par L puis vérifie si le résultat est le point neutre (identity)
- Le point neutre s’exprime sous la forme X=0, Y=Z, mais le code existant ne vérifiait que X=0
- En conséquence, des points invalides avec Y≠Z pouvaient être considérés comme valides
- Exemple : pour un point Q du groupe principal, le point Q+(0, -1), obtenu en lui ajoutant un point d’ordre 2, est invalide, mais passait la validation avant le correctif
Contenu de la correction
- Le commit de patch a été modifié comme suit
- Code existant :
return fe25519_iszero(pl.X); - Code corrigé :
fe25519_sub(t, pl.Y, pl.Z); return fe25519_iszero(pl.X) & fe25519_iszero(t);
- Code existant :
- Désormais, les deux conditions X=0 et Y=Z sont vérifiées afin d’assurer une validation correcte
Portée de l’impact
- Les cas suivants peuvent être affectés
- utilisation de la version 1.0.20 ou antérieure ou d’une version publiée avant le 30 décembre 2025
- validation de points d’entrée non fiables avec
crypto_core_ed25519_is_valid_point() - implémentation directe d’opérations sur la courbe Edwards25519
- Cependant, la plupart des utilisateurs ne sont pas concernés
- l’API de haut niveau (
crypto_sign_*) n’utilise pas cette fonction crypto_scalarmult_ed25519ne provoque pas de fuite d’information, même avec une clé publique invalide- les clés générées par
crypto_sign_keypairetcrypto_sign_seed_keypairappartiennent au bon groupe
- l’API de haut niveau (
Mesures recommandées
- Utilisation recommandée du groupe Ristretto255
- il est inclus dans libsodium depuis 2019 et résout les problèmes liés au cofactor
- les points décodés sont automatiquement sûrs, sans validation supplémentaire nécessaire
- il offre des performances supérieures à Edwards25519
- Si une mise à jour est impossible, il est possible d’effectuer la validation à l’aide de la fonction de remplacement au niveau applicatif proposée (
is_on_main_subgroup)
Diffusion du correctif et support
- Le problème a été corrigé immédiatement après sa découverte et est inclus dans toutes les versions stables diffusées après le 30 décembre 2025
- y compris les tarballs officiels, les binaires Visual Studio/MingW, les packages NuGet, les builds Android, le xcframework
swift-sodium, Rustlibsodium-sys-stableetlibsodium.js
- y compris les tarballs officiels, les binaires Visual Studio/MingW, les packages NuGet, les builds Android, le xcframework
- Une nouvelle point release est également prévue
- Le projet est maintenu par une seule personne, et il est possible de soutenir son amélioration continue via OpenCollective
1 commentaires
Réactions sur Hacker News
La bibliothèque PHP sodium_compat est elle aussi affectée par ce problème
Plus d’informations dans la PR #756 de security-advisories
Je compte passer la soirée à vérifier toutes les autres implémentations d’Ed25519 dans l’écosystème open source pour voir si elles présentent la même absence de validation
En revanche, je n’ai trouvé aucun cas implémenté de manière incorrecte comme la vulnérabilité mentionnée plus haut
Si je n’ai pas envoyé d’e-mail, c’est probablement que ce n’est pas dans la liste de déploiement Ed25519 d’ianix, que je l’ai manqué, ou que l’implémentation est sûre
Je développe depuis 4 mois des bindings sodium pour Lean4
J’en suis maintenant à l’étape Ristretto255, et je comprends pourquoi l’auteur est aussi enthousiaste à propos de cette technologie
Ristretto est une API sophistiquée qui permet de construire des polynômes arbitraires sur Curve25519, et c’est vraiment un plaisir à expérimenter
Si jamais l’auteur lit ce message, je tiens à lui adresser mes sincères remerciements
L’objectif de Libsodium était de fournir des API de haut niveau, pas des fonctions bas niveau
Le projet a été conçu pour que les utilisateurs n’aient pas besoin de connaître les algorithmes internes, mais avec le temps, de plus en plus de gens se sont mis à utiliser directement les fonctions de bas niveau
Au final, Libsodium s’est retrouvé utilisé comme une boîte à outils algorithmique
L’important, c’est de reconnaître la direction que veulent prendre les utilisateurs, sans imposer au projet une seule manière d’être utilisé
Certains projets deviennent dogmatiques sur ce point et finissent par échouer
Il est risqué de laisser des non-spécialistes manipuler directement des primitives cryptographiques
Libsodium a été conçu pour éviter que les utilisateurs ne se mettent eux-mêmes en danger
Idéalement, une bibliothèque devrait rendre impossible une mauvaise utilisation
Je recommande à ce sujet l’article “If You're Typing The Letters A-E-S Into Your Code, You're Doing It Wrong”
C’est pourquoi il est souvent préférable de limiter certaines fonctionnalités à private ou internal
Je ne sais pas si Libsodium a placé le curseur au bon endroit, mais l’équilibre est essentiel
Puis certains utilisateurs ont commencé à s’en servir comme d’un exécuteur de batch
J’ai corrigé quelques bugs pour prendre en charge leurs besoins
Au final, j’étais simplement heureux qu’il y ait des utilisateurs
Ce bug est une erreur de validation cryptographique subtile mais importante
Un contrôle apparemment simple comme « vérifier que c’est valide » est en réalité très complexe
Autoriser des points en dehors du sous-groupe d’ordre premier peut, même sans vulnérabilité immédiate apparente, faire s’effondrer les hypothèses des couches supérieures
De plus, les primitives de bas niveau sont réutilisées bien plus largement que prévu, donc une petite omission de validation peut avoir de grandes répercussions
Les problèmes de sous-groupes n’apparaissent que lorsqu’on construit des protocoles plus complexes sur Curve25519
C’est pourquoi je remappe autant que possible tous les points vers le sous-groupe d’ordre premier
Monocypher propose ce type de fonctions avancées
Par exemple
crypto_x25519_dirty_fast()oucrypto_elligator_map()Ces fonctions « dirty » génèrent des clés publiques couvrant toute la courbe, de manière à être indiscernables du hasard
On peut ensuite obtenir le même secret partagé lors d’un échange de clés X25519
C’est possible grâce à la conception de DJB, car même si la clé publique est atypique, le secret partagé est remappé vers le sous-groupe d’ordre premier
Au final, Ristretto n’est nécessaire que lorsqu’un tel remappage est impossible
Bien sûr, l’abstraction d’un groupe d’ordre premier est utile, mais quiconque est capable de concevoir ce genre de protocole devrait aussi pouvoir gérer un cofactor non trivial
Si vous travaillez dans une grande entreprise, je vous recommande d’envisager un soutien à Frank au niveau de l’entreprise
Et même si je le savais, j’aurais probablement à le soutenir avec mon propre argent, pas avec les fonds de l’entreprise
Je me demande si libnacl est également affecté
J’utilise chaque jour des logiciels compilés avec libnacl, mais aucun compilé avec « libsodium »
C’est vraiment une excellente bibliothèque
Merci à Frank Denis