From: Loup Vaillant Date: Sun, 24 Nov 2019 20:35:33 +0000 (+0100) Subject: Removed AEAD streaming interface. BREAKS COMPATIBILITY X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=5fb2f387d928fa7152d5c7c7fa1f1961cf8281c1;p=Monocypher.git Removed AEAD streaming interface. BREAKS COMPATIBILITY The streaming interface for AEAD was a bad idea: it's harder to test and encourages unsafe protocol design (unsafe handling of unauthenticated data, denial of service amplification...). Its rightful place is the trash bin. --- diff --git a/makefile b/makefile index a15842a..531dea0 100644 --- a/makefile +++ b/makefile @@ -97,9 +97,11 @@ lib/libmonocypher.so: lib/$(SONAME) lib/$(SONAME): lib/monocypher.o $(LINK_SHA512) @mkdir -p $(@D) $(CC) $(CFLAGS) -shared -Wl,-soname,$(SONAME) -o $@ $^ -lib/sha512.o : src/optional/sha512.c src/optional/sha512.h +lib/sha512.o : src/optional/sha512.c src/optional/sha512.h +lib/chacha20.o : src/deprecated/chacha20.c src/deprecated/chacha20.h +lib/aead-incr.o : src/deprecated/aead-incr.c src/deprecated/aead-incr.h lib/monocypher.o: src/monocypher.c src/monocypher.h -lib/monocypher.o lib/sha512.o: +lib/monocypher.o lib/sha512.o lib/chacha20.o lib/aead-incr.o: @mkdir -p $(@D) $(CC) $(CFLAGS) -I src -I src/optional -fPIC -c -o $@ $< @@ -107,7 +109,7 @@ lib/monocypher.o lib/sha512.o: TEST_COMMON = tests/utils.h src/monocypher.h src/optional/sha512.h SPEED = tests/speed lib/utils.o :tests/utils.c -lib/test.o :tests/test.c $(TEST_COMMON) tests/vectors.h +lib/test.o :tests/test.c $(TEST_COMMON) tests/vectors.h src/deprecated/chacha20.h lib/speed.o :$(SPEED)/speed.c $(TEST_COMMON) $(SPEED)/speed.h lib/speed-tweetnacl.o:$(SPEED)/speed-tweetnacl.c $(TEST_COMMON) $(SPEED)/speed.h lib/utils.o lib/test.o lib/speed.o lib/speed-tweetnacl.o: @@ -154,7 +156,7 @@ lib/speed-c25519.o:$(SPEED)/speed-c25519.c \ # test & speed executables -test.out : lib/test.o lib/utils.o lib/monocypher.o lib/sha512.o +test.out : lib/test.o lib/utils.o lib/monocypher.o lib/sha512.o lib/chacha20.o lib/aead-incr.o speed.out: lib/speed.o lib/utils.o lib/monocypher.o lib/sha512.o test.out speed.out: $(CC) $(CFLAGS) -I src -I src/optional -o $@ $^ diff --git a/src/deprecated/aead-incr.c b/src/deprecated/aead-incr.c new file mode 100644 index 0000000..7efcf46 --- /dev/null +++ b/src/deprecated/aead-incr.c @@ -0,0 +1,134 @@ +// Deprecated incremental API for authenticated encryption +// +// This file *temporarily* provides compatibility with Monocypher 2.x. +// Do not rely on its continued existence. +// +// Deprecated in : 3.0.0 +// Will be removed in: 4.0.0 +// +// Deprecated functions & types: +// crypto_unlock_ctx +// crypto_lock_ctx +// crypto_lock_init +// crypto_lock_auth_ad +// crypto_lock_auth_message +// crypto_lock_update +// crypto_lock_final +// crypto_unlock_init +// crypto_unlock_auth_ad +// crypto_unlock_auth_message +// crypto_unlock_update +// crypto_unlock_final +// +// For existing deployments that can no longer be updated or modified, +// use the 2.x family, which will receive security updates until 2024. +// +// upgrade strategy: +// Change your protocol in a way that it does not rely on the removed +// functions, namely by splitting the file into chunks you each use the +// crypto_lock() and crypto_unlock() functions on. +// +// For files, you may alternatively (and suboptimally) attempt to +// mmap()/MapViewOfFile() and pass the files as mapped memory into +// crypto_lock() and crypto_unlock() this way instead. + +#include "aead-incr.h" + +#define FOR_T(type, i, start, end) for (type i = (start); i < (end); i++) +#define FOR(i, start, end) FOR_T(size_t, i, start, end) +#define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx))) +#define WIPE_BUFFER(buffer) crypto_wipe(buffer, sizeof(buffer)) +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) +#define MAX(a, b) ((a) >= (b) ? (a) : (b)) +#define ALIGN(x, block_size) ((~(x) + 1) & ((block_size) - 1)) +typedef int8_t i8; +typedef uint8_t u8; +typedef int16_t i16; +typedef uint32_t u32; +typedef int32_t i32; +typedef int64_t i64; +typedef uint64_t u64; + +static const u8 zero[16] = {0}; + +static void store64_le(u8 out[8], u64 in) +{ + out[0] = in & 0xff; + out[1] = (in >> 8) & 0xff; + out[2] = (in >> 16) & 0xff; + out[3] = (in >> 24) & 0xff; + out[4] = (in >> 32) & 0xff; + out[5] = (in >> 40) & 0xff; + out[6] = (in >> 48) & 0xff; + out[7] = (in >> 56) & 0xff; +} + +static void lock_ad_padding(crypto_lock_ctx *ctx) +{ + if (ctx->ad_phase) { + ctx->ad_phase = 0; + crypto_poly1305_update(&ctx->poly, zero, ALIGN(ctx->ad_size, 16)); + } +} + +void crypto_lock_init(crypto_lock_ctx *ctx, + const u8 key[32], const u8 nonce[24]) +{ + u8 auth_key[64]; // "Wasting" the whole Chacha block is faster + ctx->ad_phase = 1; + ctx->ad_size = 0; + ctx->message_size = 0; + crypto_chacha20_x_init(&ctx->chacha, key, nonce); + crypto_chacha20_stream(&ctx->chacha, auth_key, 64); + crypto_poly1305_init (&ctx->poly , auth_key); + WIPE_BUFFER(auth_key); +} + +void crypto_lock_auth_ad(crypto_lock_ctx *ctx, const u8 *msg, size_t msg_size) +{ + crypto_poly1305_update(&ctx->poly, msg, msg_size); + ctx->ad_size += msg_size; +} + +void crypto_lock_auth_message(crypto_lock_ctx *ctx, + const u8 *cipher_text, size_t text_size) +{ + lock_ad_padding(ctx); + ctx->message_size += text_size; + crypto_poly1305_update(&ctx->poly, cipher_text, text_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_lock_auth_message(ctx, cipher_text, text_size); +} + +void crypto_lock_final(crypto_lock_ctx *ctx, u8 mac[16]) +{ + lock_ad_padding(ctx); + u8 sizes[16]; // Not secret, not wiped + store64_le(sizes + 0, ctx->ad_size); + store64_le(sizes + 8, ctx->message_size); + crypto_poly1305_update(&ctx->poly, zero, ALIGN(ctx->message_size, 16)); + crypto_poly1305_update(&ctx->poly, sizes, 16); + crypto_poly1305_final (&ctx->poly, mac); + WIPE_CTX(ctx); +} + +void crypto_unlock_update(crypto_lock_ctx *ctx, u8 *plain_text, + const u8 *cipher_text, size_t text_size) +{ + crypto_unlock_auth_message(ctx, 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_lock_final(ctx, real_mac); + int mismatch = crypto_verify16(real_mac, mac); + WIPE_BUFFER(real_mac); + return mismatch; +} diff --git a/src/deprecated/aead-incr.h b/src/deprecated/aead-incr.h new file mode 100644 index 0000000..3ace56c --- /dev/null +++ b/src/deprecated/aead-incr.h @@ -0,0 +1,77 @@ +// Deprecated incremental API for authenticated encryption +// +// This file *temporarily* provides compatibility with Monocypher 2.x. +// Do not rely on its continued existence. +// +// Deprecated in : 3.0.0 +// Will be removed in: 4.0.0 +// +// Deprecated functions & types: +// crypto_unlock_ctx +// crypto_lock_ctx +// crypto_lock_init +// crypto_lock_auth_ad +// crypto_lock_auth_message +// crypto_lock_update +// crypto_lock_final +// crypto_unlock_init +// crypto_unlock_auth_ad +// crypto_unlock_auth_message +// crypto_unlock_update +// crypto_unlock_final +// +// For existing deployments that can no longer be updated or modified, +// use the 2.x family, which will receive security updates until 2024. +// +// upgrade strategy: +// Change your protocol in a way that it does not rely on the removed +// functions, namely by splitting the file into chunks you each use the +// crypto_lock() and crypto_unlock() functions on. +// +// For files, you may alternatively (and suboptimally) attempt to +// mmap()/MapViewOfFile() and pass the files as mapped memory into +// crypto_lock() and crypto_unlock() this way instead. + +#ifndef AEAD_INCR_H +#define AEAD_INCR_H + +#include +#include +#include "monocypher.h" +#include "deprecated/chacha20.h" + +typedef struct { + crypto_chacha_ctx chacha; + crypto_poly1305_ctx poly; + uint64_t ad_size; + uint64_t message_size; + int ad_phase; +} crypto_lock_ctx; +#define crypto_unlock_ctx crypto_lock_ctx + +// Encryption +void crypto_lock_init(crypto_lock_ctx *ctx, + const uint8_t key[32], + const uint8_t nonce[24]); +void crypto_lock_auth_ad(crypto_lock_ctx *ctx, + const uint8_t *message, + size_t message_size); +void crypto_lock_auth_message(crypto_lock_ctx *ctx, + const uint8_t *cipher_text, size_t text_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]); + +// Decryption +#define crypto_unlock_init crypto_lock_init +#define crypto_unlock_auth_ad crypto_lock_auth_ad +#define crypto_unlock_auth_message crypto_lock_auth_message +void crypto_unlock_update(crypto_unlock_ctx *ctx, + uint8_t *plain_text, + const uint8_t *cipher_text, + size_t text_size); +int crypto_unlock_final(crypto_unlock_ctx *ctx, const uint8_t mac[16]); + +#endif // AEAD_INCR_H diff --git a/src/deprecated/chacha20.c b/src/deprecated/chacha20.c new file mode 100644 index 0000000..72416cc --- /dev/null +++ b/src/deprecated/chacha20.c @@ -0,0 +1,95 @@ +// Deprecated incremental API for Chacha20 +// +// This file *temporarily* provides compatibility with Monocypher 2.x. +// Do not rely on its continued existence. +// +// Deprecated in : 3.0.0 +// Will be removed in: 4.0.0 +// +// Deprecated functions & types: +// crypto_chacha_ctx +// crypto_chacha20_H +// crypto_chacha20_init +// crypto_chacha20_x_init +// crypto_chacha20_set_ctr +// crypto_chacha20_encrypt +// crypto_chacha20_stream +// +// For existing deployments that can no longer be updated or modified, +// use the 2.x family, which will receive security updates until 2024. +// +// Upgrade strategy: +// The new 3.x API can emulate incremental capabilities by setting a +// custom counter. Make sure you authenticate each chunk before you +// decrypt them, though. + +#include "chacha20.h" +#include "monocypher.h" + +#define FOR_T(type, i, start, end) for (type i = (start); i < (end); i++) +#define FOR(i, start, end) FOR_T(size_t, i, start, end) +#define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx))) +#define WIPE_BUFFER(buffer) crypto_wipe(buffer, sizeof(buffer)) +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) +#define MAX(a, b) ((a) >= (b) ? (a) : (b)) +#define ALIGN(x, block_size) ((~(x) + 1) & ((block_size) - 1)) +typedef int8_t i8; +typedef uint8_t u8; +typedef int16_t i16; +typedef uint32_t u32; +typedef int32_t i32; +typedef int64_t i64; +typedef uint64_t u64; + +void crypto_chacha20_H(u8 out[32], const u8 key[32], const u8 in[16]) +{ + crypto_hchacha20(out, key, in); +} + +void crypto_chacha20_init(crypto_chacha_ctx *ctx, + const u8 key[32], const u8 nonce[8]) +{ + FOR (i, 0, 32) { ctx->key [i] = key [i]; } + FOR (i, 0, 8) { ctx->nonce[i] = nonce[i]; } + crypto_chacha20_set_ctr(ctx, 0); +} + +void crypto_chacha20_x_init(crypto_chacha_ctx *ctx, + const u8 key[32], const u8 nonce[24]) +{ + crypto_hchacha20(ctx->key, key, nonce); + FOR (i, 0, 8) { ctx->nonce[i] = nonce[i + 16]; } + crypto_chacha20_set_ctr(ctx, 0); +} + +void crypto_chacha20_set_ctr(crypto_chacha_ctx *ctx, u64 ctr) +{ + ctx->ctr = ctr; + ctx->pool_idx = 64; // The random pool (re)starts empty +} + +void crypto_chacha20_encrypt(crypto_chacha_ctx *ctx, u8 *cipher_text, + const u8 *plain_text, size_t text_size) +{ + FOR (i, 0, text_size) { + if (ctx->pool_idx == 64) { + crypto_chacha20_ctr(ctx->pool, 0, 64, + ctx->key, ctx-> nonce, ctx->ctr); + ctx->pool_idx = 0; + ctx->ctr++; + } + u8 plain = 0; + if (plain_text != 0) { + plain = *plain_text; + plain_text++; + } + *cipher_text = ctx->pool[ctx->pool_idx] ^ plain; + ctx->pool_idx++; + cipher_text++; + } +} + +void crypto_chacha20_stream(crypto_chacha_ctx *ctx, u8 *stream, size_t size) +{ + crypto_chacha20_encrypt(ctx, stream, 0, size); +} diff --git a/src/deprecated/chacha20.h b/src/deprecated/chacha20.h new file mode 100644 index 0000000..fc7c539 --- /dev/null +++ b/src/deprecated/chacha20.h @@ -0,0 +1,68 @@ +// Deprecated incremental API for Chacha20 +// +// This file *temporarily* provides compatibility with Monocypher 2.x. +// Do not rely on its continued existence. +// +// Deprecated in : 3.0.0 +// Will be removed in: 4.0.0 +// +// Deprecated functions & types: +// crypto_chacha_ctx +// crypto_chacha20_H +// crypto_chacha20_init +// crypto_chacha20_x_init +// crypto_chacha20_set_ctr +// crypto_chacha20_encrypt +// crypto_chacha20_stream +// +// For existing deployments that can no longer be updated or modified, +// use the 2.x family, which will receive security updates until 2024. +// +// Upgrade strategy: +// The new 3.x API can emulate incremental capabilities by setting a +// custom counter. Make sure you authenticate each chunk before you +// decrypt them, though. + +#ifndef CHACHA20_H +#define CHACHA20_H + +#include +#include + +// Chacha20 +typedef struct { + uint8_t key[32]; + uint8_t nonce[8]; + uint64_t ctr; + uint8_t pool[64]; + size_t pool_idx; +} crypto_chacha_ctx; + +// Chacha20 (old API) +// ------------------ + +// Specialised hash. +void crypto_chacha20_H(uint8_t out[32], + const uint8_t key[32], + const uint8_t in [16]); + +void crypto_chacha20_init(crypto_chacha_ctx *ctx, + const uint8_t key[32], + const uint8_t nonce[8]); + +void crypto_chacha20_x_init(crypto_chacha_ctx *ctx, + const uint8_t key[32], + const uint8_t nonce[24]); + +void crypto_chacha20_set_ctr(crypto_chacha_ctx *ctx, uint64_t ctr); + +void crypto_chacha20_encrypt(crypto_chacha_ctx *ctx, + uint8_t *cipher_text, + const uint8_t *plain_text, + size_t text_size); + +void crypto_chacha20_stream(crypto_chacha_ctx *ctx, + uint8_t *stream, size_t size); + + +#endif // CHACHA20_H diff --git a/src/monocypher.c b/src/monocypher.c index a3c7656..6b2f50a 100644 --- a/src/monocypher.c +++ b/src/monocypher.c @@ -139,148 +139,143 @@ static void chacha20_rounds(u32 out[16], const u32 in[16]) out[12] = t12; out[13] = t13; out[14] = t14; out[15] = t15; } -static void chacha20_init_key(crypto_chacha_ctx *ctx, const u8 key[32]) +void chacha20_init_key(u32 block[16], const u8 key[32]) { // constant - ctx->input[0] = load32_le((const u8*)"expa"); - ctx->input[1] = load32_le((const u8*)"nd 3"); - ctx->input[2] = load32_le((const u8*)"2-by"); - ctx->input[3] = load32_le((const u8*)"te k"); + block[0] = load32_le((const u8*)"expa"); + block[1] = load32_le((const u8*)"nd 3"); + block[2] = load32_le((const u8*)"2-by"); + block[3] = load32_le((const u8*)"te k"); // key FOR (i, 0, 8) { - ctx->input[i+4] = load32_le(key + i*4); + block[i+4] = load32_le(key + i*4); } } -static u8 chacha20_pool_byte(crypto_chacha_ctx *ctx) +void chacha20_fill_pool(u8 pool[64], u32 input[16]) { - u32 pool_word = ctx->pool[ctx->pool_idx >> 2]; - u8 pool_byte = (u8)(pool_word >> (8*(ctx->pool_idx & 3))); - ctx->pool_idx++; - return pool_byte; -} - -// Fill the pool if needed, update the counters -static void chacha20_refill_pool(crypto_chacha_ctx *ctx) -{ - chacha20_rounds(ctx->pool, ctx->input); + u32 tmp[16]; + chacha20_rounds(tmp, input); FOR (j, 0, 16) { - ctx->pool[j] += ctx->input[j]; + tmp[j] += input[j]; + } + input[12]++; + if (input[12] == 0) { + input[13]++; } - ctx->pool_idx = 0; - ctx->input[12]++; - if (ctx->input[12] == 0) { - ctx->input[13]++; + FOR (i, 0, 16) { + store32_le(pool + i*4, tmp[i]); } } -void crypto_chacha20_H(u8 out[32], const u8 key[32], const u8 in[16]) +void crypto_hchacha20(u8 out[32], const u8 key[32], const u8 in [16]) { - crypto_chacha_ctx ctx; - chacha20_init_key(&ctx, key); + u32 block[16]; + chacha20_init_key(block, key); + // input FOR (i, 0, 4) { - ctx.input[i+12] = load32_le(in + i*4); + block[i+12] = load32_le(in + i*4); } - u32 buffer[16]; - chacha20_rounds(buffer, ctx.input); + chacha20_rounds(block, block); // prevents reversal of the rounds by revealing only half of the buffer. FOR (i, 0, 4) { - store32_le(out + i*4, buffer[i ]); // constant - store32_le(out + 16 + i*4, buffer[i + 12]); // counter and nonce + store32_le(out + i*4, block[i ]); // constant + store32_le(out + 16 + i*4, block[i + 12]); // counter and nonce } - WIPE_CTX(&ctx); - WIPE_BUFFER(buffer); + WIPE_BUFFER(block); } -static void chacha20_encrypt(crypto_chacha_ctx *ctx, - u8 *cipher_text, - const u8 *plain_text, - size_t text_size) +void chacha20_core(u32 input[16], u8 *cipher_text, const u8 *plain_text, + size_t text_size) { - FOR (i, 0, text_size) { - if (ctx->pool_idx == 64) { - chacha20_refill_pool(ctx); + u8 pool[64]; + while (text_size >= 64) { + chacha20_fill_pool(pool, input); + // TODO: there must be cleaner, faster ways to do this. + if (plain_text != 0) { + FOR (i, 0, 64) { + cipher_text[i] = pool[i] ^ plain_text[i]; + } + plain_text += 64; + } else { + FOR (i, 0, 64) { + cipher_text[i] = pool[i]; + } } - u8 plain = 0; + cipher_text += 64; + text_size -= 64; + } + if (text_size > 0) { + chacha20_fill_pool(pool, input); + // TODO: there must be cleaner, faster ways to do this. if (plain_text != 0) { - plain = *plain_text; - plain_text++; + FOR (i, 0, text_size) { + cipher_text[i] = pool[i] ^ plain_text[i]; + } + } else { + FOR (i, 0, text_size) { + cipher_text[i] = pool[i]; + } } - *cipher_text = chacha20_pool_byte(ctx) ^ plain; - cipher_text++; } + WIPE_BUFFER(pool); } -void crypto_chacha20_init(crypto_chacha_ctx *ctx, - const u8 key[32], - const u8 nonce[8]) +void crypto_chacha20_ctr(u8 *cipher_text, const u8 *plain_text, + size_t text_size, const u8 key[32], const u8 nonce[8], + u64 ctr) { - chacha20_init_key (ctx, key); // key - crypto_chacha20_set_ctr(ctx, 0 ); // counter - ctx->input[14] = load32_le(nonce + 0); // nonce - ctx->input[15] = load32_le(nonce + 4); // nonce + u32 input[16]; + chacha20_init_key(input, key); + input[12] = (u32) ctr; + input[13] = (u32)(ctr >> 32); + input[14] = load32_le(nonce); + input[15] = load32_le(nonce + 4); + chacha20_core(input, cipher_text, plain_text, text_size); + WIPE_BUFFER(input); } -void crypto_chacha20_x_init(crypto_chacha_ctx *ctx, - const u8 key[32], - const u8 nonce[24]) +void crypto_ietf_chacha20_ctr(u8 *cipher_text, const u8 *plain_text, + size_t text_size, + const u8 key[32], const u8 nonce[12], u32 ctr) { - u8 derived_key[32]; - crypto_chacha20_H(derived_key, key, nonce); - crypto_chacha20_init(ctx, derived_key, nonce + 16); - WIPE_BUFFER(derived_key); + u32 input[16]; + chacha20_init_key(input, key); + input[12] = (u32) ctr; + input[13] = load32_le(nonce); + input[14] = load32_le(nonce + 4); + input[15] = load32_le(nonce + 8); + chacha20_core(input, cipher_text, plain_text, text_size); + WIPE_BUFFER(input); } -void crypto_chacha20_set_ctr(crypto_chacha_ctx *ctx, u64 ctr) +void crypto_xchacha20_ctr(u8 *cipher_text, const u8 *plain_text, + size_t text_size, + const u8 key[32], const u8 nonce[24], u64 ctr) { - ctx->input[12] = ctr & 0xffffffff; - ctx->input[13] = ctr >> 32; - ctx->pool_idx = 64; // The random pool (re)starts empty + u8 sub_key[32]; + crypto_hchacha20(sub_key, key, nonce); + crypto_chacha20_ctr(cipher_text, plain_text, text_size, key, nonce+16, ctr); } -void crypto_chacha20_encrypt(crypto_chacha_ctx *ctx, - u8 *cipher_text, - const u8 *plain_text, - size_t text_size) +void crypto_chacha20(u8 *cipher_text, const u8 *plain_text, size_t text_size, + const u8 key[32], const u8 nonce[8]) { - // Align ourselves with block boundaries - size_t align = MIN(ALIGN(ctx->pool_idx, 64), text_size); - chacha20_encrypt(ctx, cipher_text, plain_text, align); - if (plain_text != 0) { - plain_text += align; - } - cipher_text += align; - text_size -= align; - - // Process the message block by block - FOR (i, 0, text_size >> 6) { // number of blocks - chacha20_refill_pool(ctx); - if (plain_text != 0) { - FOR (j, 0, 16) { - u32 plain = load32_le(plain_text); - store32_le(cipher_text, ctx->pool[j] ^ plain); - plain_text += 4; - cipher_text += 4; - } - } else { - FOR (j, 0, 16) { - store32_le(cipher_text, ctx->pool[j]); - cipher_text += 4; - } - } - ctx->pool_idx = 64; - } - text_size &= 63; + crypto_chacha20_ctr(cipher_text, plain_text, text_size, key, nonce, 0); - // remaining bytes - chacha20_encrypt(ctx, cipher_text, plain_text, text_size); } - -void crypto_chacha20_stream(crypto_chacha_ctx *ctx, u8 *stream, size_t size) +void crypto_ietf_chacha20(u8 *cipher_text, const u8 *plain_text, + size_t text_size, + const u8 key[32], const u8 nonce[12]) { - crypto_chacha20_encrypt(ctx, stream, 0, size); + crypto_ietf_chacha20_ctr(cipher_text, plain_text, text_size, key, nonce, 0); } +void crypto_xchacha20(u8 *cipher_text, const u8 *plain_text, size_t text_size, + const u8 key[32], const u8 nonce[24]) +{ + crypto_xchacha20_ctr(cipher_text, plain_text, text_size, key, nonce, 0); +} ///////////////// /// Poly 1305 /// @@ -2061,81 +2056,28 @@ int crypto_key_exchange(u8 shared_key[32], const u8 their_public_key[32]) { int status = crypto_x25519(shared_key, your_secret_key, their_public_key); - crypto_chacha20_H(shared_key, shared_key, zero); + crypto_hchacha20(shared_key, shared_key, zero); return status; } //////////////////////////////// /// Authenticated encryption /// //////////////////////////////// -static void lock_ad_padding(crypto_lock_ctx *ctx) -{ - if (ctx->ad_phase) { - ctx->ad_phase = 0; - crypto_poly1305_update(&ctx->poly, zero, ALIGN(ctx->ad_size, 16)); - } -} - -void crypto_lock_init(crypto_lock_ctx *ctx, - const u8 key[32], const u8 nonce[24]) -{ - u8 auth_key[64]; // "Wasting" the whole Chacha block is faster - ctx->ad_phase = 1; - ctx->ad_size = 0; - ctx->message_size = 0; - crypto_chacha20_x_init(&ctx->chacha, key, nonce); - crypto_chacha20_stream(&ctx->chacha, auth_key, 64); - crypto_poly1305_init (&ctx->poly , auth_key); - WIPE_BUFFER(auth_key); -} - -void crypto_lock_auth_ad(crypto_lock_ctx *ctx, const u8 *msg, size_t msg_size) -{ - crypto_poly1305_update(&ctx->poly, msg, msg_size); - ctx->ad_size += msg_size; -} - -void crypto_lock_auth_message(crypto_lock_ctx *ctx, - const u8 *cipher_text, size_t text_size) -{ - lock_ad_padding(ctx); - ctx->message_size += text_size; - crypto_poly1305_update(&ctx->poly, cipher_text, text_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_lock_auth_message(ctx, cipher_text, text_size); -} - -void crypto_lock_final(crypto_lock_ctx *ctx, u8 mac[16]) +static void lock_auth(u8 mac[16], const u8 auth_key[32], + const u8 *ad , size_t ad_size, + const u8 *cipher_text, size_t text_size) { - lock_ad_padding(ctx); u8 sizes[16]; // Not secret, not wiped - store64_le(sizes + 0, ctx->ad_size); - store64_le(sizes + 8, ctx->message_size); - crypto_poly1305_update(&ctx->poly, zero, ALIGN(ctx->message_size, 16)); - crypto_poly1305_update(&ctx->poly, sizes, 16); - crypto_poly1305_final (&ctx->poly, mac); - WIPE_CTX(ctx); -} - -void crypto_unlock_update(crypto_lock_ctx *ctx, u8 *plain_text, - const u8 *cipher_text, size_t text_size) -{ - crypto_unlock_auth_message(ctx, 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_lock_final(ctx, real_mac); - int mismatch = crypto_verify16(real_mac, mac); - WIPE_BUFFER(real_mac); - return mismatch; + store64_le(sizes + 0, ad_size); + store64_le(sizes + 8, text_size); + crypto_poly1305_ctx poly_ctx; // auto wiped... + crypto_poly1305_init (&poly_ctx, auth_key); + crypto_poly1305_update(&poly_ctx, ad , ad_size); + crypto_poly1305_update(&poly_ctx, zero , ALIGN(ad_size, 16)); + crypto_poly1305_update(&poly_ctx, cipher_text, text_size); + crypto_poly1305_update(&poly_ctx, zero , ALIGN(text_size, 16)); + crypto_poly1305_update(&poly_ctx, sizes , 16); + crypto_poly1305_final (&poly_ctx, mac); // ...here } void crypto_lock_aead(u8 mac[16], @@ -2145,11 +2087,15 @@ void crypto_lock_aead(u8 mac[16], const u8 *ad , size_t ad_size, const u8 *plain_text, size_t text_size) { - crypto_lock_ctx ctx; - crypto_lock_init (&ctx, key, nonce); - crypto_lock_auth_ad(&ctx, ad, ad_size); - crypto_lock_update (&ctx, cipher_text, plain_text, text_size); - crypto_lock_final (&ctx, mac); + u8 sub_key[32]; + u8 auth_key[64]; // "Wasting" the whole Chacha block is faster + crypto_hchacha20(sub_key, key, nonce); + crypto_chacha20(auth_key, 0, 64, sub_key, nonce + 16); + crypto_chacha20_ctr(cipher_text, plain_text, text_size, + sub_key, nonce + 16, 1); + lock_auth(mac, auth_key, ad, ad_size, cipher_text, text_size); + WIPE_BUFFER(sub_key); + WIPE_BUFFER(auth_key); } int crypto_unlock_aead(u8 *plain_text, @@ -2159,17 +2105,20 @@ int crypto_unlock_aead(u8 *plain_text, const u8 *ad , size_t ad_size, const u8 *cipher_text, size_t text_size) { - crypto_unlock_ctx ctx; - crypto_unlock_init (&ctx, key, nonce); - crypto_unlock_auth_ad (&ctx, ad, ad_size); - crypto_unlock_auth_message(&ctx, cipher_text, text_size); - crypto_chacha_ctx chacha_ctx = ctx.chacha; // avoid the wiping... - if (crypto_unlock_final(&ctx, mac)) { // ...that occurs here - WIPE_CTX(&chacha_ctx); - return -1; // reject forgeries before wasting our time decrypting + u8 sub_key[32]; + u8 auth_key[64]; // "Wasting" the whole Chacha block is faster + crypto_hchacha20(sub_key, key, nonce); + crypto_chacha20(auth_key, 0, 64, sub_key, nonce + 16); + u8 real_mac[16]; + lock_auth(real_mac, auth_key, ad, ad_size, cipher_text, text_size); + WIPE_BUFFER(auth_key); + if (crypto_verify16(mac, real_mac)) { + WIPE_BUFFER(sub_key); + return -1; } - crypto_chacha20_encrypt(&chacha_ctx, plain_text, cipher_text, text_size); - WIPE_CTX(&chacha_ctx); + crypto_chacha20_ctr(plain_text, cipher_text, text_size, + sub_key, nonce + 16, 1); + WIPE_BUFFER(sub_key); return 0; } diff --git a/src/monocypher.h b/src/monocypher.h index c99561d..161520a 100644 --- a/src/monocypher.h +++ b/src/monocypher.h @@ -13,13 +13,6 @@ // Do not rely on the size or content on any of those types, // they may change without notice. -// Chacha20 -typedef struct { - uint32_t input[16]; // current input, unencrypted - uint32_t pool [16]; // last input, encrypted - size_t pool_idx; // pointer to random_pool -} crypto_chacha_ctx; - // Poly1305 typedef struct { uint32_t r[4]; // constant multiplier (from the secret key) @@ -29,16 +22,6 @@ typedef struct { size_t c_idx; // How many bytes are there in the chunk. } crypto_poly1305_ctx; -// Authenticated encryption -typedef struct { - crypto_chacha_ctx chacha; - crypto_poly1305_ctx poly; - uint64_t ad_size; - uint64_t message_size; - int ad_phase; -} crypto_lock_ctx; -#define crypto_unlock_ctx crypto_lock_ctx - // Hash (Blake2b) typedef struct { uint64_t hash[8]; @@ -114,31 +97,6 @@ int crypto_unlock_aead(uint8_t *plain_text, const uint8_t *ad , size_t ad_size, const uint8_t *cipher_text, size_t text_size); -// Incremental interface (encryption) -void crypto_lock_init(crypto_lock_ctx *ctx, - const uint8_t key[32], - const uint8_t nonce[24]); -void crypto_lock_auth_ad(crypto_lock_ctx *ctx, - const uint8_t *message, - size_t message_size); -void crypto_lock_auth_message(crypto_lock_ctx *ctx, - const uint8_t *cipher_text, size_t text_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]); - -// Incremental interface (decryption) -#define crypto_unlock_init crypto_lock_init -#define crypto_unlock_auth_ad crypto_lock_auth_ad -#define crypto_unlock_auth_message crypto_lock_auth_message -void crypto_unlock_update(crypto_unlock_ctx *ctx, - uint8_t *plain_text, - const uint8_t *cipher_text, - size_t text_size); -int crypto_unlock_final(crypto_unlock_ctx *ctx, const uint8_t mac[16]); - // General purpose hash (Blake2b) // ------------------------------ @@ -227,32 +185,47 @@ int crypto_check_final (crypto_check_ctx *ctx); // For experts only. You have been warned. - // Chacha20 // -------- // Specialised hash. -void crypto_chacha20_H(uint8_t out[32], - const uint8_t key[32], - const uint8_t in [16]); - -void crypto_chacha20_init(crypto_chacha_ctx *ctx, - const uint8_t key[32], - const uint8_t nonce[8]); - -void crypto_chacha20_x_init(crypto_chacha_ctx *ctx, - const uint8_t key[32], - const uint8_t nonce[24]); - -void crypto_chacha20_set_ctr(crypto_chacha_ctx *ctx, uint64_t ctr); - -void crypto_chacha20_encrypt(crypto_chacha_ctx *ctx, - uint8_t *cipher_text, - const uint8_t *plain_text, - size_t text_size); - -void crypto_chacha20_stream(crypto_chacha_ctx *ctx, - uint8_t *stream, size_t size); +void crypto_hchacha20(uint8_t out[32], + const uint8_t key[32], + const uint8_t in [16]); + +void crypto_chacha20(uint8_t *cipher_text, + const uint8_t *plain_text, + size_t text_size, + const uint8_t key[32], + const uint8_t nonce[8]); +void crypto_xchacha20(uint8_t *cipher_text, + const uint8_t *plain_text, + size_t text_size, + const uint8_t key[32], + const uint8_t nonce[24]); +void crypto_ietf_chacha20(uint8_t *cipher_text, + const uint8_t *plain_text, + size_t text_size, + const uint8_t key[32], + const uint8_t nonce[12]); +void crypto_chacha20_ctr(uint8_t *cipher_text, + const uint8_t *plain_text, + size_t text_size, + const uint8_t key[32], + const uint8_t nonce[8], + uint64_t ctr); +void crypto_xchacha20_ctr(uint8_t *cipher_text, + const uint8_t *plain_text, + size_t text_size, + const uint8_t key[32], + const uint8_t nonce[24], + uint64_t ctr); +void crypto_ietf_chacha20_ctr(uint8_t *cipher_text, + const uint8_t *plain_text, + size_t text_size, + const uint8_t key[32], + const uint8_t nonce[12], + uint32_t ctr); // Poly 1305 diff --git a/tests/speed/speed.c b/tests/speed/speed.c index 2a1d82f..913a953 100644 --- a/tests/speed/speed.c +++ b/tests/speed/speed.c @@ -11,9 +11,7 @@ static u64 chacha20(void) RANDOM_INPUT(nonce, 8); TIMING_START { - crypto_chacha_ctx ctx; - crypto_chacha20_init(&ctx, key, nonce); - crypto_chacha20_encrypt(&ctx, out, in, SIZE); + crypto_chacha20(out, in, SIZE, key, nonce); } TIMING_END; } diff --git a/tests/test.c b/tests/test.c index f2a6013..efe85bf 100644 --- a/tests/test.c +++ b/tests/test.c @@ -2,6 +2,8 @@ #include #include #include "monocypher.h" +#include "deprecated/chacha20.h" +#include "deprecated/aead-incr.h" #include "sha512.h" #include "utils.h" #include "vectors.h" @@ -21,10 +23,13 @@ static void chacha20(const vector in[], vector *out) const vector *nonce = in + 1; const vector *plain = in + 2; u64 ctr = load64_le(in[3].buf); - crypto_chacha_ctx ctx; - crypto_chacha20_init (&ctx, key->buf, nonce->buf); - crypto_chacha20_set_ctr(&ctx, ctr); - crypto_chacha20_encrypt(&ctx, out->buf, plain->buf, plain->size); + crypto_chacha20_ctr(out->buf, plain->buf, plain->size, + key->buf, nonce->buf, ctr); + + /* crypto_chacha_ctx ctx; */ + /* crypto_chacha20_init (&ctx, key->buf, nonce->buf); */ + /* crypto_chacha20_set_ctr(&ctx, ctr); */ + /* crypto_chacha20_encrypt(&ctx, out->buf, plain->buf, plain->size); */ } static void hchacha20(const vector in[], vector *out)