Chiffrement des messages Cesium+

J’ai fait un petit utilitaire standalone pour envoyer des messages sur la messagerie Cesium+ (et donc sur gchange aussi je suppose):

J’arrive bien à recevoir des messages sur Cesium+, je hash et signe correctement le document généré, mais mon soucis actuellement est que je ne pense pas utiliser le bon chiffrement pour le titre et le corps du message.

J’ai essayé en base 64, 58 et autre mais cela ne corresponds jamais à ce que je perçois dans mon debuggueur en analysant un message.

Par exemple pour la chaîne de caractère test en titre, chiffré avec la clé Do99s6wQR2JLfhirPdpAERSjNbmjjECzGxHNJMiNKT3P, Cesium génère:

6kmbIdwb/6K8hyaSQQ+MS8ieqSo=

Hors j’ai beau essayer dans toutes les bases possibles je n’obtiens jamais ce format, et je ne parviens pas à déchiffrer manuellement cette dernière :thinking:


J’ai trouvé comme ressource cette doc:

Et ce message:

Mais je ne trouve pas d’explication sur le chiffrement utilisé pour les messages.

J’ai même été voir dans le code directement, je vois que tu utilises une base58, il y a visiblement le nonce qui rentre en jeu mais je ne sais pas comment…
Le format que je trouve ressemble plus a une base64 mais plus petit que ce que je génère, alors si un nonce entre en jeu je ne vois pas comment ça peut diminuer ma tambouille …


Le résultat pour le moment est que les messages reçus sur Cesium sont illisibles:
image

(Sur la plupart des messages envoyés je n’ai même pas la chance d’avoir cette erreur, j’ai juste une notification Cesium+ pour réception du message, puis à la lecture il tourne dans le vide indéfiniment. A ce moment là ma boite de réception affiche 0 message alors qu’elle est pleine, jusqu’à ce que je supprime les messages corrompu manuellement via l’API :sweat_smile: )

3 J'aimes

Very cool project Poka.

Just last week, related to a disconnected MLO node, I wanted to be able to send a message to a list of pubkeys to refer them to a post Matograine made in the user forums. I could see this being very useful (for good and bad, as w/all tools).

I have no idea how cesium+ encrypts and decrypts, but I see that natools seems to be able to encrypt for a public key and decrypt with its private key… as Ive always understood asymmetric-key encryption/decryption to work (I may be mis-understanding this code).

However, I recently learned that libnacl offers multiple forms of encryption/decryption and one of them requires the sender’s private and the receiver’s public to encrypt and likewise requires the sender’s public and the receiver’s private to decrypt… as if there is a hidden sign-then-encrypt functionality/assumption (even though there is no signing… you get sender authentication for free).

If you take a look at the python libnacl documentation https://libnacl.readthedocs.io/en/latest/, you’ll see the standard form (recip’s pub to encrypt, recip’s priv to decrypt) referred to as « Sealed Box » and the sender-authenticated form as « Public Key Encryption ». My first thought was that maybe your « chiffrage » is of the SealedBox form while cesium+ may be using PublicKeyEncryption form. I believe that duniterpy supports both forms (not sure about natools).
In duniterpy, see encryption_key.SecretKey for the sender-authenticated form, and encrypton_key.PublicKey/signing_key.Signer for the traditional sealed box form.

-Spencer971

p.s. excuse my english, but I suspect my frenglish would be even more burdensome.

2 J'aimes

Yes I just checked duniterpy documentation, so yes it support both publickey and privatekey encryption, but natools just support publickey.

@kimamila do you confirm that’s my problem ?

1 J'aime

Dans natools j’utilise encrypt_seal et decrypt_seal, je ne connaissais pas EncryptionKey

D’ailleurs, EncryptionKey permet de manier des « box », et si j’ai bien compris c’est un format particulier avec chiffrement+signature+nonce, ce n’est pas précisé dans la doc.

Je vais ajouter des commandes dans natools pour ces box.

2 J'aimes

Just stabbing in the dark, and having fun, without knowing anything concrete about Cesium+ messaging…

… has 2 interfaces that appear to be related to encryption. Assuming box() is encrypt and openbox() is decrypt, both require arguments including keys from both sending and receiving parties… in the manner that I opined above and consistent with libnacl’s use of ‹ box › terminology when relating to encrypt/decrypt.

more hints: Your error dialog hinting at authentication or corruption (with libnacl’s PublicKeyEncryption… you cannot know because there is no separate signing/verifying step… both keys required to encrypt and both required to decrypt… otherwise nothing but ‹ corrupt › looking gobbly-gook).

more hints: whenever dealing with messages in Cesium, we’re frequently asked to re-authenticate our secret-identifier/password in both sending/reading… whereas we might ONLY be required to do this when reading a message that needs decrypting had it simply been encrypted with our pubkey.

-Spencer971

Bon après avoir passé plusieurs heures à essayer plusieurs méthodes, avec tweetnacl-js, libnacl en python, le code d’exemple fraîchement publié par @Spencer (auquel j’ai ajouté le passage d’un nonce manuel à la fonction box.decrypt) et même l’outil en ligne de tweetnacl-js (qui utilise le même algo Curve25519-XSalsa20-Poly1305 que Cesium), je n’arrive toujours pas à déchiffrer un message Cesium…

Du coup, j’offre 10DU à qui me publie un code python ou JS standalone qui permet de déchiffrer le titre et le contenu de ce message:

{
  "_index": "message",
  "_type": "inbox",
  "_id": "AXWnnyNt1gPFkfRsQ2BV",
  "_version": 2,
  "found": true,
  "_source": {
    "hash": "E43E36F6E53A1F76096F943B501BF4F2A0E5C96E9086B15FE2694518033EED0E",
    "signature": "M6uYdKcUQGGSwMebeTlbFY8K/FIB8oidauzMbdeQFBPBupGw4vhmzWozlHoz44UuJ3I47eoQDoZBwG/RKcZ8Aw==",
    "issuer": "DCovzCEnQm9GUWe6mr8u42JR1JAuoj3HbQUGdCkfTzSr",
    "recipient": "DCovzCEnQm9GUWe6mr8u42JR1JAuoj3HbQUGdCkfTzSr",
    "title": "LTmTBOGiakjGPGR7fCjWPnAVVFqkVjrmrxqY/iDWvdhWP+8oLtNgULScN2Rl/NifZGCA3LI=",
    "content": "YLVTaec04RoN9AMYNqVchnGknFipFTn3u06S/iCV84wuGLpsKoAsBbCfKci+7TsEdD7V3PQCyRSDANICRHuOiZOol1Svu87uQ3u1qwKSoAlcyloq1OdgTBNgkKCMkbQ0UYCsROr4bOuL8l3P7/xpK4+XFLwpmWCHuX+9fug6WovURlHSnVn8uYwuwn/ySF5CuYmULSXeU+1awrxDERdKPfysGYt2gi6DfX+LWd7ojbHPZTxvYlyjfgzG8bT6iDfFmtxUXEz9+3LpClewfZ7jdktaSM5dFE4+7CanBVQ=",
    "time": 1604835026,
    "nonce": "MmWoNzZggLrTtC7WW4G7yG3NiNdzKxn4c",
    "version": 2
  }
}

Toutes les informations sur l’émetteur/récepteur de ce message sont là:

salt: test
password: test

seed (base58): GA47R2WcyAw2GmEU8e2rYwYiLwLCZctfJtwzk87nhJpZ
privkey (base58): 5W8k1FGifVEWrBHoK5re6xnaoC9skk75tFxSmGFapJaNTUtAdeJp1i3kUS6ZrFWHZLYeQjdAQrFZ455Uxj6wyjHg
pubkey (base58): DCovzCEnQm9GUWe6mr8u42JR1JAuoj3HbQUGdCkfTzSr

seed (base64): 4TEMX4h4mMdz8mCBUgh6t8ffk8pvdMool047YVvjRjo=
privkey (base64): 4TEMX4h4mMdz8mCBUgh6t8ffk8pvdMool047YVvjRjq1UrJjxgScvk4jZon/B6IfEE//hILt5t6wWPXZ7U7E7w==
pubkey (base64): tVKyY8YEnL5OI2aJ/weiHxBP/4SC7ebesFj12e1OxO8=

nonce du message (base64): 482xiAewUx0RM6oLglHQG//0ySelpnL9

Les conditions d’obtentions de la récompense sont inscrites dans le contenu du message.

Jeu interdit pour le créateur de Cesium :roll_eyes:

4 J'aimes

Cool, a Sunday challenge:

However, I only see information for a single account and I suspect Ill need another account.

I can confirm that salt=test and password=test creates a b58seed like GA47… and a b64seed like 4TEM… and that the corresponding privkey/pubkeys in both b58 and b64 match… but this is just one account.

Is this the Sender… if so, where is the Recipient info? (salt/pass of the other account, and confirmation of which is which is good enough to keep me busy).

In advance, Ill be working from stuff in git.duniter.org/spencer/learn-g1… and I can already see that I need to support a non-empty nonce in the pkencrypt/pkdecrypt scripts.

Thank you for this challenge Poka, cool stuff… cool reward!

-Spencer971

These are same to keep it simple :slight_smile:

1 J'aime

Sorry to leave you hanging… but Im sofar unable to figure it out.

My problem is introducing a nonce… things work fine when no nonce included or nonce is null (whether Im using libnacl.public.Box class as well as the raw function libnacl.crypto_box_open()). I’ve tried with your nonce (its the right size of 24bytes) or the libnacl.rand_nonce() function and I always get the same error CryptError(‹ Unable to decrypt ciphertext ›). Breakfast for me, then another look with fresh eyes. -Spencer971

btw: If no nonce or null nonce works for you… The docs do imply that a nonce will be deterministically chosen from the message… which solves the security risk of using same nonce with same sender/recip yet different messages which might leak secret keys.

1 J'aime

I hereby concede defeat. I am unable to decrypt your Title and Contents above.
…but why not invite the Cesium devs?

I did figure out my problem with libnacl Public Key Encryption (using their box class and also the raw functions) regarding a user-supplied nonce… and my answer was to pass this in ONLY to the encryption function… but NOT during decryption (so the nonce must somehow be included in the cyphertext… which is cool… one less thing to exchange with the recipient).

I’ve pushed the ‹ user supplied nonce › fix and Ill include 2 files that show 1) using your keys and nonce to encrypt/decrypt and 2) using your keys without a nonce to do the same.

-Spencer971

withusernonce.txt (1,2 Ko)
withoutnonce.txt (1,2 Ko)

2 J'aimes

I know that I already conceded defeat, but I kept wondering all day.


Title: Grand jeu concours de l’année 2020 !
Content: Félicitation !!
Tu as remporté le grand jeu concours de reverse-engineer de Cesium+ =)

Tu as gagné 10DU :wink:

Publie ton code et répond à ce message avec ta clé publique pour recevoir ta récompense !


I mentioned my problem of passing the nonce into decrypt when « it must be included in the ciphertext » (btw: i learned how to spell « cipher »). It is… Its right there prefixed on the base64 ciphertext… the first 32 characters (24 bytes). So I simply concatenated your nonce + title as well as your nonce + content and then tried to decrypt those strings with the same keys…et voila.

Somewhere, those first 24bytes are being stripped off of what libnacl.public.Box().encrypt() returns as your ciphertext… but they actually need to be part of that ciphertext when it’s time to decrypt at the other end.

Ill follow the instructions and leave some code in another post.

-Spencer

4 J'aimes

Oh yeah !!

Congratulation @Spencer you won :slight_smile:

4 J'aimes

here you go… as simply as I could make it. :wink: -spencerpour_pokapow.txt (1,4 Ko)

[
added by Spencer971 after reward claimed… in the interests of overdelivering for poka, and leaving explanation of findings.
pour_pokapow2.txt (2,2 Ko)
]

1 J'aime

I can already see the payment… and you 2x-ed the reward. Thank you so much Poka. This is a monumental day for me… the first G1 I’ve actually earned. This is a great story!

-Spencer971

p.s. Im going to pass on your kindness with a 10DU to fdrubigny’s sport sante crowdfunding (an effort to merge his sports group with monnaie-libre).

1 J'aime

I confirm this code is OK !

As you said I decided to double the bet for perseverance !

Payment is written in blockchain: https://demo.cesium.app/#/app/block/371799

Once again, Bravo !

3 J'aimes

Ah ah!
Well done @Spencer ! You are at the top! I knew that you can bring a lot to the community with your technical knowledge, it’s great, I love it!
Thank you in advance for the sport-health crowdfunding, it’s really nice.
Sincerely, Francis

Sorry for my poor english, I didn’t make the effort to try to write in English myself I used a translator … Oops!

PS : With the confinement here, if you have a little time 1 hour or 2 hours a week, I have time to take English lessons with you, it will change you to the technique, but you will also earn Junes ! :wink:

1 J'aime

Avec plaisir Francis!!! :slight_smile: woohoo!

1 J'aime

Now natools handles box encryption/decryption!

echo hello |
python natools.py box-encrypt -p $RECIPIENT_PUBKEY -N |
python natools.py box-decrypt -p $SENDER_PUBKEY
# prints "hello"

Nonce can be passed explicitely with -n <nonce>.

Thank you @Spencer!

4 J'aimes

Nice!

I tried your commandline with 2 test accounts that I regularly play with and got « schooled » on pipes; it took me a few tries, then I remembered. The processes toward the end of the pipeline need to open first so that preceding processes have a stdin to receive their stdout. So I had to enter the credentials for decrypting before entering credentials to encrypt… and voila… as you said… « Now natools handles box encryption/decryption! ». Great work @tuxmain !

-Spencer971

No, the pipe executes the first command, then redirects its stdout to the next command’s stdin, in the same order as written.

The encrypt command takes the recipient’s pubkey and the sender’s credentials, the opposite for the decrypt command.

However, it is not working yet for Cesium+ messages…

2 J'aimes