2 points par GN⁺ 2026-01-01 | 1 commentaires | Partager sur WhatsApp
  • 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
    Publicité
  • 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);
  • 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_ed25519 ne provoque pas de fuite d’information, même avec une clé publique invalide
    • les clés générées par crypto_sign_keypair et crypto_sign_seed_keypair appartiennent au bon groupe
    Publicité

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, Rust libsodium-sys-stable et libsodium.js
  • 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

 
GN⁺ 2026-01-01
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

    • J’ai constaté que, dans certaines bibliothèques, la logique de validation était totalement absente
      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 voulais simplement dire merci pour votre contribution à l’open source
  • 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

    • Je me demande s’il existe un dépôt public pour ce projet
  • 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

    • C’est une remarque intéressante. Mais à l’inverse, ce que l’on pense que les utilisateurs veulent peut différer de ce dont ils ont réellement besoin
      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”
    • Si l’on considère toutes les fonctions internes comme faisant partie du contrat d’API, presque n’importe quel changement devient alors une rupture de compatibilité
      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
    • J’avais autrefois créé un framework de test C++ appelé CeeFIT, et j’étais fier de sa manière d’enregistrer les fixtures à la compilation
      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

    • Cela dit, X25519 et Ed25519 ont justement été conçus pour ne pas nécessiter ce type de validation
      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() ou crypto_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

    • Je travaille chez Apple, mais je ne sais pas qui est Frank ni comment fonctionne la procédure de soutien
      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