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

I hate to waste your time because Im sure Im doing something dumb. Im still looking for updated docs but the link Im using is under /nodes/common/doc/blob/dewif/rfc/.

This morning’s code changes are few, a change from 1byte currency g1 to 4bytes g1-test, trying to match the dewif string in your latest dewif.rs commit, and using aes_pw=‘titi tata toto’ as scrypt passphrase and the hash of ‘dewif’ + aes_pw as salt to create the aes key.

If you point me to your latest docs link… I’d rather waste my time than yours.

dewif_draft.py.txt (1,7 Ko)

Spencer971

Haaa ok that’s why you can’t do it, you rely on the old repository that is archived. The RFC repository has been moved here: documents / RFCs · GitLab

The DEWIF RFC is here: https://git.duniter.org/documents/rfcs/blob/dewif/rfc/0013_Duniter_Encrypted_Wallet_Import_Format.md

1 Like

cool… Please give me a chance to work from there and Ill come back with my results.

1 Like

Ok… Im getting closer, but docs are still off. Docs need an update, but the code you are using to create your example dewif works for me.

Docs are better regarding the version (its 4 bytes big-endian as expected instead of 1) and the currency (which is 4bytes big-endian for g1-test instead of 1byte g1).

Docs are still flawed in that the example seed and pubkey do not match how the docs indicate they should be created, and the example pubkey is NOT the pubkey that the example seed would create.

To match your example dewif as my test target, I simply used your example seed… creating a different pubkey than the example, then followed the expected algo for creating a dewif… without exceptions… and I end up matching your dewif example.

My latest code is: dewif_draft.py.txt (1,6 Ko)

Spencer971

added: While updating docs examples, between version and seed, I believe you need « 0x10000001 # g1-test » since it will be part of the dewif string that others are trying to match.

1 Like

Thank you very much @Spencer for your new attempt :slight_smile:

I just found out why. It’s the credentials in the example that are not good ‘salt’ instead of ‘user salt’, same for the password. I just fixed that in the RFC :slight_smile:

If you want to try again, I think everything should be right now :slight_smile:

1 Like

I missed that… I was trying to create seed/pubkey with ‹ password › and ‹ salt › instead of ‹ user password › and ‹ user salt › respectively.

Now the only updates needed in the docs are to adjust the pubkey example (because it’s not created by the seed), and to add an example 4byte big-endian currency for g1-test.

I’ll later take a re-look at the docs, when you are done with commits, and implement dewif as default in my generate_keys.py script… later when I have fresh eyes… Ill run down the docs from top to bottom at that time to verify that they’re accurate. Thank you for getting to this Elois.

Respectfully,
Spencer971

? Are you really sure?

I have the seed bfa3f6e322cf21d0e652f79a69df9498fdf5347665e5646d9041f756496a1143 create the 17df9d2b59cdd2825955691e3a783e6da403148ddebb1144d1a9b9e545f23710 pubkey.

I just re-checked again and this time I’m sure of it, I think you’re wrong somewhere.

I already give the value of the 4 bytes for the g1-test, the proof:

Currencies code

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

So I don’t understand what you’re talking about :confused:

1 Like

For my comment about the currency, I agree that you have the legend up top… but your example just above your sample dewif shows all the test inputs necessary to construct the dewif, except for the currency and I just thought it might be improved by having « 0x10000001 #g1-test » as the 2nd line… since that is necessary to duplicate the dewif example string… so future devs don’t have to try guess which currency was used in your example. as in:

0x000000001 #v1
0x100000001 #g1-test
0xbfa3f6e322cf21d0e652f79a69df9498fdf5347665e5646d9041f756496a1143 # seed
0x17df9d2b59cdd2825955691e3a783e6da403148ddebb1144d1a9b9e545f23710 # public key

As for the seed in the example creating the example pubkey, I still get something different. I get: 17df9d2b059cdd2825955691e3a783e6da403148ddebb1144d1a9b9e545f2371
which is eerily similar to yours, but not exact. Have we found a buggy ed25519 implementation? Did we break ed25519 and now we get to win a prize? Did I cut/paste your sample pubkey wrong? Im lost again (but don’t worry, this happens frequently, Im used to it).

Spencer971

added:
The only difference in our pubkeys are the first 4 bits of the 5th byte and the last byte… or as if a 0 was clipped off the end of the hex and inserted at 5th byte.

or perhaps the 0 was mistakenly clipped from byte5 and appended in the docs… because if that didnt happen, im not sure how we come up with the same aes-encrypted results… the 2nd half of the encrypted-part would be wrong since it’s the pubkey.

p.s… this just confirms to me that documentation (and doing it) is evil… RTFCode > RTFM

I reproduced my same Rust test with the lib sodiumoxide and:

seed: bfa3f6e322cf21d0e652f79a69df9498fdf5347665e5646d9041f756496a1143
sodiumoxide pubkey bytes: [23, 223, 157, 43, 5, 156, 221, 40, 37, 149, 86, 145, 227, 167, 131, 230, 218, 64, 49, 72, 221, 235, 177, 20, 77, 26, 155, 158, 84, 95, 35, 113]

sodiumoxide pubkey hex: 17df9d2b59cdd2825955691e3a783e6da403148ddebb1144d1a9b9e545f2371
ring pubkey bytes: [23, 223, 157, 43, 5, 156, 221, 40, 37, 149, 86, 145, 227, 167, 131, 230, 218, 64, 49, 72, 221, 235, 177, 20, 77, 26, 155, 158, 84, 95, 35, 113, 0]
ring pubkey hex: 17df9d2b59cdd2825955691e3a783e6da403148ddebb1144d1a9b9e545f23710

We can see that sodiumoxide does produce the same bytes as ring but gives only 31 bytes (although ring adds zeros at the end to make sure that the output is always 32 bytes).

But adding this zero in the middle like your script does is not correct. Maybe it’s your base 16 encoding that’s not good, you have to print the bytes to check !

2 Likes

If I print the bytes of my pubkey, I get the same list of bytes represented as integers as you… it ends in 113 and is 32 bytes long.

If I just focus on the 5th byte of your pubkey: hex of 59 translates to decimal 89, not to decimal 5. Your list of printed bytes (represented as integers) implies that the real 5th byte of your pubkey has a hex value of 05 instead of 59.

Futher, I imagine we’re both aes encrypting bytes… and we couldnt possibly land on the same encrypted-part of the dewif if we were not using the same aes key, seed, and pubkey bytes.

Spencer971

1 Like

In fact it’s my conversion to base 16 which was not good, not wanting to install a lib for that I had made it by hand as well:

print!("ring pubkey hex: ");
for b in keypair.public_key().as_ref() {
    print!("{:x}", b);
}

By using the lib hex instead :

println!("ring pubkey hex: {}", hex::encode(keypair.public_key()));

I get the same representation as you:

17df9d2b059cdd2825955691e3a783e6da403148ddebb1144d1a9b9e545f2371

I have just corrected the RFC, is everything compliant now? :slight_smile:

2 Likes

yes… I confirm.

I was able to cut/paste the pubkey from your rfc example, remove my commented-out assert statements, and my script ran confirming that my python is creating the same dewif string as yours.

I will still followup with a re-read of your rfc while implementing dewif for my play/learn script, when I have fresh eyes, and will get back to you IF I have problems.

Thank you for your time today,
Spencer971

2 Likes

Dewif files load and save are implemented as a domain in Tikka architecture.

Inherits SigningKey class of DuniterPy for future implementation in v1.0.0 of DuniterPy.

Here is the code for @Spencer and all Pythonists !

Thanks to @Spencer for his simple AES encrypt code that I have used (and improved :wink: )

dewif.py (2,9 Ko)

Enjoy !

5 Likes

Je viens de mettre à jour la spec de DEWIF ainsi que l’implémentation de référence en Rust, le changement:

Modification du paramètre N de scrypt de 4096 à 32768. cela va permettre d’utiliser un password de chiffrement moins fort.

2 Likes

Après j’ai envie de dire, en fonction des performances sur mobile, il doit être possible de définir 2 niveau de scrypt(N) possible automatiquement en fonction de la version d’android. Et le nombre de caractère du code PIN en fonction:

Si ta un vieux téléphone, t’a besoin de 2 cases de ta mémoire en plus.

1 Like

Finalement pour garantir une compatibilité descendante j’ai restauré les anciens paramètres de scrypt pour la version v1 de DEWIF.

Et j’ai créé une version v3 permettant de choisir une valeur libre pour le paramètre N, valeur inscrite dans l’en-tête du format DEWIF v3.

J’en ai profité pour simplifier la RFC (suppression de phrases confusantes signalées par @vit ). Je vous invite à lire la RFC à jour :

https://git.duniter.org/documents/rfcs/blob/dewif/rfc/0013_Duniter_Encrypted_Wallet_Import_Format.md

Ceux qui ont déjà implémenté la v1 (@vit et @Spencer je crois ? ) n’ont donc finalement pas besoin de modifier leur implémentation.

Vous pouvez, si vous le souhaitez, ajouter le support de la v3 à votre implémentation, j’ai fourni un exemple dans la RFC :slight_smile:

J’ai implémenté DEWIF v3 dans l’implémentation de référence en Rust. La nouvelle version de la crate dup_crypto sera automatiquement publiée sur crates.io si la CI/CD se déroule avec succès.

Avec DEWIF v3 il va être désormais possible de choisir la valeur de N au runtime.

Concernant les critères sur lesquels se baser pour le choix de N, c’est indépendant de DEWIF, dont je te réponds sur le fil de Ğecko.

4 Likes

Dans la mesure où tu proposés d’implémenter les HDwallets pour Gecko, un ajout à la RFC me semble nécessaire.

Les HD wallets ont une contrainte : la clef publique maître ne doit être révélée que dans l’objectif de faire un audit des clefs dérivées. Pour éviter toute fuite de la clef publique maître, je pense qu’il serait bon de la masquer à l’utilisateur sauf cas exceptionnel et ne présenter que des clefs dérivées.

Pour cette raison, un nouveau currency code pourrait être créé afin d’indiquer au client que ce trousseau est le maître d’un HDWallet et que sa clef publique ne devrait pas être révélée.

Je propose d’ajouter 1 aux codes existantes :

0x00000010 - HD G1
0x10000001 - HD GTest

1 Like

Dsl mais je ne vois pas le rapport avec la choucroute.

Les spec de DEWIF sont agnostiques de l’usage qui sera fait du trousseau. Le fait qu’un trousseau servira ou non de trousseau maître pour de la dérivation HD wallet est hors du scope de DEWIF.

DEWIF fait déjà le nécessaire pour ne pas dévoiler la clé publique.

Il faudrait plutôt qu’on crée une RFC dédiée à comment on souhaite gérer les HD wallet dans l’écosystème Ğ1, mais c’est indépendant de la manière de stocker un trousseau.

Pas forcément. Si tu fais de la hardened dérivation alors la clé publique maître ne permet pas de connaître les clés dérivées.

2 Likes

Le rapport avec la choucroute, c’est le “I” de Import. Il me semble nécessaire qu’il y ait une procédure pour que, lors de l’import d’un trousseau, le client sache tout de suite si des mesures particulières doivent être prises avec ce trousseau.

Dans la RFC actuelle, DEWIF désigne à la fois :

  • un format de fichier en .dewif contenant une string base64, qui peut être utilisé comme format d’import,
  • la string base64 proprement dite.

Il y a là ambiguïté, à mon sens.

Il est tout à fait possible d’intégrer la string DEWIF dans un fichier texte formaté differemment, avec par exemple le champs :

usage : member/wallet/hdwallet

Ce type de fichier d’import aurait le rôle indiqué ci-avant : indiquer au client l’usage prévu pour ce trousseau.

Pas de souci pour avoir une RFC spécifique pour ce point, après avoir discuté de comment on veut utiliser les HDwallets.

Ta dernière phrase me montre que je devrais aller repotasser le sujet :slight_smile:

1 Like

En effet, je viens de supprimer toute notion de fichier ou de stockage dans la RFC.

DEWIF défini désormais uniquement un format de sérialisation d’un wallet, il n’y a plus de notion de fichier :slight_smile:

2 Likes