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

Je ne comprends pas non plus toute ces contraintes que tu formules.
En quoi lire un fichier et en prendre que la partie que l’on souhaite est compliqué en Rust ? La lib de crypto ne sais pas lire un sorte de « pipe » qui viendrait de ton parseur de fichier ?

Oui voila. @elois tu ajoutes bien les formats que tu veux. De toute manière les gens qui utiliserons le même fichier pour Dunitrust et les clients pourront demander ensuite ce qui est le plus pratique pour eux.

Pourtant il n’y en a que 5 et j’ai beau les relire je n’en aucune de supprimable, quelle contrainte ne comprend tu pas exactement ?

La raison d’être de ce thread est de définir un format unique interopérable et sécurisé qui serve de standard, ce qui me semble désirable et pour l’utilisateur final et pour les dev (un seul format a gérer dans le code).

Pour atteindre cet objectifs les contraintes 2, 3 et 5sont absolument nécessaire. Il reste le versionnement et 'indication de l’algo, tu voudrais un format qui ne soit pas versionné ou qui n’indique pas l’algo utilisé ? Je ne comprend pas :wink:

@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.

Les format « conteneur » peuvent sembler propres et élégant à première vue, je comprend que tu est pris cette direction kimamila, mais en fait c’est une fasse bonne idée pour 2 raisons :

  1. Certains des sous-formats a l’intérieur ne seront pas accepté ça et là, donc ce n’est pas interopérable.
  • Ce type de format « conteneur » est très confusant pour l’utilisateur, qui en comprendra pas pourquoi dans certain cas son .duniterkey est accepté et dans d’autres cas non alors que c’est « le même format ».
1 Like

Ce n’est pas « mon ». L’idée originale est de cgeek (himself !).

bon bref propose un autre format super selon tes contraintes, et on codera le truc. pas de soucis :slight_smile:

1 Like

Ca peut être le hash de notre clef en mots du dictionnaire.
Faut penser à cette histoire de testamen aussi… N’oubliez pas/

Le mieux pour ne pas laisser la clef dans l’ordinateur, c’est de ne lui donner que quand on veut qu’il la connaisse. Pour mémoriser 42 mots, niveau que produit « manyverse » c’est déjà galère.

A moins qu’on le choisisse d’une façon qui nous fasse le mémoriser.

My 2 LOVe

1 Like

De notre seed tu veut dire ? En terme de sécurité ce n’est pas acceptable, la seed ne doit pas être liée « facilement » avec des mots humains, sinon c’est trop facile a bruteforcer.
Le passage entre les mots humains et la seed doit être assuré par une fonction de dérivation coûteuse en calcule et en mémoire afin d’empêcher les attaques par dictionnaire : c’est le rôle de scrypt.

De plus, le format doit être universel, or scrypt prend 3 paramètres libres qui l’utilisateur peut choisir quand il génère son trousseau (sakia le permet), donc impossible de faire un format universel qui contiendrais des mots humains (d’autant qu’il existe d’autres fonctions de dérivation que scrypt, même si scrypt est la plus robuste actuellement, on ne peut pas empêcher que certains utilisent autre chose).

Exactement. On peut très bien saisir ses crédentials a chaque démarrage afin qu’il ne soient jamais stockées sur le disque.
Duniter le permet déjà avec l’option --keyprompt, ainsi plus besoin de fichier de trousseau.
Je proposerai également cette option dans Dunitrust :slight_smile:

A noter cependant que ton trousseau est forcément en mémoire vive pendant que le programme s’en sert, donc c’est forcément « dans l’ordinateur » même si c’est que temporairement :wink:

C’est embêtant ça… Perso, je ne pourrai jamais mémoriser une clef hexadécimale, et la conserver sur papier peut être cause d’erreur de recopie…

Mais pourquoi c’est trop facile à bruteforcer?
Ca doit dépendre du nombre de mots, et du dico utilisé?

A partir de combien de mots on pourrait considérer que cette méthode est solide?

key = SigningKey.from_credentials(argv[1], argv[2], None)

Non ça n’a rien d’embêtant, tu n’a pas besoin de mémoriser une clé hexadécimale. On peut très bien mettre en place des Mnemonic comme sur le bitcoin, eux aussi utilisent une KDF (Key Derivation Fonction), au contraire, une KDF coûteuse nous permet d’avoir à mémoriser seulement 9 mots pour la même sécurité que 48 mots sans KDF coûteuse :slight_smile:

Parce que sans KDF coûteuse, les ressources nécessaires pour tester une combinaison sont trop faibles, il est donc trop facile de calculer des milliards de milliards de combinaison très rapidement pour qui dispose d’un supercalculateur.
Alors qu’avec une KDF coûteuse comme scrypt et avec les paramètres utilisées actuellement dans Duniter et Cesium (N=4096,r=16,p=1), il faut faire des calculs dans 8Mo de mémoire pour tester une seule combinaison. Or, la mémoire dispo pour chaque unité de calcul est très limitée, y compris dans les supercalculateurs, ce qui réduit de plusieurs ordre de grandeur le nombre de combinaisons testables par seconde.

Tout dépend de la façon de générer la seed a partir des credentials, et tout dépend également de la nature des crédentials (du dico utilisé, le dico diceware n’a pas la même taille que le dico des Mnemonic).

Je dirai qu’avec les param qu’on utilise actuellement dans scrypt, si ont utilisais les Mnemonic on serait très safe a partir de 9 mots :slight_smile:

1 Like

Merci. OK, si j’ai bien compris, on trouve les mots après avoir fait la paire de clefs (avec une fonction bijective qui bouffe un max de RAM)?
Un logiciel (CLI) qui ferait ça en langue française à recommander?

Non tu n’a toujours pas compris, je t’invite a lire la RFC bip39 : https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki

La génération des Mnemonic se fait indépendamment de la façon de générer la seed.
On peut le mettre en place dans Duniter/G1 mais il faut qu’on choisisse une convention commune : quels salt et password on injecte dans scrypt a partir d’un Mnemonic et avec quels paramètres pour scrypt.

Je peut faire une proposition, le vrai dilemme étant le choix des param de scrypt, s’il sont trop élevés, ça ne fonctionnera pas sur les vieux téléphones, s’il sont trop faibles, on ne pourra pas utiliser les Mnemonic (le dico ne contenant que 2048 mots il faut des param fort pour la KDF).

1 Like

Oui, ce serait super qu’on fixe un truc… Parce qu’une fois fourré dans une chaine de blocs, on peut pas trop revenir en arrière… Enfin, je sens que ça va pas être facile de tomber d’accord avant la fin du mois…
Le problème des vieux téléphones… Tu veux parler de ceux à clapet? Ou de smartphones qui n’ont pas assez de RAM/CPU ?

En fait, si on trouve un bon dico, on peut réduire les paramètres pour scrypt.
Un gros dico ferait l’affaire?

Des smartphones qui n’ont pas assez de RAM/CPU, ils pourraient planter au moment la génération de la seed a partir du Mnemonic saisi par l’utilisateur.

Le principe des Mnemonic est d’être simple a retenir pour l’utilisateur, ça a été bien étudié par des linguistes, on a pas les compétences pour refaire le dictionnaire.
En vrai, y a pas besoin d’allonger le dico, avec 9 mots on peut se contenter de param de scrypt soutenables, par contre il faudra imposer 9 mots minimum a tous les utilisateurs des Mnemonic.

1 Like

@elois ok, cool. je crois que j’ai mieux cerné le problème avec ces foutues clefs
Ce qu’on aurait de mieux de dispo en CLI c’est ça?

@vit C’est en python, ça peut se fusionner avec duniterpy?

@Frederic_Renault je viens d’en coder un en Rust, ça m’a pris 4h, si ça te sert n’hésite pas a me faire un dons en G1 :slight_smile:

1 Like

ça ne me semble pas tout à fait le même sujet met en lien :
Selon moi, la meilleurs sécurité qu’on peut avoir pour les secrets, ce n’est pas un fichier de trousseau à tel ou tel format, c’est un trousseau dont la clef privée (stockée ou dérivé d’une seed) ne quitte jamais son hardware dédié (carte à puce, ledger, NFC…) ce qui impliquerait de demander à ce hardware d’effectuer le travail de signature à chaque fois qu’on en a besoin. De cette façon, keylogger, ou autre cesium-web serais bien incapable de s’accaparer les secrets de l’usager. Tout au plus ils pourrait proposer au hardware de signer des documents non souhaité par l’usager, et l’usager pourrais ne pas y être attentif.

Mais coté dev, ça demanderait plus que la gestion d’un format supplémentaire puisqu’il faudrait communiquer avec le hardware pour demander la signature des documents.

Autres reférences hardware wallet sur le forum (et lieux je pense plus approprié que ce fils pour continuer à parler hardware-wallet pour les intéressés) :




3 Likes

Je suis évidement à 200% d’accord, mais tous les utilisateurs ne pourront pas se procurer ce matériel, ça coûte des UNL.
De plus, on garde le risque de perte de ses credentials si on perd le matériel.

Personnellement, en tant qu’utilisateur la solution qui me conviendrais le plus c’est le brainstockage d’un mnemotic, que je saisirai a chaque fois sur un matériel hors-ligne qui signerai les documents via qr-code ou autre moyen. Ainsi, si je perd le matériel je ne perd pas mes credentials car ils sont dérivés de ma passphrase mnemotic, ce serait l’idéal :slight_smile:

2 Likes

Voici ma proposition de Format DEWIF (Duniter Encrypted Wallet Import Format) :

Ça ressemble un peu au format WIF défini par Tortue en plus safe et plus simple :

  • Pas de version non chiffrée.
  • Pas de salt non-chiffré, ce dernier permet de vérifier si le fichier dérobé contient bien le trousseau recherché (en calculant le salt de la pubkey ciblée), et facilite donc les attaques ciblées. Un fichier trousseau bien sécurisé ne doit pas permettre de savoir quel trousseau se trouve à l’intérieur.
  • Pas de checksum complexe, la pubkey est déjà le meilleur checksum possible.
  • Pas de base58, cette base complexe et coûteuse n’a été inventée que pour faciliter la saisie manuelle, elle n’a donc pas de sens pour un stockage dans un fichier destiné a être lu uniquement par une machine.

Format DEWIF v1 en résumé :

version (8 bytes)
encrypted seed (32 bytes)
encrypted pubkey (32 bytes)

Exemple :

Trousseau généré via scrypt avec les paramètres suivants:
password: « password »
salt: « salt »
N : 4096
r: 16
p: 1

0x000000001 #v1
0x22a91d9afa1dd13e96cecfa38d3f3655ca2726818ba5aa84e6b7dee1a036fc0f # seed
0xecdaab8f7ea0ea6f4b9f4e930cef2a1bb277736f64c971c43ca5d73cfb4bb80f # public key

Le fichier DEWIF contiendra la string base 64 suivante (chiffrée avec la clé AES zéro, càd 32 octets valant tous zéro) :

AAFTQgEdcnSqvdxZW9Q+37b1RpiC5lsd/kjT01xUq122obU8R2IyyAVqpAsC2s7dwOX9xJ4r9WRnNrcpjLt3Mnq3

Si ce format vous convient je vais coder une implémentation de référence en Rust avec plusieurs cas de test, ça vous sera utile pour tester vos développements :slight_smile:

1 Like

C’est DEWIF ou DUWIF ? Y a les deux mon capitaine… :wink:

1 Like

Oups, c’est DEWIF, je doit être trop habitué a taper DU :sweat_smile:

Dans le cas d’un serveur où on ne veut pas retaper les identifiants à chaque redémarrage, comment fait-on ? Soit on stocke la clé de déchiffrement du DEWIF, soit on n’utilise pas DEWIF ?

@matograine a déjà posé la même question plus haut et j’y ai déjà répondu :

De plus, Dunitrust proposera une options --random-keys qui permettra de le redémarrer sans rien saisir, il utilisera alors un trousseau aléatoire différent a chaque fois, c’est pratique pour les tests.

Donc, en dehors des cas de trousseaux aléatoires, on ne fait pas, c’est une mauvaise pratique de sécurité qui vulnérabilise la monnaie.
Aujourd’hui on s’en fou on est trop petit, plus on sera gros plus les attaques seront fortes et fréquentes, je pense que nous devons poser maintenant les bases d’une meilleure securité a moyen terme pour préserver notre monnaie a long terme. Et cela passe par interdire les mauvaises pratiques qui ne sont pas gênantes aujourd’hui mais qui pourraient être la cause de la mort de notre monnaie demain.

2 Likes