rweather / arduinolibs

Arduino Cryptography Library
435 stars 211 forks source link

Encrypt-then-sign or sign-then-encrypt? re: ed22519 #15

Open kitmonisit opened 7 years ago

kitmonisit commented 7 years ago

Hi, first of all I'll say it up front that I'm not very good at C or C++. I just want to get this working with my cloud backend, which uses libsodium under PyNacl.

As I understand it, in ed22519, I see that the sign function takes the following as arguments:

I have a few questions:

  1. Does it encrypt-then-sign or sign-then-encrypt?
  2. Where is the resulting ciphertext stored? I plan to hex-encode this ciphertext and send it to the cloud backend.
  3. How do I ensure that only the cloud backend can decrypt the ciphertext?

My idea of encrypting the message is:

  1. Take the plaintext
  2. Encrypt it using the privateKey of the sender.
  3. Encrypt it again using the publicKey of the recipient (cloud backend).
  4. Sign it using the signature of the sender.
  5. Send the ciphertext to the recipient.

Sender shares the following keys to the recipient in a secure way:

  1. verificationKey derived from signature
  2. publicKey derived from privateKey

To decrypt it at the cloud backend:

  1. Take the ciphertext.
  2. Verify it using the verificationKey of the sender. This ensures the sender is authentic.
  3. Decrypt it using the privateKey of the recipient. This ensures secrecy of the message and only the recipient can read it.
  4. Decrypt it using the publicKey of the sender. This ensures again that the sender is authentic.
  5. Hooray! I now have the plaintext.

How does your library lend itself to the above operations?

(I have left out details about defending against replay attacks and key theft, which I have already taken care of)

rweather commented 7 years ago

My library provides the basic building blocks for creating larger protocols like PEM, SSL/TLS, Noise, etc but it doesn't currently implement any of them.

Ed25519 is for signatures only. It doesn't provide any encryption facilities. A separate mechanism needs to be provided to encrypt the message contents. The usual method would be to use Curve25519 to establish a shared secret between the parties, and then hash that to create a key for AES-CTR or something similar. Then ed25519 is used to sign the encrypted message that is sent under the shared secret to verify the origin.

In general, encrypt-then-sign is the better choice because if an attacker manages to break the signature scheme, all they learn is statistical information about the ciphertext - which they already have. With sign-then-encrypt, if the signature scheme is broken then the attacker may learn some statistical information about the plaintext. The same applies to authenticated encryption modes like GCM and EAX.

kitmonisit commented 7 years ago

Thank you @rweather. I understand only bits and pieces of your comment (no fault of yours, of course), and by now my lack of understanding of encryption should be evident. Do you have examples demonstrating simple interfaces for encrypting, signing, and decrypting? Similar to these: PyNaCl public key encryption and PyNaCl digital signatures.

dastultz commented 5 years ago

In general, encrypt-then-sign is the better choice because if an attacker manages to break the signature scheme

If you sign then encrypt one would need to first break the outer encryption before having access to the signature scheme. This article makes a pretty good case for sign then encrypt: https://www.quora.com/Which-one-is-more-preferable-encrypt-then-sign-or-sign-then-encrypt

WildCryptoFox commented 3 years ago

Hello. I found this issue while searching for the following link I referenced to a friend.

https://theworld.com/~dtd/sign_encrypt/sign_encrypt7.html

This article describes why you don't want either sign-then-encrypt nor encrypt-then-sign and offers (dated) alternatives.

Short version. If Alice signs a message "I love you" and encrypts it to Bob, then Bob may re-encrypt the signed message and send Alice' love letter to Carol, who now believes Alice loves Carol. If Alice encrypts the same message for Bob and signs it, an active attacker may intercept the message and replace the signature with her own.

The "simple solution" (one of several offered in the article) is to sign the message along with a tag saying who the intended recipient is, then encrypt it.

The typical modern solution is hybrid encryption, meaning you asymmetrically exchange a key you then use to symmetrically authenticate and encrypt the messages. For one-offs use libsodium's crypto_box. To auth-encrypt a sequence of related messages and detect messages being dropped, duplicated, reordered, or truncated; use libsodium's secret_stream interface. Unlike crypto_box the secret_stream consumes a preshared key, so you'll need to do the key exchange yourself. For this I recommend 3DH (triple Diffie-Hellman) with static and ephemeral keypairs on both sides, using curve25519. This gives you 3 uniform keys, hash them together with blake2 to establish the shared session key.

(Ignore the X [dotted line] of Signal's X3DH to get the simpler and stronger 3DH.)

patrickduc commented 3 years ago

In general, encrypt-then-sign is the better choice because if an attacker manages to break the signature scheme

If you sign then encrypt one would need to first break the outer encryption before having access to the signature scheme. This article makes a pretty good case for sign then encrypt: https://www.quora.com/Which-one-is-more-preferable-encrypt-then-sign-or-sign-then-encrypt

Thanks for the comment. However, I don't agree with you. Or I should say, experts don't agree with you. This is a good reference on the subject : https://docs.google.com/viewer?url=https%3A%2F%2Fwww.iacr.org%2Farchive%2Fcrypto2001%2F21390309.pdf