/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #include "bitops.h" #include "salsa20.h" #include "blockwise.h" #include "tassert.h" #include #include void cf_chacha20_core(const uint8_t key0[16], const uint8_t key1[16], const uint8_t nonce[16], const uint8_t constant[16], uint8_t out[64]) { uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, za, zb, zc, zd, ze, zf; uint32_t x0 = z0 = read32_le(constant + 0), x1 = z1 = read32_le(constant + 4), x2 = z2 = read32_le(constant + 8), x3 = z3 = read32_le(constant + 12), x4 = z4 = read32_le(key0 + 0), x5 = z5 = read32_le(key0 + 4), x6 = z6 = read32_le(key0 + 8), x7 = z7 = read32_le(key0 + 12), x8 = z8 = read32_le(key1 + 0), x9 = z9 = read32_le(key1 + 4), xa = za = read32_le(key1 + 8), xb = zb = read32_le(key1 + 12), xc = zc = read32_le(nonce + 0), xd = zd = read32_le(nonce + 4), xe = ze = read32_le(nonce + 8), xf = zf = read32_le(nonce + 12); #define QUARTER(a, b, c, d) \ a += b; d = rotl32(d ^ a, 16); \ c += d; b = rotl32(b ^ c, 12); \ a += b; d = rotl32(d ^ a, 8); \ c += d; b = rotl32(b ^ c, 7); int i; for (i = 0; i < 10; i++) { QUARTER(z0, z4, z8, zc); QUARTER(z1, z5, z9, zd); QUARTER(z2, z6, za, ze); QUARTER(z3, z7, zb, zf); QUARTER(z0, z5, za, zf); QUARTER(z1, z6, zb, zc); QUARTER(z2, z7, z8, zd); QUARTER(z3, z4, z9, ze); } x0 += z0; x1 += z1; x2 += z2; x3 += z3; x4 += z4; x5 += z5; x6 += z6; x7 += z7; x8 += z8; x9 += z9; xa += za; xb += zb; xc += zc; xd += zd; xe += ze; xf += zf; write32_le(x0, out + 0); write32_le(x1, out + 4); write32_le(x2, out + 8); write32_le(x3, out + 12); write32_le(x4, out + 16); write32_le(x5, out + 20); write32_le(x6, out + 24); write32_le(x7, out + 28); write32_le(x8, out + 32); write32_le(x9, out + 36); write32_le(xa, out + 40); write32_le(xb, out + 44); write32_le(xc, out + 48); write32_le(xd, out + 52); write32_le(xe, out + 56); write32_le(xf, out + 60); } static const uint8_t *chacha20_tau = (const uint8_t *) "expand 16-byte k"; static const uint8_t *chacha20_sigma = (const uint8_t *) "expand 32-byte k"; static void set_key(cf_chacha20_ctx *ctx, const uint8_t *key, size_t nkey) { switch (nkey) { case 16: memcpy(ctx->key0, key, 16); memcpy(ctx->key1, key, 16); ctx->constant = chacha20_tau; break; case 32: memcpy(ctx->key0, key, 16); memcpy(ctx->key1, key + 16, 16); ctx->constant = chacha20_sigma; break; default: abort(); } } void cf_chacha20_init(cf_chacha20_ctx *ctx, const uint8_t *key, size_t nkey, const uint8_t nonce[8]) { set_key(ctx, key, nkey); memset(ctx->nonce, 0, sizeof ctx->nonce); memcpy(ctx->nonce + 8, nonce, 8); ctx->nblock = 0; ctx->ncounter = 8; } void cf_chacha20_init_custom(cf_chacha20_ctx *ctx, const uint8_t *key, size_t nkey, const uint8_t nonce[16], size_t ncounter) { assert(ncounter > 0); set_key(ctx, key, nkey); memcpy(ctx->nonce, nonce, sizeof ctx->nonce); ctx->nblock = 0; ctx->ncounter = ncounter; } static void cf_chacha20_next_block(void *vctx, uint8_t *out) { cf_chacha20_ctx *ctx = vctx; cf_chacha20_core(ctx->key0, ctx->key1, ctx->nonce, ctx->constant, out); incr_le(ctx->nonce, ctx->ncounter); } void cf_chacha20_cipher(cf_chacha20_ctx *ctx, const uint8_t *input, uint8_t *output, size_t bytes) { cf_blockwise_xor(ctx->block, &ctx->nblock, 64, input, output, bytes, cf_chacha20_next_block, ctx); }