RFC DEWIF: Duniter Encrypted Wallet Import Format

Je suis d’accord avec @kimamila sur la confusion entre version et type de structure/contenu de la sérialisation.

Je propose ceci pour simplifier la RFC et les implémentations :

  • C’est la première version de la RFC, alors on ne doit avoir que la version 1. Cela me paraît plus logique.
  • Pour les variantes, on ajoute un champ type, avec un code (chaîne, entier, ou tableau parce que y a pas que les chaînes ou les entiers dans la vie, y a aussi les tableaux). Pour moi un entier suffit.
  • Du coup en suivant ce raisonnement, dans version on met 1.
  • La variante 3 est une évolution de la variante 1, on peut donc supprimer la variante 1, car elle peut être stockée sous la forme de la variante 3.
  • La variante 2, stockage de plusieurs trousseaux, pareil, elle peut stocker 1 clef, donc on vire la variante 3 et 4, et on spécifie le type (ed25519 ou bip32-ed25519) avec le champ type.

Au final, on devrait avoir dans la RFC de la version 1 de la sérialisation :

  • La version 2 actuelle avec 1 dans le champ version, déclinée en deux types : (ed25519 ou bip32-ed25519)

Dewif bytes structure

Version Currency code Type log N Version data
4 bytes big endian 4 bytes 1 byte 1 byte Any size

Currencies code

Currency Code
None 0x00000000
Ğ1 0x00000001
Ğ1-Test 0x10000001

Type code

Type Code
ed25519 0x01
bip32-ed25519 0x02

Version data (encrypted)

seed1 public key1 seed n… public key n…
32 bytes 32 bytes 32 bytes 32 bytes

The public key serves as a checksum. To check that the DEWIF base64 string is not corrupted, simply generate an ed25519 keypair with the seed and check that the obtained public key matches.

Symmetric encryption algorithm : aes256

aes256 key: scrypt of user passphrase with the following parameters:

password: passphrase
salt: sha256(« dewif » ++ passphrase)
N: 2^(log N)
r: 16
p: 1

2 Likes

@kimamila @vit suite a vos remarques je viens de retravailler entièrement la RFC:

Il n’a plus qu’une seule version, qui contient comme méta-données l’algorithme et le Log N.

Pour simplifier également, un DEWIF ne stockera qu’un seul trousseau.
Avec les HD wallet on peut générer une infinité de trousseaux à partir d’un seul trousseau maître, et celui qui à plusieurs trousseaux maîtres peut avoir un DEWIF pour chaque trousseau maître, ça me semble plus cohérent.

J’ai ajouté 2 exemples (1 par algo):

3 Likes

J’ai ajouté un commit pour corriger des petits bugs de markdown, et j’en ai profité pour mettre les paramètres dans des tableaux. @elois, ne force push pas sur la branche :wink:

C’est bon pour moi.

1 Like

C’est noté je viens d’update ma branche locale :slight_smile:

Du coup, j’ai réfléchi à cette RFC, et notamment au format de sérialisation.
Dans le format dunikey, il y avait déjà Type, Version

Dans Type, on peut mettre le format (ed25519-BIP32, etc)
Puis on ajoute les autres champs dont on besoin, ici ça peut être : Seed ou bien Data.

Le tout est en Yaml.

Donc qu’est-ce qui empêche de mettre les HD Wallet dans ce format ? La seule différence est que DEWIF est en binaire.

Pourquoi vouloir faire absolument du binaire, pour un si petit contenu ?
On pourrait mettre juste la Seed en binaire (puis base 64)

Tout ce nouveau format RFC me paraît bien complexe, vis a vis de ce qu’il apporte comme gain : uniquement la gestion HD Wallet.

Bon après, si vous voulez absolument un chaîne base64 qui porte tout pourquoi pas.
Mais est-on bien d’accord qu’il faudra bien savoir, à un moment, de quel format il s’agit pour pouvoir le parser… Donc soit une extension de fichier, soit un champ texte Type: DEWIF ( mais dans ce autant découplé encore et utilise le Type comme dans la RFC : ed25519 et ed25519-BIP32).

J’aimerai qu’on aille au bout du cas d’utilisation pour un utilisateur, pour valider tout ça, et le gain réel fonctionnel.

Bref …

Moi je fais une implémentation avec une extension .dewif.

Ce que je n’aime pas avec les fichiers .dunikey, c’est justement la multiplicité des versions/format dans une même capsule, qui rend catastrophique l’interopérabilité.

C’est comme si on disait à quelqu’un, je t’ai envoyé un .dunikey et qu’il nous répondait," mon client ne le supporte pas". Ça n’arrive pas avec pdf…

Tikka ne supportera que des formats protégés par un mdp, donc ewif et dewif.
Pour obliger l’utilisateur à sécuriser ses trousseaux, qu’il ne manquera pas de laisser traîner partout, notamment sur mobile…

Moins on n’aura de formats, plus ce sera facile pour les utilisateurs.

La structure du fichier n’a aucune importance pour moi, puisqu’elle ne concerne que le développeur et que c’est aussi simple de parser du binaire (même plus sûr, car mieux spécifié) que du texte (qui peut avoir des espaces, des tabulations et des sauts de lignes différents entre les systèmes).

En résumé, pour moi, une extension ne doit contenir idéalement qu’un format.

2 Likes

Un message a été scindé en un nouveau sujet : Extensions de fichiers

Je viens de passer rapidement sur la version du jour et j’ai une question: pourquoi « version, currency code, version data » et pas « version, currency code, data » ? (ou payload ou autre, peu importe).

Actuellement, en lisant la section « Version data » on pourrait croire qu’il s’agit de la donnée qui doit être dans le champs « version »: je pense que ça prête à confusion, même si j’imagine que l’intention est de signifier « data expected for this specific version ».

Oui tout à fait, je viens d’expliciter ça du coup :slight_smile:


En discutant avec @poka on se rend compte qu’on à besoin de stocker directement le mnemonic à la place de la seed afin de pouvoir le redonner à l’utilisateur plus tard (nécessaire pour différer le sharding par exemple).

Étant donné que les trousseaux maîtres des HD wallet doivent être issues d’un mnemonic (c’est ce qui est demandé par la norme BIP32 et ce que je propose également dans notre RFC HD wallet,
je propose que l’algo Bip32-Ed25519 implique nécessairement que ce soit l’entropie du mnemonic qui soit stocké à la place de la seed.

Pour rappel, l’entropie d’un mnemonic est définie ici : bips/bip-0039.mediawiki at master · bitcoin/bips · GitHub

Outre l’entropie, du mnemonic, il faut également stoker le langage (1 octet).

@vit qu’en dit tu ?

Si j’ai bien compris, on aurait en lieu et place de la seed :

Mnemonic Sentence Mnemonic Entropy
String int

De toute façon, stocker la seed ou la phrase Mnemonic, en terme de risque on est kifkif puisqu’à partir de la mnémonic on a une seule seed possible.

Cela fera plaisir aux utilisateurs qui auront perdu leur Mnemonic (à condition qu’ils ne perdent pas le code de chiffrement du bloc Dewif).

Moi ça me va.

Dans les fichiers vidéos, pour stocker des données de longueur variables, il existe le standard KLV (Key Length Value). On peut s’en servir pour la phrase de mnémonic, à moins que vous ayez déjà une idée.

Non juste l’entropie, la phrase étant obtenue de manière déterministe à partir de l’entropie :slight_smile:

Oui c’est le but :slight_smile:

Pas besoin de faire aussi compliqué alors que l’entropie d’un mnemonic n’a que 5 longueurs possibles : 16, 20, 24, 28 et 32.
Il suffit donc de stocker directement cette longueur sur 1 octet.

1 Like

@vit j’ai commité une proposition de spec pour stocker le mnemonic dans le cas de l’algo Bip32-Ed25519. Peut tu regarder ça ?

L’exemple 2 ne contient pas encore toutes les données car je n’ai pas encore fait l’implémentation, je n’ai pas envie de reperdre du temps à coder une implémentation pour rien, j’attends qu’on soit d’accord sur les spec pour implémenter, après quoi je compléterai les données de l’exemple 2 :slight_smile:

Cela me paraît bon. Je comprend enfin mieux l’entropie, un nombre proposé dans l’implémentation recommandée en Python par le dépôt que tu pointes.

Si je peux me permettre une remarque, je dirais que, machinalement, je n’ai pas utilisé dans mon implémentation la sérialisation en base64 de la structure binaire proposée, car je ne voyais pas ce quelle venait faire là. Parfois les premières impressions sont les bonnes et je me dis que cette sérialisation est superflue (en tout cas si je stocke le binaire brut dans un fichier comme je le fait). Elle n’a de sens que si on transporte les données dans des protocoles textes genre email ou autre, si je ne me trompe ?

Du coup je me demande si cette sérialisation a sa place dans la RFC, chacun pouvant sérialiser comme il veut selon ses besoins (et moi pas du tout)…

1 Like

Tu as tout à fait raison. J’ai proposé la sérialisation en base64 par souci de simplicité pour les dev habitués à raisonner en mode texte (où dit autrement, pour les dev pas à l’aise avec le binaire).
Peut-être peut t’on reformuler cela comme un exemple de format de sérialisation possible, voudrais-tu bien faire une MR pour expliquer ça dans la RFC de la manière qui te semble pertinente ? :slight_smile:

Ok je fais ça.

Pour info :

1 Like

Done.

1 Like

@vit il y a encore un changement que j’aimerais apporter à DEWIF: je souhaite remplacer l’algo de chiffrement symétrique AES256 par XOR.

XOR est l’algorithme de chiffrement symétrique le plus rapide au monde, ça seule contrainte c’est que pour être sécurisé, la clé de chiffrement doit être à usage unique et au moins aussi longue que les données chiffrées.
Vu qu’on utilise déjà scrypt pour dériver la clé de chiffrement, il suffit de demander à scrypt de nous fournir une sortie de taille égale à la taille des données chiffrées.

Ça simplifierait la stack, on pourrait virer AES256, qui n’a d’intérêt que lorsque l’on doit chiffrer plusieurs messages différents avec la même clé de chiffrement.

1 Like

Moi ça me va. Il y a un exemple Python dans la page wikipedia (si tu me prends par les sentiments… :wink: ).
C’est simple et élégant. Si on peut nous même choisir la longueur de la clef via scrypt, on est bon.

Haha j’avais même pas vu :stuck_out_tongue:

De mon côté avec l’implémentation Rust de scrypt je peux. Si tu utilises une implémentation type C tu dois avoir un paramètre dkLen pour choisir la taille de la sortie :slight_smile:

Ok, je viens de pusher un commit mettant à jour la RFC en ce sens. Je vais commencer l’implémentation ce soir ou demain :slight_smile:

1 Like

The entropy is stored in 32 bytes to avoid revealing the size of the stored mnemonic.

Je suis en train de faire l’implémentation python et je trouve cette phrase bizarre puisqu’on stocke la taille de l’entropie et que l’on peut en dériver la phrase mnemonic. Peux-tu préciser quelle info est vraiment cachée ici ?

[edit]
Dans l’exemple 1, le log de N est de 15 au départ, il devrait être de 12 (tableau parameters)
[edit 2]
Implémentation terminée en Python dans Tikka ! tests fonctionnels avec les exemples !

1 Like