Définir un format sécurisé pour les trousseaux de clés Ğ1

Pourquoi Dunitrust ne peut pas lire les clés privées ed25519 ?

J’ai déjà répondu a cette question dans le 1er post en indiquant que cela est dit au fait que Duniter utilise ring, et que ring ne peut pas lire les clés privées ed25519 ce qui est vrai.

Mais personne ne m’a demandé pourquoi je ne pourrais pas tout simplement utiliser une autre lib de crypto ou forker ring ? II y a des raisons précises à cela, que je n’ai volontairement pas explicité dans mon 1er post pour ne pas faire trop long, me disant qu’on finirait de toute façon par me poser la question.

J’ai préféré insister sur le fait que cette limitation n’est pas spécifique a ring mais s’inscrit dans la continuité de l’esprit « safe by design » qui est un des fondements du langage Rust et qui est fortement respecté par la plupart des librairies Rust, ce qui est vrai.

Évacuons déjà la possibilité du fork :
Je ne souhaite pas maintenir un fork d’une librairie de crypto tierce, cela représente plus de travail et augmente les risques de failles de sécurité par maintenance non assidue du fork. C’est exactement ce qui s’est produit dans Duniter avec le bug de TweetNacl, ce dernier a été corrigé dans TweetNacl dés 2015, mais cgeek ayant créé son propre fork « naclb », ce dernier n’a pas bénéficié du correctif.
C’est précisément parce que je sais qu’un tel problème pourrais se reproduire dans Dunitrust si j’utilise un fork d’une lib de crypto tierce que je me refuse à le faire.
Nous avons eu beaucoup de chances que le bug de tweetnacl n’était pas exploitable de façon malveillante, mais on ne peut pas parier qu’il en sera de même à l’avenir (ce serait un pari très dangereux qui me semble irresponsable de faire).

Enfin concernant la possibilité d’utiliser une autre lib de crypto, je me suis fixé plusieurs contraintes :

  • La lib doit être activement maintenue par beaucoup de développeurs et depuis longtemps, pour s’assurer qu’elle sera bien maintenue dans les années à venir lorsque des failles de sécurité seront découvertes dans les algorithmes qu’elle expose.
  • La lib doit dépendre d’aucune librairie dynamique (donc exclu un wrapper rust de libsodium), afin de faciliter le build et l’installation sur tous type de plateforme et d’OS.
  • La lib doit être la plus performante parmi celles qui respectent les autres contraintes.
  • Si d’autres dépendances de Dunitrust utilisent déjà indirectement une lib de crypto gérant ed25519, utiliser celle-ci de préférence pour ne pas alourdir le binaire Dunitrust avec 2 lib de crypto.

Historiquement, Dunitrust utilisait rust-crypto. C’est @nanocryk qui avait choisi cette lib a l’époque. Mais cette lib n’est plus maintenue depuis plus de 4 ans, car les dev initiaux de cette lib ont décidé il y a un peu plus de 4 ans de faire exploser cette grosse crate en plein de petites crates pour être plus « rusty way ». Ed25519 n’a jamais été réimplémenté, l’équipe de rust-crypto s’est contenté de l’écriture d’une abstraction utilisable par le « backend » de son choix : https://github.com/RustCrypto/signatures.

Il me fallait donc choisir un « backend » une implémentation concrète d’ed25519. J’ai donc passé plusieurs semaines (voir mois je ne sais plus) à étudier l’état de l’art dans l’éco-système rust, j’ai retenu 3 librairies sérieuses : ed25519‑dalek, sodiumoxide et ring.

Ne souhaitant pas dépendre de lib dynamiques, j’ai exclu sodiumoxyde. je trouvais également très dommage de faire une implémentation en Rust pour se baser sur du code C++ pour la partie la plus critique(la crypto), on perd les garanties apportées par le Rust.
J"ai donc expérimenté les 2 restantes :

ed25519‑dalek : 17 contributeurs, projet qui n’a que 3 ans et qui a déjà connu des trous d’inactivités importante dans le graphe des contributions. 340000 téléchargements, utilisé par 63 crates rust.
ring: 171 contributeurs, projet qui a déjà 6 ans et qui n’a jamais connu aucun trou d’inactivité depuis 6 ans. 2,8 millions de téléchargements, utilisé par 236 autres crates rust.

Les chiffres sont explicites, et confirme les conseils que j’ai reçu en meetup rust ou dans les channel irc rust, ring est l’état de l’art de Rust pour la crypto, c’est LA librairie que tous le monde recommande d’utiliser.

De plus, ring présente de meilleurs benchmark que ed25519‑dalek.

Et pour couronner le tous, ring est déjà utilisé par rustls , une implémentation en Rust de TLS/httpS, qui est utilisée par actix, le framework web que j’utilise dans Dunitrust. Donc je dépends déjà de cette crate.

Pour toutes ces raisons, je ne souhaite pas utiliser une autre lib. je vous avait prévenu que ce serait long :stuck_out_tongue:

4 Likes

ha désolé je n’avais pas compris, je mettrais un bémol sur le « clairement ». Tu parlais de « toutes ces contraintes » sans en viser une en particulier.
Et tu demandais "En quoi lire un fichier et en prendre que la partie que l’on souhaite est compliqué en Rust ", ce qui me semblais ne pas avoir de lien direct avec « pourquoi dunitrust ne peut pas utilisé la clé privé ». Je pensais que c’était lié a notre discussion sur le forum « conteneur » .dunikeys qui pose problème, ma réponse en atteste :

@kimamila ça n’a rien de compliqué, mais là n’est pas la question, c’est la conception même de ton format « conteneur » de plusieurs formats qui pose problème.


En effet c’est moins grave, car la seed ne sert a rien une fois le trousseau de clés généré, donc le développeur ne vas pas être tenté de la garder dans une variable, il sait qu’il peut se débarrasser de la seed dés qu’il a le trousseau de clé, la seed est donc utilisée dans un scope beaucoup plus limité et donc plus maîtrisable.
La clé privée a l’inverse, est nécessaire pour signer, elle est utilisée tout au long de la vie du programme (dans Duniter/Dunitrust en tout cas), sont risque d’exposition est donc infiniment plus grand.

1 Like

Désolé, je ne comprends pas. Si le développeur a le seed il peut bien faire ce qu’il veut, non ? Il lui suffit de l’utiliser avec n’importe quel code à lui et il a la clef privé en moins de 1ms… Conception safe ou non.

Tu veux donc utiliser ring qui ne gère rien d’autre que le seed, qui est un synonyme bijectif de la clef secrète. Je ne trouve pas cette explication longue. :slight_smile:

Pour la lib qui utilise sodium (qui est quand même la référence), quels sont les chiffres au fait ? Et les benchmark vis a vis de ring ?
Sodium est tellement léger que ça me paraît raisonnable de penser que Rust n’apportera pas grand chose (sur les perfs). A vérifier.

l’API d’une lib est conçue selon l’hypothèse que le développeur utilise cette lib. S’il utilise une autre lib pour contourner les protections de la 1ère ça ne sert en effet a rien, mais cela ne peut pas être causé par une faute d’inattention, c’est un acte volontaire fort, qui nécessite l’ajout d’une nouvelle dépendance et ne peut donc pas passer inaperçu.

Dans l’hypothèse ou une seule lib de crypto est utilisée donc, il est moins risqué que cette lib expose la seed plutot que la clé privée.

En fait ring gère la clé privée, mais les utilisateurs de ring n’y ont pas accès, l’encapsulation n’est pas dérogeable en Rust, il existe bien un mécanisme d’introspection mais il ne permet pas d’outrepasser l’encapsulation (contrairement au Java par exemple).

La référence en C, pas en Rust. L’un des objectifs de Rust est tout de même de remplacer le C/C++.
Je souhaite avoir le minimum de dépendances C/C++ dans Dunitrust, c’est beaucoup plus chiant a gérer dans tout ce qui est build/Ci/cross-compilation et plus chiant pour l’utilisateur final sur distribution peu commune.

Quand aux chiffres, le wrapper sodiumoxyde est beaucoup moins utilisé que ring (475000 téléchargements, 61 crates rust qui en dépendent) et à moins de contributeurs (70 contre 171).
Concernant les performances, je n’ai pas trouvé de benchmark qui comparent ring et sodium, mais si tu veut je peut essayer sur mon poste, ça devrait être rapide a coder :slight_smile:

Il y a également une autre raison : je souhaite que la crypto de Dunitrust soit compilable en webassembly, pour dup-tools-wasm notamment, mais aussi peut-être pour la future interface d’administration de Dunitrust, et pour un éventuel projet de PWA qui réutiliserais la lib de crypto de Dunitrust. Donc le wrapper sodiumoxyde n’est pas envisageable pour moi.

1 Like

En effet c’était rapide, j’ai utilisé criterion, une lib spécialisée dans la mesure de performances :

The primary goal of Criterion.rs is to provide a powerful and statistically rigorous tool for measuring the performance of code, preventing performance regressions and accurately measuring optimizations.

Voici comment reproduire ces benchmark sur votre poste :

git clone https://git.duniter.org/libs/dup-crypto-rs -b benches-ring-sodium
cd dup-crypto-rs
cargo bench

Si vous n’avez pas cargo : curl https://sh.rustup.rs -sSf | sh -s -- -y

Pour vous assurer d’avoir des résultats non influencés par le « bruits », cessez toute activité sur la machine ou les tests sont lancés puis rejouez la commande cargo bench jusqu’a ce que la phrase « No change in performance detected » apparaisse sur les 2 tests.

Ensuite, les graphes se trouvent dans target/criterion/report/index.html

Et voici les résultats sur mon poste de dev :

Ce graphe représente la fréquence des temps moyen. Chaque temps moyen étant calculé sur 100 itérations. Au total plus de 200000 itérations sont effectués pour chaque lib, ce qui fait plus de 2000 moyennes.
La moyenne des moyennes se situe autour de 18 us pour ring et 23,5 us pour sodium.

Et sur mon raspberry pi 4 :

La moyenne des moyennes se situe autour de 180 us pour ring et 223 us pour sodium.

Conclusion : sur mon poste de dev et sur mon rpi4, ring est environ 20% plus rapide que sodium pour signer. Reste a tester la vérification, je verrai ça demain :slight_smile:

3 Likes

Pour redonner les explications autrement : une librairie qui protège l’accès a la clé privée limite fortement les erreurs de fuite de cette clé dans le code du programme.

Les seed peuvent toujours être fuitée suite a une erreur, mais comme elles ne sont théoriquement utilisée qu’à un seul endroit du code (pour générer la clé privée), le risque d’erreur et de fuite est beaucoup plus limité.

Quand on dit « safe by design », c’est donc surtout en terme de limitation des erreurs humaines au sein du code du programme.

6 Likes

Tu as justifié l’impossibilité de Dunitrust à lire des clés privées en nous parlant de Rust et de son écosystème. Il aurait été suffisant de dire :

et :

Point. C’est tout ! Pas besoin de blabla sur « l’écosystème Rust incarne […] » qui n’a rien de pertinent et ne fait que déclencher chez le lecteur le radar « il essaye de noyer le poisson ».

2 Likes

Enfin, un point que tu ne précises pas : est-ce qu’il existe une impossibilité d’utiliser 2 libs en parallèle ? Ring la plupart du temps, ed25519-dalek pour les utilisateurs qui souhaiteraient utiliser leur trousseau existant.

J’ai d’ailleurs un exemple : le trousseau de Remuniter a été généré à partir de données aléatoires que je n’ai pas souhaité conserver. En l’état de Dunitrust, cela signifie-t-il que ce trousseau ne pourra jamais être réutilisé ?

2 Likes

Ok, merci d’avoir pris le temps de ces explications, qui me semblent plus claires. De même pour les tests de perfs.

Je saurai au moins la finalité de mon travail, quand je coderai le format PubSeed ou équivalent. :slight_smile:

1 Like

Désolé ça me semblais être au contraire le plus pertinent car c’est la raison même du pourquoi de cette limitation. Ce n’est pas du blabla, c’est une véritable « philosophie » de développement qui permet de limiter les erreurs humaines, et qui me semble donc on en peut pas pertinente dans le cas très critique d’une crypto-monnaie.

Il n’y a pas d’impossibilité à utiliser 2 lib en parallèle, mais ça complexifierai le dev et ça alourdirai le binaire final.

Haaaaaaaaa, merci, je connais enfin la vrai raison qui fait que mon choix te pose problème :slight_smile:

Et bien en effet Dunitrust est incapable d’utiliser ce trousseau pour le moment, cela nécessiterai en effet d’utiliser 2 lib de crypto et parallèles, c’est possible mais chiant, ouvre un ticket sur le dépôt Dunitrust pour tracer ce besoin :slight_smile:

1 Like

C’est fait, pour ne pas alourdir ce sujet j’ai récapitulé tous les résultats des tests de performance dans un nouveau sujet : Tests de performances : sodium et ring

Non, comme dit plus haut que tu fasses des choix ne me pose pas de problème (du moins, je trouve ce choix effectivement pénible, mais rien de bloquant car les fonds de Remuniter peuvent être transférés à une autre clé compatible Dunitrust).

Quelle surpoids ed25519-dalek impliquerait, à peu près ? Sur quelle taille de binaire actuel ?

C’est justement l’objet de mon reproche : je prétends que tu « te caches » derrière une philosophie. Pour quelle raison ? D’après ce que j’ai lu c’est principalement parce qu’elle te rassure¹.

N’est-ce pas ?


¹ : je viens juste de m’en faire la réflexion.

2 Likes

Du coup j’y est réfléchi et je pense que le mieux soit que le futur module remuniter utilise sa propre lib de crypto pour signer ses transactions. Ainsi pas d’ajout de complexité dans le cœur. Et si une erreur humaine se glisse dans le code du futur module de remuniter alors elle n’exposera pas tous les noeuds Dunitrust mais seulement ceux qui auront ce module.

Je ne m’en cache pas, j’adhère pleinement a cette philosophie « safe by design » et je pense même que c’est un devoir moral vis a vis des utilisateurs que de faire « de notre mieux » pour minimiser les risques. L’erreur est humaine, même les plus grand expert font des erreurs (cf faille Heartbleed).

Je prétend au contraire que c’est pour le moins irresponsable de ne pas adopter un paradigme « safe by design » pour quelque chose d’aussi critique que la monnaie.

1 Like

Si tu sécurises, tu le fais forcément au détriment de libertés (« sécuriser » signifiant restreindre un champ des possibles). Si l’on pousse le raisonnement à l’extrême, la position la plus responsable de toutes consisterait à ne pas réaliser de monnaie libre, ou bien tellement sécurisée qu’elle en deviendrait inutilisable. Ce qui serait absurde.

Par ce raisonnement on voit bien que la sécurité n’est qu’un aspect et certainement pas le plus important s’agissant de créer une monnaie libre.

Tu fais ici un choix discutable. A mes yeux et dans ce cas précis, c’est encore acceptable.

Mais ce que je souhaite souligner, rappeler, c’est que la sécurité n’est pas l’élément déterminant et qu’il convient de le laisser à sa juste place, autrement dit ne pas le mettre sur un piédestal.

2 Likes

Oui tout à fait. C’est pour cela que la bonne approche, c’est de restreindre par défaut, et selon les use case, de ne lever certaines limitations qui s’il y a un use-case qui le nécessite. Ainsi la surface d’attaque n’est pas plus grande que nécessaire.

Sophisme de l’homme de paille. On sait tous que le risque zéro n’existe pas, ce n’est pas pour autant qu’il faudrait tous autoriser. Une partie importante du travail de sécurisation consiste justement à définir ce qui est nécessaire et suffisant à exposer pour répondre aux besoins, tous le reste devant être interdit.

Je n’ai jamais dit que c’était le seul aspect, ni le plus important, tu fais encore un sophisme de l’homme de paille. Le sujet de ce fil concerne le format des trousseaux de clés, tu me poses des questions sur une limitation du format dont la motivation 1ère est la sécurité (même s’il y a d’autres motivations, que j’ai évoqué), forcément on parle de sécurité ici, ça ne veut pas dire que c’est le seul aspect ou le plus important. Sur ce coup là c’est toi qui te « caches » derrière un homme de paille au lieu de me dire honnêtement que ta crainte est la perte de libertés d’usage.

Je n’ai jamais dit le contraire, nous ne sommes tout simplement visiblement pas d’accord sur ce qu’est « sa juste place ».

L’un de mes objectifs à travers le développement de Dunitrust est justement d’améliorer sensiblement la sécurité de la Ğ1 (entre autre). Et cela passera forcément par minimiser la surface d’attaque, donc interdire les fonctionnalités risquées qui ne sont pas nécessaires.

Évidemment, le but n’est pas d’empêcher l’utilisation, tous les besoins nécessaires doivent être autorisés, mais parfois cela impliquera des changements cotés utilisateur.

Chaque limitation sera évidemment discutée, comme on l’a fait ici pour le format des trousseaux :slight_smile:

De mon côté, ça me poserait un problème de conscience d’ouvrir des potentielles brèches pour donner un confort non indispensable a l’utilisateur. Donc tous ce que je livrerai de manière « officielle » sera le plus possible « safe by design », quitte à limiter certaines fonctionnalités ou/et les rendre moins confortables à utiliser.
Le code étant libre, chacun est libre de forker pour lever une limitation qui ne lui conviendrait pas, mais dans ce dernier cas ce n’est pas de mon ressort.

1 Like

Quelle ironie, c’est précisément ce que je reproche à ton argumentation initiale. Selon moi ton homme de paille dans ce message pour le non-support des trousseaux PubSec est la sécurité, la véritable motivation : pas envie de rajouter la librairie ed25519-dalek.

Ceci étant dit, j’estime avoir suffisamment donné mon point de vue. Je vous laisse donc continuer la discussion.

3 Likes

Je penses d’ailleurs qu’on pourrait retirer le terme « standard » du titre du post.
Qu’elles propose un nouveau format ne me pose pas de problème, mais le définir d’emblée comme standard un peu plus.
C’est juste un nouveau format, quoi.

Bon elois, à toi de jouer avec ta petite équipe : bon courage à tous !

1 Like

@cgeek tu fait là un procès d’intention en décidant a ma place quelles sont mes véritables motivations, ça deviens très grave. Te rend tu compte une seconde de l’absurdité et du manque de respect d’une telle affirmation ? Ne pas être d’accord c’est une chose, mais décréter les intentions de l’autre a sa place NON ! Si tu te permet de faire cela alors plus aucune discussion n’est possible.

Franchement je ne comprend pas, il me semble essentiel de définir un format standard pour les trousseaux de clés, pas toi ?

S’il n’est pas « standard » a quoi bon en discuter ici ? Vous avez discutés quelque part du format .dunikeys décris par vit ? C’est ça que tu considère être le « standard » ?
Ou alors tu considère qu’il ne doit pas y avoir de standard du tout ?
Tu t’en fiche de l’interopérabilité et de son importance pour l’expérience utilisateur ?
Tu préfère que ça reste le bordel ou chacun a son propre format afin que notre écosystème reste un truc de geek incompréhensible ?

J’ai la désagréable impression de me démener seul pour définir des standard plus fiables et permettant une meilleure expérience utilisateur. Je ne comprend pas pourquoi je n’ai pas plus de soutien, vous pensez que ce n’est pas important d’avoir des standard et de l’interopérabilité dans l’écosystème Duniter/Ğ1 ? Vous pensez que la sécurité on s’en fou et qu’on avisera le jours où on subira une attaque avec une crise de confiance envers la Ğ1 (donc quand il sera trop tard quoi) ?

J’avoue ne pas comprendre, j’espère qu’il y a une majorité silencieuse qui comprend ces 2 objectifs on ne peut plus basiques et élémentaires (interopérabilité et sécurité). Mais savoir que 2 des principaux développeurs de l’éco-système Duniter/Ğ1 s’en fichent c’est sincèrement très inquiétant :confused:

1 Like

Le problème est que le format que tu proposes impose la sécurité.
Plus de sécurité signifie moins d’usages possibles.
Il en résulte, en conséquence, que ce format ne peut pas devenir un standard.

J’ai l’impression qu’il est en train de se passer ce qui suit :

1 Like