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 $@ $<
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:
# 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 $@ $^
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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 <stddef.h>
+#include <inttypes.h>
+#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
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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 <stddef.h>
+#include <inttypes.h>
+
+// 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
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 ///
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],
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,
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;
}
// 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)
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];
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)
// ------------------------------
// 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
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;
}
#include <stdlib.h>
#include <string.h>
#include "monocypher.h"
+#include "deprecated/chacha20.h"
+#include "deprecated/aead-incr.h"
#include "sha512.h"
#include "utils.h"
#include "vectors.h"
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)