LoupVaillant / Monocypher

An easy to use, easy to deploy crypto library
https://monocypher.org
Other
594 stars 79 forks source link

Compatibility with TweetNaCL #177

Closed peirick closed 4 years ago

peirick commented 4 years ago

Hi Loup Vaillant,

following the documentation monocypher should be compatible with Libsodium/TweetNaCL in the sense that the client can run monocypher and the server can run Libsodium.

I wrote a simple test application, but encryption with monocypher and decryption with TweetNaCl does not work.

Here my very basic code:

#include "monocypher.h"
#include "tweetnacl.h"
#include <stdio.h>
#include <string.h>

// not used just a stub
void randombytes(uint8_t *buff, uint64_t size) { memset(buff, 1, size); }

int main(int argc, char *argv[]) {

  uint8_t secretkey1[32];
  uint8_t secretkey2[32];
  memset(secretkey1, 1, sizeof(secretkey1));
  memset(secretkey2, 2, sizeof(secretkey2));

  uint8_t publickey1[32];
  uint8_t publickey2[32];

  // derive publickey with tweetnacl for server
  crypto_scalarmult_curve25519_base(publickey2, secretkey2);

  const uint8_t text[50] = "test text";
  // create nonce
  const uint8_t nonce[24] = {3};

  // add 16 bytes to hold mac
  uint8_t cipher[16 + sizeof(text)] = {0};

  // client using monocypher
  {
    // derive publickey with monocypher for client
    crypto_key_exchange_public_key(publickey1, secretkey1);
    // key exchange
    uint8_t sharedkey1[32];
    crypto_key_exchange(sharedkey1, secretkey1, publickey2);
    // encrypt
    crypto_lock(cipher, cipher + 16, sharedkey1, nonce, text, sizeof(text));
  }

  // client using tweetnacl
  //{
  //  // derive publickey with monocypher for client
  //  crypto_scalarmult_curve25519_base(publickey1, secretkey1);

  //  // key exchange
  //  uint8_t sharedkey1[32];
  //  crypto_box_beforenm(sharedkey1, publickey2, secretkey1);

  //  // pad with 16 0 bytes
  //  uint8_t temp_plain[sizeof(text) + crypto_box_ZEROBYTES];
  //  memset(temp_plain, 0, crypto_box_ZEROBYTES);
  //  memcpy(temp_plain + crypto_box_ZEROBYTES, text, sizeof(text));

  //  // encrypt
  //  uint8_t temp_encrypted[sizeof(text) + 16 + crypto_box_BOXZEROBYTES] = {0};
  //  int ret = crypto_box_afternm(temp_encrypted, temp_plain,
  //                               sizeof(text) + crypto_box_ZEROBYTES, nonce,
  //                               sharedkey1);
  //  if (ret != 0)
  //    return 1;

  //  // unpad 16 bytes
  //  memcpy(cipher, temp_encrypted + crypto_box_BOXZEROBYTES, sizeof(cipher));
  //}

  // server using tweetnacl
  {
    // key exchange
    uint8_t sharedkey2[32];
    crypto_box_beforenm(sharedkey2, publickey1, secretkey2);

    // pad with 16 0 bytes
    uint8_t temp_encrypted[sizeof(cipher) + crypto_box_BOXZEROBYTES];
    memset(temp_encrypted, 0, crypto_box_BOXZEROBYTES);
    memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, cipher, sizeof(cipher));

    // decrypt
    uint8_t plain[sizeof(cipher) + crypto_box_ZEROBYTES] = {0};
    int ret = crypto_box_open_afternm(
        plain, temp_encrypted, sizeof(temp_encrypted), nonce, sharedkey2);
    if (ret != 0)
      return 1;

    // unpad 16 0 bytes and 16 bytes of MAC
    memmove(plain, plain + crypto_box_ZEROBYTES,
            sizeof(plain) - crypto_box_ZEROBYTES);

    if (memcmp(plain, text, sizeof(text)) == 0) {
      puts("ok");
    } else {
      puts("nok");
    }
  }
}

Maybe you can spot the error in my code? Btw. it would also be nice to have a migration guide from NaCL API to Monocypher API.

Regards

LoupVaillant commented 4 years ago

Hi peirick,

Unfortunately, what you are trying to do is impossible. Monocypher is compatible with Libsodium only. Not with NaCl nor TweetNacl. There are two major differences here:

There's a third major difference with EdDSA (called Ed25519 in (Tweet)NaCl and Libsodium, but Monocypher provides a way to use SHA-512 like everyone else (and thus fully conform to Ed25519).


To interoperate with Libsodium, you want to use those Libsodium functions:

crypto_scalarmult_base()  // generate public key
crypto_scalarmult()       // key exchange
crypto_core_hchacha20()   // hash shared secrets with that
crypto_aead_xchacha20poly1305_ietf_encrypt()
crypto_aead_xchacha20poly1305_ietf_decrypt()
crypto_aead_xchacha20poly1305_ietf_encrypt_detached()
crypto_aead_xchacha20poly1305_ietf_decrypt_detached()

May I ask you what part of the documentation lead you to believe Monocypher was compatible with TweetNaCl? Something somewhere is probably not as clear as it should be.

peirick commented 4 years ago

Now that you said that. It's not explicitly stated. It just has been my impression. Maybe the benchmarks and the explicit comparison to tweetnacl and NaCl, and statements from Readme:

If Monocypher is too slow, try Libsodium or NaCl. If you're not sure, you can always switch later.

and that in the Documenatation under

Why not LibHydrogen?

It's explicitly stated that It's incompatible with libsodium. But it's nowhere stated that Monocypher is incompatible with NaCl.

So my wrong conclusion must have been, that if NaCl/tweetnacl ist compatible with libsodium and Monocypher is compatible with libsodium, so Monocypher must be compatible with NaCl/tweetnacl.

Thanks for clarification.

LoupVaillant commented 4 years ago

Thanks, I made a couple mistakes indeed. The README was outright mistaken, sorry about that. It's fixed now.

Additionally, the Why page now states: "Monocypher is compatible with Libsodium (Libsodium only, not (Tweet)NaCl)."

Sorry again for the confusion, and thank you for your feedback.