From: Loup Vaillant Date: Sun, 1 Oct 2017 18:40:52 +0000 (+0200) Subject: Added incremental interface X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=ad92a9acf8631377cc3922faac5a78f506d0ab1b;p=Monocypher.git Added incremental interface Fixed #29 Bonus: we now can authenticate a message without decrypting it. --- diff --git a/doc/man/man3/crypto_lock.3monocypher b/doc/man/man3/crypto_lock.3monocypher index f048a3f..162ce70 100644 --- a/doc/man/man3/crypto_lock.3monocypher +++ b/doc/man/man3/crypto_lock.3monocypher @@ -25,6 +25,43 @@ .Fa "const uint8_t *cipher_text" .Fa "size_t text_size" .Fc +.Ft void +.Fo crypto_lock_init +.Fa "crypto_lock_ctx *ctx" +.Fa "const uint8_t key[32]" +.Fa "const uint8_t nonce[24]" +.Fc +.Ft void +.Fo crypto_lock_auth +.Fa crypto_lock_ctx *ctx +.Fa const uint8_t *ad +.Fa size_t ad_size +.Fc +.Ft void +.Fo crypto_lock_update +.Fa crypto_lock_ctx *ctx +.Fa uint8_t *cipher_text +.Fa const uint8_t *plain_text +.Fa size_t text_size +.Fc +.Ft void +.Fo crypto_lock_final +.Fa crypto_lock_ctx *ctx +.Fa uint8_t mac[16] +.Fc +.Ft void +.Fo crypto_unlock_update +.Fa crypto_lock_ctx *ctx +.Fa uint8_t *plain_text +.Fa const uint8_t *cipher_text +.Fa size_t text_size +.Fc +.Ft int +.Fo crypto_unlock_final +.Fa crypto_lock_ctx *ctx +.Fa const uint8_t mac[16] +.Fc +.F .Sh DESCRIPTION Encryption makes your messages unreadable to eavesdroppers. Authentication ascertain the origin and integrity of the messages you @@ -173,6 +210,88 @@ if (ret != 0) { */ } .Ed +.Sh INCREMENTAL INTERFACE +Useful for decrypting huge inputs. +This time, decryption is performed regardless of whether the message +is corrupted or not. +This may be relevant if you expect a high rate of corrupted messages. +.Pp +Encryption: +.Bd -literal -offset indent +/* Prepare the key, nonce, and input */ + +/* First, initialise the context */ +crypto_lock_ctx ctx; +crypto_lock_init(&ctx, key, nonce); + +/* Second, authenticate the additional data, if any. */ +crypto_lock_auth(&ctx, ad1, ad_size1); +crypto_lock_auth(&ctx, ad2, ad_size2); +crypto_lock_auth(&ctx, ad3, ad_size3); + +/* Third, encrypt the plain text */ +crypto_lock_update(&ctx, cipher1, plain1, text_size1); +crypto_lock_update(&ctx, cipher2, plain2, text_size2); +crypto_lock_update(&ctx, cipher3, plain2, text_size3); + +/* Finally, compute the authentication code */ +crypto_lock_final (&ctx, mac); +.Ed +.Pp +Make sure you authenticate the additional data before you begin the +encryption, or the mac won't be compatible with the direct interface. +.Pp +To decrypt the above: +.Bd -literal -offset indent +/* First, initialise the context. + * Use the key and nonce that were used for encryption. + */ +crypto_lock_ctx ctx; +crypto_lock_init(&ctx, key, nonce); + +/* Second, authenticate the additional data, if any. */ +crypto_lock_auth(&ctx, ad1, ad_size1); +crypto_lock_auth(&ctx, ad2, ad_size2); +crypto_lock_auth(&ctx, ad3, ad_size3); + +/* Third, decrypt the cipher text */ +crypto_unlock_update(&ctx, re_plain1, cipher1, text_size1); +crypto_unlock_update(&ctx, re_plain2, cipher2, text_size2); +crypto_unlock_update(&ctx, re_plain3, cipher3, text_size3); + +/* Finally, check the authentication code */ +if (crypto_unlock_final(&ctx, mac2)) { + /* Message corrupted. */ +} else { + /* Decryption went well. */ +} +.Ed +.Pp +To authenticate without decrypting at all: +.Bd -literal -offset indent +/* First, initialise the context. + * Use the key and nonce that were used for encryption. + */ +crypto_lock_ctx ctx; +crypto_lock_init(&ctx, key, nonce); + +/* Second, authenticate the additional data, if any. */ +crypto_lock_auth(&ctx, ad1, ad_size1); +crypto_lock_auth(&ctx, ad2, ad_size2); +crypto_lock_auth(&ctx, ad3, ad_size3); + +/* Third, authenticate the cipher text */ +crypto_lock_auth(&ctx, re_plain1, cipher1, text_size1); +crypto_lock_auth(&ctx, re_plain2, cipher2, text_size2); +crypto_lock_auth(&ctx, re_plain3, cipher3, text_size3); + +/* Finally, check the authentication code */ +if (crypto_unlock_final(&ctx, mac2)) { + /* Message corrupted. */ +} else { + /* Message authentic. */ +} +.Ed .Sh SEE ALSO .Xr crypto_aead_lock 3monocypher , .Xr crypto_aead_unlock 3monocypher , diff --git a/doc/man/man3/crypto_lock_auth.3monocypher b/doc/man/man3/crypto_lock_auth.3monocypher new file mode 120000 index 0000000..126507a --- /dev/null +++ b/doc/man/man3/crypto_lock_auth.3monocypher @@ -0,0 +1 @@ +crypto_lock.3monocypher \ No newline at end of file diff --git a/doc/man/man3/crypto_lock_final.3monocypher b/doc/man/man3/crypto_lock_final.3monocypher new file mode 120000 index 0000000..126507a --- /dev/null +++ b/doc/man/man3/crypto_lock_final.3monocypher @@ -0,0 +1 @@ +crypto_lock.3monocypher \ No newline at end of file diff --git a/doc/man/man3/crypto_lock_init.3monocypher b/doc/man/man3/crypto_lock_init.3monocypher new file mode 120000 index 0000000..126507a --- /dev/null +++ b/doc/man/man3/crypto_lock_init.3monocypher @@ -0,0 +1 @@ +crypto_lock.3monocypher \ No newline at end of file diff --git a/doc/man/man3/crypto_lock_update.3monocypher b/doc/man/man3/crypto_lock_update.3monocypher new file mode 120000 index 0000000..126507a --- /dev/null +++ b/doc/man/man3/crypto_lock_update.3monocypher @@ -0,0 +1 @@ +crypto_lock.3monocypher \ No newline at end of file diff --git a/doc/man/man3/crypto_unlock_final.3monocypher b/doc/man/man3/crypto_unlock_final.3monocypher new file mode 120000 index 0000000..126507a --- /dev/null +++ b/doc/man/man3/crypto_unlock_final.3monocypher @@ -0,0 +1 @@ +crypto_lock.3monocypher \ No newline at end of file diff --git a/doc/man/man3/crypto_unlock_update.3monocypher b/doc/man/man3/crypto_unlock_update.3monocypher new file mode 120000 index 0000000..126507a --- /dev/null +++ b/doc/man/man3/crypto_unlock_update.3monocypher @@ -0,0 +1 @@ +crypto_lock.3monocypher \ No newline at end of file diff --git a/src/monocypher.c b/src/monocypher.c index 140543c..cafaee6 100644 --- a/src/monocypher.c +++ b/src/monocypher.c @@ -1653,3 +1653,42 @@ int crypto_unlock(u8 *plain_text, return crypto_aead_unlock(plain_text, key, nonce, mac, 0, 0, cipher_text, text_size); } + +void crypto_lock_init(crypto_lock_ctx *ctx, const u8 key[32], const u8 nonce[24]) +{ + u8 auth_key[32]; + crypto_chacha20_x_init(&(ctx->chacha), key, nonce); + crypto_chacha20_stream(&(ctx->chacha), auth_key, 32); + crypto_poly1305_init (&(ctx->poly ), auth_key); +} + +void crypto_lock_auth(crypto_lock_ctx *ctx, const u8 *ad, size_t ad_size) +{ + crypto_poly1305_update(&(ctx->poly), ad, ad_size); +} + +void crypto_lock_update(crypto_lock_ctx *ctx, u8 *cipher_text, + const u8 *plain_text, size_t text_size) +{ + crypto_chacha20_encrypt(&(ctx->chacha), cipher_text, plain_text, text_size); + crypto_poly1305_update (&(ctx->poly ), cipher_text, text_size); +} + +void crypto_lock_final(crypto_lock_ctx *ctx, u8 mac[16]) +{ + crypto_poly1305_final (&(ctx->poly), mac); +} + +void crypto_unlock_update(crypto_lock_ctx *ctx, u8 *plain_text, + const u8 *cipher_text, size_t text_size) +{ + crypto_poly1305_update (&(ctx->poly ), cipher_text, text_size); + crypto_chacha20_encrypt(&(ctx->chacha), plain_text, cipher_text, text_size); +} + +int crypto_unlock_final(crypto_lock_ctx *ctx, const u8 mac[16]) +{ + u8 real_mac[16]; + crypto_poly1305_final(&(ctx->poly), real_mac); + return crypto_memcmp(real_mac, mac, 16); +} diff --git a/src/monocypher.h b/src/monocypher.h index 4d6eb66..9bcce73 100644 --- a/src/monocypher.h +++ b/src/monocypher.h @@ -175,4 +175,28 @@ int crypto_unlock(uint8_t *plain_text, const uint8_t mac[16], const uint8_t *cipher_text, size_t text_size); +typedef struct { + crypto_chacha_ctx chacha; + crypto_poly1305_ctx poly; +} crypto_lock_ctx; + +void crypto_lock_init(crypto_lock_ctx *ctx, + const uint8_t key[32], + const uint8_t nonce[24]); + +void crypto_lock_auth(crypto_lock_ctx *ctx, + const uint8_t *ad, size_t ad_size); + +void crypto_lock_update(crypto_lock_ctx *ctx, + uint8_t *cipher_text, + const uint8_t *plain_text, size_t text_size); + +void crypto_lock_final(crypto_lock_ctx *ctx, uint8_t mac[16]); + +void crypto_unlock_update(crypto_lock_ctx *ctx, + uint8_t *plain_text, + const uint8_t *cipher_text, size_t text_size); + +int crypto_unlock_final(crypto_lock_ctx *ctx, const uint8_t mac[16]); + #endif // MONOCYPHER_H diff --git a/tests/test.c b/tests/test.c index cf70cd7..03afeed 100644 --- a/tests/test.c +++ b/tests/test.c @@ -667,6 +667,71 @@ static int p_aead() return status; } +static int p_lock_incremental() +{ + int status = 0; + FOR (i, 0, 1000) { + RANDOM_INPUT(key , 32); + RANDOM_INPUT(nonce, 24); + RANDOM_INPUT(ad , 128); + RANDOM_INPUT(plain, 256); + // total sizes + size_t ad_size = rand64() % 128; + size_t text_size = rand64() % 256; + // incremental sizes + size_t ad_size1 = ad_size == 0 ? 0 : rand64() % ad_size; + size_t text_size1 = text_size == 0 ? 0 : rand64() % text_size; + size_t ad_size2 = ad_size - ad_size1; + size_t text_size2 = text_size - text_size1; + // incremental buffers + u8 *ad1 = ad; u8 *ad2 = ad + ad_size1; + u8 *plain1 = plain; u8 *plain2 = plain + text_size1; + + u8 mac1[16], cipher1[256]; + u8 mac2[16], cipher2[256]; + crypto_aead_lock(mac1, cipher1, key, nonce, + ad, ad_size, plain, text_size); + crypto_lock_ctx ctx; + crypto_lock_init (&ctx, key, nonce); + crypto_lock_auth (&ctx, ad1, ad_size1); // just to show ad also have + crypto_lock_auth (&ctx, ad2, ad_size2); // an incremental interface + crypto_lock_update(&ctx, cipher2 , plain1, text_size1); + crypto_lock_update(&ctx, cipher2 + text_size1, plain2, text_size2); + crypto_lock_final (&ctx, mac2); + status |= crypto_memcmp(mac1 , mac2 , 16 ); + status |= crypto_memcmp(cipher1, cipher2, text_size); + + // Now test the round trip. + u8 re_plain1[256]; + u8 re_plain2[256]; + status |= crypto_aead_unlock(re_plain1, key, nonce, mac1, + ad, ad_size, cipher1, text_size); + crypto_lock_init (&ctx, key, nonce); + crypto_lock_auth (&ctx, ad, ad_size); + crypto_unlock_update(&ctx, re_plain2, cipher2, text_size); + status |= crypto_unlock_final(&ctx, mac2); + status |= crypto_memcmp(mac1 , mac2 , 16 ); + status |= crypto_memcmp(plain, re_plain1, text_size); + status |= crypto_memcmp(plain, re_plain2, text_size); + + // Test authentication without decryption + crypto_lock_init(&ctx, key, nonce); + crypto_lock_auth(&ctx, ad , ad_size ); + crypto_lock_auth(&ctx, cipher2, text_size); + status |= crypto_unlock_final(&ctx, mac2); + // The same, except we're supposed to reject forgeries + if (text_size > 0) { + cipher2[0]++; // forgery attempt + crypto_lock_init(&ctx, key, nonce); + crypto_lock_auth(&ctx, ad , ad_size ); + crypto_lock_auth(&ctx, cipher2, text_size); + status |= !crypto_unlock_final(&ctx, mac2); + } + } + printf("%s: aead (incremental)\n", status != 0 ? "FAILED" : "OK"); + return status; +} + int main(void) { int status = 0; @@ -698,11 +763,11 @@ int main(void) status |= p_eddsa(); status |= p_eddsa_overlap(); status |= p_aead(); - + status |= p_lock_incremental(); printf("\nConstant time tests"); printf("\n-------------------\n"); status |= test_cmp(); - printf("\n"); + printf("\n%s\n\n", status != 0 ? "SOME TESTS FAILED" : "All tests OK!"); return status; }