void chacha_crypt(struct chacha_ctx *ctx, size_t length, uint8_t *c, const uint8_t *m) { if (!length) return; for (;;) { uint32_t x[_CHACHA_STATE_LENGTH]; _chacha_core (x, ctx->state, CHACHA_ROUNDS); ctx->state[13] += (++ctx->state[12] == 0); /* stopping at 2^70 length per nonce is user's responsibility */ if (length <= CHACHA_BLOCK_SIZE) { memxor3 (c, m, x, length); return; } memxor3 (c, m, x, CHACHA_BLOCK_SIZE); length -= CHACHA_BLOCK_SIZE; c += CHACHA_BLOCK_SIZE; m += CHACHA_BLOCK_SIZE; } }
static void test_memxor3 (const uint8_t *ain, const uint8_t *bin, const uint8_t *c, size_t size, unsigned align_dst, unsigned align_a, unsigned align_b) { uint8_t dst_buf[MAX_SIZE + ALIGN_SIZE + 1]; uint8_t a_buf[MAX_SIZE + ALIGN_SIZE + 1]; uint8_t b_buf[MAX_SIZE + ALIGN_SIZE + 1]; uint8_t *dst = set_align (dst_buf, align_dst); uint8_t *a = set_align (a_buf, align_a); uint8_t *b = set_align (b_buf, align_b); if (verbose) fprintf(stderr, "size = %d, align_dst = %d, align_a = %d, align_b = %d\n", (int) size, align_dst, align_a, align_b); memset (dst, 0, size); dst[-1] = 17; dst[size] = 17; memcpy (a, ain, size); memcpy (b, bin, size); memxor3 (dst, a, b, size); ASSERT (MEMEQ (size, dst, c)); ASSERT (dst[-1] == 17); ASSERT (dst[size] == 17); }
static void ctr32_encrypt_blocks_inplace(const unsigned char *in, unsigned char *out, size_t blocks, const AES_KEY *key, const unsigned char ivec[16]) { unsigned i; uint8_t ctr[16]; uint8_t tmp[16]; memcpy(ctr, ivec, 16); for (i=0;i<blocks;i++) { aes_v8_encrypt(ctr, tmp, key); memxor3(out, tmp, in, 16); out += 16; in += 16; INC32(ctr); } }
void cfb_encrypt(const void *ctx, nettle_cipher_func *f, size_t block_size, uint8_t *iv, size_t length, uint8_t *dst, const uint8_t *src) { uint8_t *p; TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE); TMP_ALLOC(buffer, block_size); if (src != dst) { for (p = iv; length >= block_size; p = dst, dst += block_size, src += block_size, length -= block_size) { f(ctx, block_size, dst, p); memxor(dst, src, block_size); } } else { for (p = iv; length >= block_size; p = dst, dst += block_size, src += block_size, length -= block_size) { f(ctx, block_size, buffer, p); memxor(dst, buffer, block_size); } } if (p != iv) memcpy(iv, p, block_size); if (length) { f(ctx, block_size, buffer, iv); memxor3(dst, buffer, src, length); /* We do not care about updating IV here. This is the last call in * message sequence and one has to set IV afterwards anyway */ } }
void cfb8_decrypt(const void *ctx, nettle_cipher_func *f, size_t block_size, uint8_t *iv, size_t length, uint8_t *dst, const uint8_t *src) { TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE * 2); TMP_DECL(outbuf, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE * 2); TMP_ALLOC(buffer, block_size * 2); TMP_ALLOC(outbuf, block_size * 2); uint8_t i = 0; memcpy(buffer, iv, block_size); memcpy(buffer + block_size, src, length < block_size ? length : block_size); while (length) { for (i = 0; i < length && i < block_size; i++) f(ctx, block_size, outbuf + i, buffer + i); memxor3(dst, src, outbuf, i); length -= i; src += i; dst += i; memcpy(buffer, buffer + block_size, block_size); memcpy(buffer + block_size, src, length < block_size ? length : block_size); } memcpy(iv, buffer + i, block_size); }
static void test_salsa20_stream(const struct tstring *key, const struct tstring *iv, const struct tstring *ciphertext, const struct tstring *xor_ref) { struct salsa20_ctx ctx; uint8_t data[STREAM_LENGTH + 1]; uint8_t stream[STREAM_LENGTH + 1]; uint8_t xor[SALSA20_BLOCK_SIZE]; unsigned j; ASSERT (iv->length == SALSA20_IV_SIZE); ASSERT (ciphertext->length == 4*SALSA20_BLOCK_SIZE); ASSERT (xor_ref->length == SALSA20_BLOCK_SIZE); salsa20_set_key(&ctx, key->length, key->data); salsa20_set_iv(&ctx, iv->data); memset(stream, 0, STREAM_LENGTH + 1); salsa20_crypt(&ctx, STREAM_LENGTH, stream, stream); if (stream[STREAM_LENGTH]) { fprintf(stderr, "Stream of %d bytes wrote too much!\n", STREAM_LENGTH); FAIL(); } if (!MEMEQ (64, stream, ciphertext->data)) { fprintf(stderr, "Error failed, offset 0:\n"); fprintf(stderr, "\nOutput: "); print_hex(64, stream); fprintf(stderr, "\nExpected:"); print_hex(64, ciphertext->data); fprintf(stderr, "\n"); FAIL(); } if (!MEMEQ (128, stream + 192, ciphertext->data + 64)) { fprintf(stderr, "Error failed, offset 192:\n"); fprintf(stderr, "\nOutput: "); print_hex(128, stream + 192); fprintf(stderr, "\nExpected:"); print_hex(64, ciphertext->data + 64); fprintf(stderr, "\n"); FAIL(); } if (!MEMEQ (64, stream + 448, ciphertext->data + 192)) { fprintf(stderr, "Error failed, offset 448:\n"); fprintf(stderr, "\nOutput: "); print_hex(64, stream + 448); fprintf(stderr, "\nExpected:"); print_hex(64, ciphertext->data + 192); fprintf(stderr, "\n"); FAIL(); } memxor3 (xor, stream, stream + SALSA20_BLOCK_SIZE, SALSA20_BLOCK_SIZE); for (j = 2*SALSA20_BLOCK_SIZE; j < STREAM_LENGTH; j += SALSA20_BLOCK_SIZE) memxor (xor, stream + j, SALSA20_BLOCK_SIZE); if (!MEMEQ (SALSA20_BLOCK_SIZE, xor, xor_ref->data)) { fprintf(stderr, "Error failed, bad xor 448:\n"); fprintf(stderr, "\nOutput: "); print_hex(SALSA20_BLOCK_SIZE, xor); fprintf(stderr, "\nExpected:"); print_hex(SALSA20_BLOCK_SIZE, xor_ref->data); fprintf(stderr, "\n"); FAIL(); } for (j = 1; j <= STREAM_LENGTH; j++) { memset(data, 0, STREAM_LENGTH + 1); salsa20_set_iv(&ctx, iv->data); salsa20_crypt(&ctx, j, data, data); if (!MEMEQ(j, data, stream)) { fprintf(stderr, "Encrypt failed for length %u:\n", j); fprintf(stderr, "\nOutput: "); print_hex(j, data); fprintf(stderr, "\nExpected:"); print_hex(j, stream); fprintf(stderr, "\n"); FAIL(); } if (!memzero_p (data + j, STREAM_LENGTH + 1 - j)) { fprintf(stderr, "Encrypt failed for length %u, wrote too much:\n", j); fprintf(stderr, "\nOutput: "); print_hex(STREAM_LENGTH + 1 - j, data + j); fprintf(stderr, "\n"); FAIL(); } } }
void cfb_decrypt(const void *ctx, nettle_cipher_func *f, size_t block_size, uint8_t *iv, size_t length, uint8_t *dst, const uint8_t *src) { if (src != dst) { size_t left = length % block_size; length -= left; if (length > 0) { /* Decrypt in ECB mode */ f(ctx, block_size, dst, iv); f(ctx, length - block_size, dst + block_size, src); memcpy(iv, src + length - block_size, block_size); memxor(dst, src, length); } if (left > 0) { TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE); TMP_ALLOC(buffer, block_size); f(ctx, block_size, buffer, iv); memxor3(dst + length, src + length, buffer, left); } } else { /* For in-place CFB, we decrypt into a temporary buffer of size * at most CFB_BUFFER_LIMIT, and process that amount of data at * a time. */ /* NOTE: We assume that block_size <= CFB_BUFFER_LIMIT */ TMP_DECL(buffer, uint8_t, CFB_BUFFER_LIMIT); TMP_DECL(initial_iv, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE); size_t buffer_size; size_t left; buffer_size = CFB_BUFFER_LIMIT - (CFB_BUFFER_LIMIT % block_size); TMP_ALLOC(buffer, buffer_size); TMP_ALLOC(initial_iv, block_size); left = length % block_size; length -= left; while (length > 0) { size_t part = length > buffer_size ? buffer_size : length; /* length is greater that zero and is divided by block_size, so it is * not less than block_size. So does part */ f(ctx, block_size, buffer, iv); f(ctx, part - block_size, buffer + block_size, src); memcpy(iv, src + part - block_size, block_size); memxor(dst, buffer, part); length -= part; src += part; dst += part; } if (left > 0) { f(ctx, block_size, buffer, iv); memxor(dst, buffer, left); } } }
void cbc_decrypt(void *ctx, nettle_crypt_func *f, unsigned block_size, uint8_t *iv, unsigned length, uint8_t *dst, const uint8_t *src) { assert(!(length % block_size)); if (!length) return; if (src != dst) { /* Decrypt in ECB mode */ f(ctx, length, dst, src); /* XOR the cryptotext, shifted one block */ memxor(dst, iv, block_size); memxor(dst + block_size, src, length - block_size); memcpy(iv, src + length - block_size, block_size); } else { /* For in-place CBC, we decrypt into a temporary buffer of size * at most CBC_BUFFER_LIMIT, and process that amount of data at * a time. */ /* NOTE: We assume that block_size <= CBC_BUFFER_LIMIT, and we depend on memxor3 working from the end of the area, allowing certain overlapping operands. */ TMP_DECL(buffer, uint8_t, CBC_BUFFER_LIMIT); TMP_DECL(initial_iv, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE); unsigned buffer_size; if (length <= CBC_BUFFER_LIMIT) buffer_size = length; else buffer_size = CBC_BUFFER_LIMIT - (CBC_BUFFER_LIMIT % block_size); TMP_ALLOC(buffer, buffer_size); TMP_ALLOC(initial_iv, block_size); for ( ; length > buffer_size; length -= buffer_size, src += buffer_size, dst += buffer_size) { f(ctx, buffer_size, buffer, src); memcpy(initial_iv, iv, block_size); memcpy(iv, src + buffer_size - block_size, block_size); memxor3(dst + block_size, buffer + block_size, src, buffer_size - block_size); memxor3(dst, buffer, initial_iv, block_size); } f(ctx, length, buffer, src); memcpy(initial_iv, iv, block_size); /* Copies last block */ memcpy(iv, src + length - block_size, block_size); /* Writes all but first block, reads all but last block. */ memxor3(dst + block_size, buffer + block_size, src, length - block_size); /* Writes first block. */ memxor3(dst, buffer, initial_iv, block_size); } }