tls

tls.git
git clone git://git.lenczewski.org/tls.git
Log | Files | Refs

chacha20.c (3012B)


      1 #include "chacha20.h"
      2 
      3 #include <endian.h>
      4 #include <string.h>
      5 
      6 struct chacha20_ctx {
      7 	alignas(CHACHA20_ALIGN)
      8 	chacha20_word_t vs[CHACHA20_BLOCK_WORDS];
      9 };
     10 
     11 void
     12 _chacha20_init(struct chacha20_ctx *ctx,
     13 	       unsigned char key[static CHACHA20_KEY_SIZE],
     14 	       uint32_t ctr,
     15 	       unsigned char iv[static CHACHA20_IV_SIZE])
     16 {
     17 	ctx->vs[0] = 0x61707865;
     18 	ctx->vs[1] = 0x3320646e;
     19 	ctx->vs[2] = 0x79622d32;
     20 	ctx->vs[3] = 0x6b206574;
     21 
     22 	memcpy(&ctx->vs[4], key, CHACHA20_KEY_SIZE);
     23 
     24 	ctx->vs[12] = ctr;
     25 
     26 	memcpy(&ctx->vs[13], iv, CHACHA20_IV_SIZE);
     27 }
     28 
     29 #define CHACHA20_ROTL(v, n, b) (((v) << (n)) | ((v) >> ((b) - (n))))
     30 
     31 #define CHACHA20_QUARTERROUND(a, b, c, d) \
     32 { \
     33 	a += b; d ^= a; d = CHACHA20_ROTL(d, 16, 32); \
     34 	c += d; b ^= c; b = CHACHA20_ROTL(b, 12, 32); \
     35 	a += b; d ^= a; d = CHACHA20_ROTL(d,  8, 32); \
     36 	c += d; b ^= c; b = CHACHA20_ROTL(b,  7, 32); \
     37 }
     38 
     39 static void
     40 _chacha20_inner_block(struct chacha20_ctx *ctx)
     41 {
     42 	CHACHA20_QUARTERROUND(ctx->vs[0], ctx->vs[4], ctx->vs[8],  ctx->vs[12]);
     43 	CHACHA20_QUARTERROUND(ctx->vs[1], ctx->vs[5], ctx->vs[9],  ctx->vs[13]);
     44 	CHACHA20_QUARTERROUND(ctx->vs[2], ctx->vs[6], ctx->vs[10], ctx->vs[14]);
     45 	CHACHA20_QUARTERROUND(ctx->vs[3], ctx->vs[7], ctx->vs[11], ctx->vs[15]);
     46 
     47 	CHACHA20_QUARTERROUND(ctx->vs[0], ctx->vs[5], ctx->vs[10], ctx->vs[15]);
     48 	CHACHA20_QUARTERROUND(ctx->vs[1], ctx->vs[6], ctx->vs[11], ctx->vs[12]);
     49 	CHACHA20_QUARTERROUND(ctx->vs[2], ctx->vs[7], ctx->vs[8],  ctx->vs[13]);
     50 	CHACHA20_QUARTERROUND(ctx->vs[3], ctx->vs[4], ctx->vs[9],  ctx->vs[14]);
     51 }
     52 
     53 static void
     54 _chacha20_block(struct chacha20_ctx *ctx,
     55 		unsigned char key[static CHACHA20_KEY_SIZE],
     56 		uint32_t ctr,
     57 		unsigned char iv[static CHACHA20_IV_SIZE])
     58 {
     59 	_chacha20_init(ctx, key, ctr, iv);
     60 
     61 	struct chacha20_ctx save;
     62 	memcpy(&save, ctx, sizeof *ctx);
     63 
     64 	for (size_t i = 0; i < CHACHA20_ROUNDS; i++) {
     65 		_chacha20_inner_block(ctx);
     66 	}
     67 
     68 	for (size_t i = 0; i < CHACHA20_BLOCK_WORDS; i++) {
     69 		save.vs[i] += ctx->vs[i];
     70 		ctx->vs[i] = htole32(save.vs[i]);
     71 	}
     72 }
     73 
     74 static void
     75 _chacha20_round(unsigned char key[static CHACHA20_KEY_SIZE],
     76 		uint32_t ctr,
     77 		unsigned char iv[static CHACHA20_IV_SIZE],
     78 		void const *plaintext, size_t len,
     79 		void *ciphertext)
     80 {
     81 	struct chacha20_ctx keystream;
     82 	_chacha20_block(&keystream, key, ctr, iv);
     83 
     84 	unsigned char const *in = plaintext, *end = in + len;
     85 	unsigned char *state = (void *) keystream.vs;
     86 	unsigned char *out = ciphertext;
     87 
     88 	while (in < end) {
     89 		*out++ = *in++ ^ *state++;
     90 	}
     91 }
     92 
     93 void
     94 chacha20(unsigned char key[static CHACHA20_KEY_SIZE],
     95 	 uint32_t ctr,
     96 	 unsigned char iv[static CHACHA20_IV_SIZE],
     97 	 void const *buf, size_t len,
     98 	 void *out)
     99 {
    100 	size_t blocks = len / CHACHA20_BLOCK_SIZE;
    101 	size_t tail = len - (blocks * CHACHA20_BLOCK_SIZE);
    102 	unsigned char const *ptr = buf;
    103 	unsigned char *dst = out;
    104 
    105 	size_t i;
    106 	for (i = 0; i < blocks; i++) {
    107 		_chacha20_round(key, ctr + i, iv, ptr, CHACHA20_BLOCK_SIZE, dst);
    108 
    109 		ptr += CHACHA20_BLOCK_SIZE;
    110 		dst += CHACHA20_BLOCK_SIZE;
    111 	}
    112 
    113 	_chacha20_round(key, ctr + i, iv, ptr, tail, dst);
    114 }