#include "chacha20.h"
-/////////////////
-/// Utilities ///
-/////////////////
-
static uint32_t
load32_le(const uint8_t s[4])
{
output[3] = (input >> 24) & 0xff;
}
-////////////
-/// Core ///
-////////////
-
static void
chacha20_rounds(uint32_t out[16], const uint32_t in[16])
{
}
}
-//////////////////////////////
-/// Context initialization ///
-//////////////////////////////
static void
-init_constant(crypto_chacha_ctx *ctx)
+chacha20_init_key(crypto_chacha_ctx *ctx, const uint8_t key[32])
{
+ // constant
ctx->input[0] = load32_le((uint8_t*)"expa");
ctx->input[1] = load32_le((uint8_t*)"nd 3");
ctx->input[2] = load32_le((uint8_t*)"2-by");
ctx->input[3] = load32_le((uint8_t*)"te k");
- ctx->pool_index = 64; // the random pool starts empty
-}
-
-static void
-init_key(crypto_chacha_ctx *ctx, const uint8_t key[32])
-{
+ // key
for (int i = 0; i < 8; i++)
ctx->input[i + 4] = load32_le(key + i*4);
+ // pool index (the random pool starts empty)
+ ctx->pool_index = 64;
}
-static void
-init_nonce(crypto_chacha_ctx *ctx, const uint8_t nonce[8])
+void
+crypto_chacha20_H(uint8_t out[32],
+ const uint8_t key[32],
+ const uint8_t in [16])
{
- ctx->input[12] = 0; // counter
- ctx->input[13] = 0; // counter
- ctx->input[14] = load32_le(nonce + 0);
- ctx->input[15] = load32_le(nonce + 4);
+ crypto_chacha_ctx ctx;
+ chacha20_init_key(&ctx, key);
+ for (int i = 0; i < 4; i++)
+ ctx.input[i + 12] = load32_le(in + i*4);
+
+ uint32_t buffer[16];
+ chacha20_rounds(buffer, ctx.input);
+ // prevents reversal of the rounds by revealing only half of the buffer.
+ for (int i = 0; i < 4; i++) {
+ store32_le(out + i*4, buffer[i ]); // constant
+ store32_le(out + 16 + i*4, buffer[i + 12]); // counter and nonce
+ }
}
-///////////////////
-/// Exposed API ///
-///////////////////
void
crypto_chacha20_init(crypto_chacha_ctx *ctx,
const uint8_t key[32],
const uint8_t nonce[8])
{
- init_constant(ctx );
- init_key (ctx, key );
- init_nonce (ctx, nonce);
+ chacha20_init_key(ctx, key ); // key
+ ctx->input[12] = 0; // counter
+ ctx->input[13] = 0; // counter
+ ctx->input[14] = load32_le(nonce + 0); // nonce
+ ctx->input[15] = load32_le(nonce + 4); // nonce
}
void
const uint8_t key[32],
const uint8_t nonce[24])
{
- crypto_chacha_ctx init_ctx;
- init_constant (&init_ctx );
- init_key (&init_ctx, key);
- // init big nonce (first 16 bytes)
- for (int i = 0; i < 4; i++)
- init_ctx.input[i + 12] = load32_le(nonce + i*4);
-
- // chacha20 rounds (reversible if we reveal all the buffer)
- uint32_t buffer[16];
- chacha20_rounds(buffer, init_ctx.input);
-
- init_constant(ctx);
- // init key
- for (int i = 0; i < 4; i++) {
- ctx->input[i + 4] = buffer[i ]; // constant
- ctx->input[i + 8] = buffer[i + 12]; // counter and nonce
- }
- init_nonce(ctx, nonce + 16); // init big nonce (last 8 bytes)
+ uint8_t derived_key[32];
+ crypto_chacha20_H(derived_key, key, nonce);
+ crypto_chacha20_init(ctx, derived_key, nonce + 16);
}
void
crypto_chacha20_encrypt(crypto_chacha_ctx *ctx,
const uint8_t *plain_text,
uint8_t *cipher_text,
- size_t msg_length)
+ size_t message_size)
{
- for (size_t i = 0; i < msg_length; i++) {
+ for (size_t i = 0; i < message_size; i++) {
// refill the pool if empty
if (ctx->pool_index == 64) {
// fill the pool
void
crypto_chacha20_random(crypto_chacha_ctx *ctx,
uint8_t *cipher_text,
- size_t msg_length)
+ size_t message_size)
{
- crypto_chacha20_encrypt(ctx, 0, cipher_text, msg_length);
+ crypto_chacha20_encrypt(ctx, 0, cipher_text, message_size);
}
// This is a chacha20 context.
// To use safely, just follow these guidelines:
// - Always initialize your context with one of the crypto_init_* functions below
-// - Dont't modify it, except through the crypto_*_chacha20 below.
+// - Dont't modify it, except through the crypto_chacha20_* below.
// - Never duplicate it.
typedef struct crypto_chacha_ctx {
uint32_t input[16]; // current input, unencrypted
uint8_t pool_index; // pointer to random_pool
} crypto_chacha_ctx;
+// HChacha20. *Kind* of a cryptographic hash, based on the chacha20 rounds.
+// Used for XChacha20, and the key derivation of the X25519 shared secret.
+// Don't use it unless you really know what you're doing.
+void
+crypto_chacha20_H(uint8_t out[32],
+ const uint8_t key[32],
+ const uint8_t in [16]);
+
// Initializes a chacha context.
//
// WARNING: DON'T USE THE SAME NONCE AND KEY TWICE
const uint8_t key[32],
const uint8_t nonce[8]);
-// Initializes a chacha context, with an even bigger nonce (192 bits),
+// Initializes a chacha context, with a big nonce (192 bits),
// more than enough to be selected at random.
//
// The price you pay for that is a slower initialization. The security
// Encrypts the plain_text by XORing it with a pseudo-random
// stream of numbers, seeded by the provided chacha20 context.
-// It can safely be chained thus:
+// Decryption uses the exact same method.
+//
+// Once the context is initialized, encryptions can safely be chained thus:
//
-// crypto_encrypt_chacha20(ctx, plaint_0, cipher_0, length_0);
-// crypto_encrypt_chacha20(ctx, plaint_1, cipher_1, length_1);
-// crypto_encrypt_chacha20(ctx, plaint_2, cipher_2, length_2);
+// crypto_encrypt_chacha20(ctx, plain_0, cipher_0, length_0);
+// crypto_encrypt_chacha20(ctx, plain_1, cipher_1, length_1);
+// crypto_encrypt_chacha20(ctx, plain_2, cipher_2, length_2);
+//
+// plain_text and cipher_text may point to the same location, for in-place
+// encryption.
//
// plain_text is allowed to be null (0), in which case it will be
// interpreted as an all zero input. The cipher_text will then
// contain the raw chacha20 stream. Useful as a random number
// generator.
+//
+// WARNING: ENCRYPTION ALONE IS NOT SECURE. YOU NEED AUTHENTICATION AS WELL.
+// Use the provided authenticated encryption constructions.
void
crypto_chacha20_encrypt(crypto_chacha_ctx *ctx,
const uint8_t *plain_text,
uint8_t *cipher_text,
- size_t msg_length);
+ size_t message_size);
-// convenience function.
-// equivalent to encrypt_chacha20(ctx, 0, cipher_text, msg_length)
+// convenience function. Same as chacha20_encrypt() with a null plain_text.
void
crypto_chacha20_random(crypto_chacha_ctx *ctx,
uint8_t *cipher_text,
- size_t msg_length);
+ size_t message_size);
#endif // CHACHA20_H