LoupVaillant / Monocypher

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

Example for aead streaming encryption #270

Open TrueBrain opened 5 months ago

TrueBrain commented 5 months ago

For OpenTTD we are trying to figure out how we want to do encryption between server and client, and monocypher came out on top because of its small footprint and easy to use API. However, internally we have a small debate how to do things, as that goes with encryption.

In the documentation you make use of "incremental encryption" with some suggestion here and there about "stream", and this makes things a bit unclear to us. And this is mostly because we don't really understand any of this, so I thought it would be easier to just ask, instead of us trying something that might be insecure :D

First of all, can we use crypto_aead_write for streaming encryption? As in, we have a small packet between 10 and 1200 bytes, which we send every once in a while. Run it through crypto_aead_write, send the mac and cipher_text to the other side, and repeat? The nonce is already sent in the handshake, and from how I read it, we only need to send that once?

Second, as I read it, the key is rotated on every crypto_aead_write action, and as such, we do not need to add anything to prevent replay-attacks, like rotating the nonce every packet or something?

Ideally, if it is not all that much to ask, what would really help us is an example of a streaming implementation. Much like the Encrypt one message with the incremental interface example, but with more than one packet. With two packets alone would be of great help, just to understand what we do need to send, and what we don't.

Any help would be greatly appreciated :) Tnx!

LoupVaillant commented 5 months ago

Hi,

Your understanding of the streaming API is mostly correct. One thing you might have overlooked is the crypto_aead_init_*() functions of which we have 3 variants: djb, x, and ietf. You need to chose one of those to initialise the context… and chose your nonce. More on that at the end.


First of all, can we use crypto_aead_write for streaming encryption? As in, we have a small packet between 10 and 1200 bytes, which we send every once in a while.

Yes you can, and I explicitly thought of your use case when I designed this API.

Run it through crypto_aead_write, send the mac and cipher_text to the other side, and repeat?

Yep.

Second, as I read it, the key is rotated on every crypto_aead_write action, and as such, we do not need to add anything to prevent replay-attacks, like rotating the nonce every packet or something?

Correct. Once you've initialised the context, crypto_aead_write() will take care of everything, you don't need to call anything else, and you don't need to rotate the nonce. Just encrypt, send the cyphertext and mac, done.

Ideally, if it is not all that much to ask, what would really help us is an example of a streaming implementation.

I'll work on this. In the mean time:

// Handshake takes care of key,
// You may need to chose a nonce.
uint8_t key        [32];
uint8_t nonce      [24];
arc4random_buf(key,   32);
arc4random_buf(nonce, 24);

// Init streaming context.
// Note the use of `crypto_aead_init_x()` to support random nonces.
crypto_aead_ctx ctx;
crypto_aead_init_x(&ctx, key, nonce);

// Streaming loop (one message at a time)
while (plaintext_available()) {
    // Get buffers
    uint8_t *text = plaintext_text();
    size_t size = plaintext_size();
    uint8_t mac[16];

    // Encrypt
    // Note how I overwrite the plaintext
    crypto_aead_write(&ctx, text, mac, NULL, 0, text, size);

    // Send
    send(socket, cipher_text, text_size, flags);
    send(socket, mac, 16, flags);
}

// Wipe sensitive info
crypto_wipe(key, 32);
crypto_wipe(&ctx, sizeof(ctx));

The nonce is already sent in the handshake, and from how I read it, we only need to send that once?

That would depend on your handshake:


Hope this clears things up. I'll keep this issue open until I clarify the documentation.

TrueBrain commented 5 months ago

Thank you so much! Exactly the answers we were looking for :)

And thank you for the example, this is lovely!