From 970348c1b62c2eb7e94c1c2601f74820f5f63624 Mon Sep 17 00:00:00 2001 From: Ariel Abreu Date: Sun, 10 Jan 2021 15:22:00 -0500 Subject: [PATCH] Implement AES-ECB and CBC mode This is also a huge rewrite to the GCM code to make it block cipher independent. The AES-ECB code is basically a combination of the previous AES block cipher encryption code with new code for AES decryption. --- CMakeLists.txt | 9 +- include/corecrypto/ccmode_factory.h | 2 +- include/corecrypto/ccmode_impl.h | 2 +- include/corecrypto/private/cc128.h | 164 ++++++ include/corecrypto/private/ccaes_extra.h | 349 ------------- include/corecrypto/private/ccgcm.h | 82 --- include/corecrypto/private/ccstubs.h | 15 + src/ccaes.c | 557 +++++++++++++++++--- src/ccaes_extra.c | 86 --- src/cccbc.c | 67 +++ src/ccccm.c | 30 ++ src/cccfb.c | 14 + src/cccfb8.c | 14 + src/ccckg.c | 38 ++ src/ccctr.c | 14 + src/ccgcm.c | 635 ++++++++++++++--------- src/ccmode.c | 121 +++-- src/ccn.c | 4 +- src/ccofb.c | 9 + src/ccxts.c | 18 + 20 files changed, 1330 insertions(+), 900 deletions(-) create mode 100644 include/corecrypto/private/cc128.h delete mode 100644 include/corecrypto/private/ccaes_extra.h delete mode 100644 include/corecrypto/private/ccgcm.h create mode 100644 include/corecrypto/private/ccstubs.h delete mode 100644 src/ccaes_extra.c create mode 100644 src/cccbc.c create mode 100644 src/ccccm.c create mode 100644 src/cccfb.c create mode 100644 src/cccfb8.c create mode 100644 src/ccckg.c create mode 100644 src/ccctr.c create mode 100644 src/ccofb.c create mode 100644 src/ccxts.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a4f4225..72932e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,12 +57,19 @@ set(corecrypto_sources src/ccec_points.c src/ccn_extra.c src/cczp_extra.c - src/ccaes_extra.c src/ccgcm.c src/ccsrp.c src/ccwrap_priv.c src/cc_priv.c src/ccec25519.c + src/cccbc.c + src/ccccm.c + src/cccfb.c + src/cccfb8.c + src/ccctr.c + src/ccofb.c + src/ccxts.c + src/ccckg.c ) if (DARLING) diff --git a/include/corecrypto/ccmode_factory.h b/include/corecrypto/ccmode_factory.h index 8a2e9e7..a43d124 100644 --- a/include/corecrypto/ccmode_factory.h +++ b/include/corecrypto/ccmode_factory.h @@ -253,7 +253,7 @@ int ccmode_ctr_init(const struct ccmode_ctr *ctr, ccctr_ctx *ctx, size_t rawkey_len, const void *rawkey, const void *iv); int ccmode_ctr_crypt(ccctr_ctx *ctx, size_t nbytes, const void *in, void *out); -int ccmode_ctr_setctr(ccctr_ctx* ctx, ccctr_ctx *, const void* iv); +int ccmode_ctr_setctr(const struct ccmode_ctr *ctr, ccctr_ctx *ctx, const void* iv); struct _ccmode_ctr_key { const struct ccmode_ecb *ecb; diff --git a/include/corecrypto/ccmode_impl.h b/include/corecrypto/ccmode_impl.h index 118f8db..5f9055a 100644 --- a/include/corecrypto/ccmode_impl.h +++ b/include/corecrypto/ccmode_impl.h @@ -106,7 +106,7 @@ struct ccmode_ctr { int (*init)(const struct ccmode_ctr *ctr, ccctr_ctx *ctx, size_t key_len, const void *key, const void *iv); int (*ctr)(ccctr_ctx *ctx, size_t nbytes, const void *in, void *out); - int (*setctr)(ccctr_ctx* ctx, ccctr_ctx *, const void* iv); + int (*setctr)(const struct ccmode_ctr *ctr, ccctr_ctx *ctx, const void* iv); const void *custom; }; diff --git a/include/corecrypto/private/cc128.h b/include/corecrypto/private/cc128.h new file mode 100644 index 0000000..66cc329 --- /dev/null +++ b/include/corecrypto/private/cc128.h @@ -0,0 +1,164 @@ +#ifndef _CC_PRIVATE_CC128_H_ +#define _CC_PRIVATE_CC128_H_ + +// +// 128-bit arithmetic +// +// TODO: take advantadge of native architecture support for 128-bit integers when available +// + +#include +#include +#include +#include + +// little endian representation of a 128-bit integer +typedef struct { + uint8_t bytes[16]; +} cc128_t; + +// note that this is a literal but *not* a constant +#define CC128_LITERAL16(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \ + ((cc128_t) { .bytes = { 0x ## p, 0x ## o, 0x ## n, 0x ## m, 0x ## l, 0x ## k, 0x ## j, 0x ## i, 0x ## h, 0x ## g, 0x ## f, 0x ## e, 0x ## d, 0x ## c, 0x ## b, 0x ## a, }, }) +#define CC128_LITERAL15(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \ + CC128_LITERAL16(0, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) +#define CC128_LITERAL14(a, b, c, d, e, f, g, h, i, j, k, l, m, n) \ + CC128_LITERAL15(0, a, b, c, d, e, f, g, h, i, j, k, l, m, n) +#define CC128_LITERAL13(a, b, c, d, e, f, g, h, i, j, k, l, m) \ + CC128_LITERAL14(0, a, b, c, d, e, f, g, h, i, j, k, l, m) +#define CC128_LITERAL12(a, b, c, d, e, f, g, h, i, j, k, l) \ + CC128_LITERAL13(0, a, b, c, d, e, f, g, h, i, j, k, l) +#define CC128_LITERAL11(a, b, c, d, e, f, g, h, i, j, k) \ + CC128_LITERAL12(0, a, b, c, d, e, f, g, h, i, j, k) +#define CC128_LITERAL10(a, b, c, d, e, f, g, h, i, j) \ + CC128_LITERAL11(0, a, b, c, d, e, f, g, h, i, j) +#define CC128_LITERAL9(a, b, c, d, e, f, g, h, i) \ + CC128_LITERAL10(0, a, b, c, d, e, f, g, h, i) +#define CC128_LITERAL8(a, b, c, d, e, f, g, h) \ + CC128_LITERAL9(0, a, b, c, d, e, f, g, h) +#define CC128_LITERAL7(a, b, c, d, e, f, g) \ + CC128_LITERAL8(0, a, b, c, d, e, f, g) +#define CC128_LITERAL6(a, b, c, d, e, f) \ + CC128_LITERAL7(0, a, b, c, d, e, f) +#define CC128_LITERAL5(a, b, c, d, e) \ + CC128_LITERAL6(0, a, b, c, d, e) +#define CC128_LITERAL4(a, b, c, d) \ + CC128_LITERAL5(0, a, b, c, d) +#define CC128_LITERAL3(a, b, c) \ + CC128_LITERAL4(0, a, b, c) +#define CC128_LITERAL2(a, b) \ + CC128_LITERAL3(0, a, b) +#define CC128_LITERAL1(a) \ + CC128_LITERAL2(0, a) + +#define CC128_ZERO ((cc128_t) {0}) + +CC_INLINE +bool cc128_bit(const cc128_t* a, uint8_t bit_index) { + return (a->bytes[bit_index / 8] >> (bit_index % 8)) & 1; +}; + +CC_INLINE +void cc128_xor(const cc128_t* a, const cc128_t* b, cc128_t* output) { + cc_xor(sizeof(cc128_t), output, a, b); +}; + +CC_INLINE +void cc128_shift_right_once(const cc128_t* a, cc128_t* output) { + for (uint8_t i = 0; i < 15; ++i) + output->bytes[i] = ((a->bytes[i + 1] & 1) << 7) | (a->bytes[i] >> 1); + output->bytes[15] = a->bytes[15] >> 1; +}; + +CC_INLINE +void cc128_mul(const cc128_t* a, const cc128_t* b, cc128_t* output) { + cc128_t z = {0}; + cc128_t v = *b; + + for (uint8_t i = 128; i > 0; --i) { + if (cc128_bit(a, i - 1)) { + cc128_xor(&z, &v, &z); + } + bool lsb_v = cc128_bit(&v, 0); + cc128_shift_right_once(&v, &v); + if (lsb_v) + v.bytes[15] ^= 0xe1; + } + + *output = z; +}; + +/** + * Increments the least significant word (32 bits) of the given block by 1. + */ +CC_INLINE +void cc128_lsw_increment(const cc128_t* a, cc128_t* output) { + uint32_t lsw = 0; + CC_LOAD32_LE(lsw, a->bytes); + ++lsw; + CC_STORE32_LE(lsw, output->bytes); + cc_copy(12, &output->bytes[4], &a->bytes[4]); +}; + +/** + * Loads 128 bits from the given input buffer as a big-endian integer. + * If there aren't enough bits available (i.e. input_length * 8 is less than 16), + * the output will be padded with trailing zeros. + */ +CC_INLINE +void cc128_load_be(size_t input_length, const void* input, cc128_t* output) { + const uint8_t* real_input = input; + size_t limit = input_length < 16 ? input_length : 16; + for (size_t i = 0; i < limit; ++i) + output->bytes[15 - i] = real_input[i]; + for (size_t i = limit; i < 16; ++i) + output->bytes[15 - i] = 0; +}; + +/** + * Stores 128 bits into the given output buffer as a big-endian integer. + * If there isn't enough space to store all 128 bits (i.e. output_length * 8 is less than 16), + * the output will be truncated to the most significant bits that fit in the output buffer. + */ +CC_INLINE +void cc128_store_be(const cc128_t* input, size_t output_length, void* output) { + uint8_t* real_output = output; + size_t limit = output_length < 16 ? output_length : 16; + for (size_t i = 0; i < limit; ++i) + real_output[i] = input->bytes[15 - i]; +}; + +/** + * Stores the least significant given number of bits from the input block into the output block. + * The input and output blocks MUST NOT overlap. + */ +CC_INLINE +void cc128_lsbits(const cc128_t* restrict input, uint8_t bits, cc128_t* restrict output) { + *output = CC128_ZERO; + uint8_t bytes = (bits + 7) / 8; + + for (uint8_t i = 0; i < bytes; ++i) + output->bytes[i] = input->bytes[i]; + + uint8_t final_byte_bits = bits % 8; + output->bytes[bytes - 1] &= (0xff << (8 - final_byte_bits)) >> (8 - final_byte_bits); +}; + +/** + * Stores the most significant given number of bits from the input block into the output block. + * The input and output blocks MUST NOT overlap. + */ +CC_INLINE +void cc128_msbits(const cc128_t* restrict input, uint8_t bits, cc128_t* restrict output) { + *output = CC128_ZERO; + uint8_t bytes = (bits + 7) / 8; + uint8_t diff = 16 - bytes; + + for (uint8_t i = 0; i < bytes; ++i) + output->bytes[i] = input->bytes[i + diff]; + + uint8_t final_byte_bits = bits % 8; + output->bytes[bytes - 1] &= (0xff << (8 - final_byte_bits)) >> (8 - final_byte_bits); +}; + +#endif // _CC_PRIVATE_CC128_H_ diff --git a/include/corecrypto/private/ccaes_extra.h b/include/corecrypto/private/ccaes_extra.h deleted file mode 100644 index 2a53d65..0000000 --- a/include/corecrypto/private/ccaes_extra.h +++ /dev/null @@ -1,349 +0,0 @@ -#ifndef CC_PRIVATE_CCAES_EXTRA_H -#define CC_PRIVATE_CCAES_EXTRA_H - -#include -#include - -// -// ~~~typedefs~~~ -// - -// little endian representation of a 128-bit block -typedef struct { - uint8_t block[16]; -} ccaes_block_128_t; - -typedef struct { - uint8_t bytes[4][4]; -} ccaes_state_t; - -typedef struct { - uint8_t bytes[4]; -} ccaes_word_t; - -// `key` is a big-endian array -typedef ccaes_block_128_t (*ccaes_block_cipher_function_t)(const ccaes_block_128_t input, const size_t key_len, const uint8_t* const key); - -// -// ~~~constants~~~ -// - -static const uint8_t ccaes_s_box[16][16] = { - { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, }, - { 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, }, - { 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, }, - { 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, }, - { 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, }, - { 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, }, - { 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, }, - { 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, }, - { 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, }, - { 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, }, - { 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, }, - { 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, }, - { 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, }, - { 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, }, - { 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, }, - { 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, }, -}; - -static const uint8_t ccaes_round_constant[] = { - 0x01, - 0x02, - 0x04, - 0x08, - 0x10, - 0x20, - 0x40, - 0x80, - 0x1b, - 0x36, -}; - -// -// ~~~function declarations~~~ -// - -// `key` is a big-endian array -ccaes_block_128_t ccaes_block_cipher(const ccaes_block_128_t input, const size_t key_len, const uint8_t* const key); - -// -// ~~~inline functions~~~ -// - -CC_INLINE -void ccaes_sub_bytes(const size_t len, const uint8_t* const in, uint8_t* const out) { - for (size_t i = 0; i < len; ++i) - out[i] = ccaes_s_box[(in[i] & 0xf0) >> 4][in[i] & 0x0f]; -}; - -CC_INLINE -ccaes_state_t ccaes_shift_rows(const ccaes_state_t state) { - return (ccaes_state_t) { - .bytes = { - { state.bytes[0][0], state.bytes[0][1], state.bytes[0][2], state.bytes[0][3], }, - { state.bytes[1][1], state.bytes[1][2], state.bytes[1][3], state.bytes[1][0], }, - { state.bytes[2][2], state.bytes[2][3], state.bytes[2][0], state.bytes[2][1], }, - { state.bytes[3][3], state.bytes[3][0], state.bytes[3][1], state.bytes[3][2], }, - }, - }; -}; - -CC_INLINE -ccaes_state_t ccaes_mix_columns(const ccaes_state_t state) { - // https://en.wikipedia.org/wiki/Rijndael_MixColumns#Implementation_example - - ccaes_state_t result = {0}; - - // hopefully the compiler is smart enough to unroll this loop - for (uint8_t i = 0; i < 4; ++i) { - uint8_t b[4] = {0}; - - for (uint8_t j = 0; j < 4; ++j) { - uint8_t h = state.bytes[j][i] & 0x80; - b[j] = state.bytes[j][i] << 1; - if (h) - b[j] ^= 0x1b; - } - - result.bytes[0][i] = b[0] ^ state.bytes[3][i] ^ state.bytes[2][i] ^ b[1] ^ state.bytes[1][i]; - result.bytes[1][i] = b[1] ^ state.bytes[0][i] ^ state.bytes[3][i] ^ b[2] ^ state.bytes[2][i]; - result.bytes[2][i] = b[2] ^ state.bytes[1][i] ^ state.bytes[0][i] ^ b[3] ^ state.bytes[3][i]; - result.bytes[3][i] = b[3] ^ state.bytes[2][i] ^ state.bytes[1][i] ^ b[0] ^ state.bytes[0][i]; - } - - return result; -}; - -CC_INLINE -ccaes_state_t ccaes_add_round_key(const ccaes_state_t state, const ccaes_word_t* const round_key) { - return (ccaes_state_t) { - .bytes = { - { (state.bytes[0][0] ^ round_key[0].bytes[0]), (state.bytes[0][1] ^ round_key[1].bytes[0]), (state.bytes[0][2] ^ round_key[2].bytes[0]), (state.bytes[0][3] ^ round_key[3].bytes[0]), }, - { (state.bytes[1][0] ^ round_key[0].bytes[1]), (state.bytes[1][1] ^ round_key[1].bytes[1]), (state.bytes[1][2] ^ round_key[2].bytes[1]), (state.bytes[1][3] ^ round_key[3].bytes[1]), }, - { (state.bytes[2][0] ^ round_key[0].bytes[2]), (state.bytes[2][1] ^ round_key[1].bytes[2]), (state.bytes[2][2] ^ round_key[2].bytes[2]), (state.bytes[2][3] ^ round_key[3].bytes[2]), }, - { (state.bytes[3][0] ^ round_key[0].bytes[3]), (state.bytes[3][1] ^ round_key[1].bytes[3]), (state.bytes[3][2] ^ round_key[2].bytes[3]), (state.bytes[3][3] ^ round_key[3].bytes[3]), }, - }, - }; -}; - -CC_INLINE -ccaes_state_t ccaes_read_state(const size_t len, const uint8_t* const data) { - ccaes_state_t result = {0}; - - for (size_t i = 0; i < len && i < 16; ++i) - result.bytes[i / 4][i % 4] = data[i]; - - return result; -}; - -CC_INLINE -void ccaes_write_state(const ccaes_state_t state, const size_t len, uint8_t* const out) { - for (size_t i = 0; i < len && i < 16; ++i) - out[i] = state.bytes[i / 4][i % 4]; -}; - -CC_INLINE -void ccaes_read_column(ccaes_state_t* const state, const size_t column, const uint8_t* const data) { - for (size_t i = 0; i < 4; ++i) - state->bytes[i][column] = data[i]; -}; - -CC_INLINE -void ccaes_write_column(const ccaes_state_t state, const size_t column, uint8_t* const out) { - for (size_t i = 0; i < 4; ++i) - out[i] = state.bytes[i][column]; -}; - -CC_INLINE -size_t ccaes_round_count(const size_t key_len) { - if (key_len == 16) - return 10; - if (key_len == 24) - return 12; - if (key_len == 32) - return 14; - return 0; -}; - -CC_INLINE -ccaes_word_t ccaes_rot_word(const ccaes_word_t word) { - return (ccaes_word_t) { - .bytes = { word.bytes[1], word.bytes[2], word.bytes[3], word.bytes[0] }, - }; -}; - -CC_INLINE -ccaes_word_t ccaes_xor_word(const ccaes_word_t x, const ccaes_word_t y) { - return (ccaes_word_t) { - .bytes = { x.bytes[0] ^ y.bytes[0], x.bytes[1] ^ y.bytes[1], x.bytes[2] ^ y.bytes[2], x.bytes[3] ^ y.bytes[3] }, - }; -}; - -// get the bit at the specified 0-based index -CC_INLINE -bool ccaes_bit_128(const ccaes_block_128_t block, const uint8_t index) { - return (block.block[index / 8] >> (index % 8)) & 1; -}; - -CC_INLINE -ccaes_block_128_t ccaes_xor_128(const ccaes_block_128_t x, const ccaes_block_128_t y) { - return (ccaes_block_128_t) { - .block = { - x.block[ 0] ^ y.block[ 0], - x.block[ 1] ^ y.block[ 1], - x.block[ 2] ^ y.block[ 2], - x.block[ 3] ^ y.block[ 3], - x.block[ 4] ^ y.block[ 4], - x.block[ 5] ^ y.block[ 5], - x.block[ 6] ^ y.block[ 6], - x.block[ 7] ^ y.block[ 7], - x.block[ 8] ^ y.block[ 8], - x.block[ 9] ^ y.block[ 9], - x.block[10] ^ y.block[10], - x.block[11] ^ y.block[11], - x.block[12] ^ y.block[12], - x.block[13] ^ y.block[13], - x.block[14] ^ y.block[14], - x.block[15] ^ y.block[15], - }, - }; -}; - -// shift right by a single bit (i.e. `>> 1`) -CC_INLINE -ccaes_block_128_t ccaes_shift_right_128(const ccaes_block_128_t block) { - ccaes_block_128_t result = {0}; - - for (uint8_t i = 0; i < 15; ++i) - result.block[i] = (block.block[i] >> 1) | ((block.block[i + 1] & 1) << 7); - - result.block[15] = block.block[15] >> 1; - - return result; -}; - -CC_INLINE -ccaes_block_128_t ccaes_most_significant_bits_128(const ccaes_block_128_t block, const uint8_t bits) { - const uint8_t bytes = (bits + 7) / 8; - ccaes_block_128_t result = {0}; - const uint8_t diff = 16 - bytes; - - for (uint8_t i = 0; i < bytes; ++i) - result.block[i] = block.block[i + diff]; - - const uint8_t final_byte_bits = bits % 8; - result.block[bytes - 1] &= (0xff << (8 - final_byte_bits)) >> (8 - final_byte_bits); - - return result; -}; - -CC_INLINE -ccaes_block_128_t ccaes_least_significant_bits_128(const ccaes_block_128_t block, const uint8_t bits) { - ccaes_block_128_t result = {0}; - const uint8_t bytes = (bits + 7) / 8; - - for (uint8_t i = 0; i < bytes; ++i) - result.block[i] = block.block[i]; - - const uint8_t final_byte_bits = bits % 8; - result.block[bytes - 1] &= (0xff << (8 - final_byte_bits)) >> (8 - final_byte_bits); - - return result; -}; - -// increment the least significant `bits` number of bits of `block` -CC_INLINE -ccaes_block_128_t ccaes_increment_128(const ccaes_block_128_t block, const uint8_t bits) { - ccaes_block_128_t result = block; - const uint8_t bytes = (bits + 7) / 8; - uint8_t carry = 1; - - for (uint8_t i = 0; i < bytes - 1; ++i) { - const uint8_t sum = result.block[i] + carry; - carry = (sum < result.block[i]) ? 1 : 0; - result.block[i] = sum; - } - - const uint8_t final_byte_bits = bits - ((bytes - 1) * 8); - const uint8_t mask = (0xff << (8 - final_byte_bits)) >> (8 - final_byte_bits); - - result.block[bytes - 1] = (result.block[bytes - 1] & ~mask) | ((result.block[bytes - 1] + carry) & mask); - - return result; -}; - -CC_INLINE -ccaes_block_128_t ccaes_multiply_128(const ccaes_block_128_t x, const ccaes_block_128_t y) { - ccaes_block_128_t z = {0}; - ccaes_block_128_t v = y; - - for (uint8_t i = 128; i > 0; --i) { - if (ccaes_bit_128(x, i - 1)) - z = ccaes_xor_128(z, v); - const bool lsb_v = ccaes_bit_128(v, 0); - v = ccaes_shift_right_128(v); - if (lsb_v) - v.block[15] ^= 0xe1; - } - - return z; -}; - -CC_INLINE -ccaes_block_128_t ccaes_power_128(const ccaes_block_128_t block, const size_t power) { - if (power == 0) { - return (ccaes_block_128_t) { - .block = { - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - }, - }; - } - - ccaes_block_128_t result = block; - - for (size_t i = 0; i < power - 1; ++i) - result = ccaes_multiply_128(result, block); - - return result; -}; - -// creates a 128-bit block from the leading bytes of `data`, -// regardless of whether `data` actually has 128-bits of data available -// -// (assumes that `data` is big-endian) -// -// this could actually be named `ccaes_read_block_128` -CC_INLINE -ccaes_block_128_t ccaes_normalize_128(const size_t len, const uint8_t* const data) { - ccaes_block_128_t result = {0}; - - for (size_t i = 0; i < len && i < 16; ++i) - result.block[15 - i] = data[i]; - - return result; -}; - -// writes the given block to the output array in big-endian byte order -CC_INLINE -void ccaes_write_block_128(ccaes_block_128_t block, const size_t out_len, uint8_t* const out) { - for (size_t i = 0; i < out_len && i < 16; ++i) - out[i] = block.block[15 - i]; -}; - -#endif // CC_PRIVATE_CCAES_EXTRA_H diff --git a/include/corecrypto/private/ccgcm.h b/include/corecrypto/private/ccgcm.h deleted file mode 100644 index 4c72c2b..0000000 --- a/include/corecrypto/private/ccgcm.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef CC_PRIVATE_CCGCM_H -#define CC_PRIVATE_CCGCM_H - -#include -#include - -// -// ~~~constants~~~ -// - -#define CCGCM_MODE_INITIALIZE 0 -#define CCGCM_MODE_IV 1 -#define CCGCM_MODE_AAD 2 -#define CCGCM_MODE_CIPHERTEXT 3 -#define CCGCM_MODE_FINALIZE 4 - -// -// ~~~typedefs~~~ -// - -typedef struct { - // true if decrypting, false if encrypting - bool decrypting; - - // initialize, IV, AAD, ciphertext, or finalize mode - uint8_t mode; - - size_t key_len; - const uint8_t* key; - - size_t total_iv_length; - size_t total_cipher_length; - size_t total_aad_length; - - uint8_t current_iv[12]; - - // hash subkey - ccaes_block_128_t hash_subkey; - - // initial counter block - ccaes_block_128_t initial_cb; - - // cumulative hash block - ccaes_block_128_t hash; - - // most recent block of data (IV, AAD, or ciphertext, depending on which mode we're in) - ccaes_block_128_t cache; - - // current counter block - // (used for ciphertext generation) - ccaes_block_128_t cb; - - // cached result of processing the current counter block with the block cipher function - ccaes_block_128_t processed_cb; -} ccgcm_state; - -// -// ~~~function declarations~~~ -// - -// input_len should be a multiple of 16, otherwise you may receive unexpected results! -// (however the function will not error if it is not, you will simply receive possibly -// erroneous results) -ccaes_block_128_t ccgcm_ghash_128(const ccaes_block_128_t hash_subkey, const size_t input_len, const uint8_t* const input); - -int ccgcm_gctr_128(const ccaes_block_cipher_function_t block_cipher_function, const size_t key_len, const uint8_t* const key, const ccaes_block_128_t icb, const size_t input_len, const uint8_t* const input, uint8_t* const output); - -int ccgcm_internal_init(const struct ccmode_gcm* gcm, ccgcm_ctx* ctx, size_t key_len, const void* key); - -int ccgcm_internal_set_iv(ccgcm_ctx* ctx, size_t iv_size, const void* iv); - -int ccgcm_internal_gmac(ccgcm_ctx* ctx, size_t nbytes, const void* in); - -int ccgcm_internal_gcm(ccgcm_ctx* ctx, size_t nbytes, const void* in, void* out); - -int ccgcm_internal_finalize(ccgcm_ctx* key, size_t tag_size, void* tag); - -int ccgcm_internal_reset(ccgcm_ctx* ctx); - -void ccgcm_process_iv(ccgcm_state* ctx); - -#endif // CC_PRIVATE_CCGCM_H diff --git a/include/corecrypto/private/ccstubs.h b/include/corecrypto/private/ccstubs.h new file mode 100644 index 0000000..d0fab63 --- /dev/null +++ b/include/corecrypto/private/ccstubs.h @@ -0,0 +1,15 @@ +#ifndef CC_PRIVATE_CCSTUBS_H +#define CC_PRIVATE_CCSTUBS_H + +#include +#include + +#define CC_STUB(return_value) \ + printf("DARLING CORECRYPTO STUB: %s\n", __FUNCTION__); \ + return return_value; + +#define CC_STUB_VOID() CC_STUB(;) + +#define CC_STUB_ERR() CC_STUB(CCERR_INTERNAL) + +#endif // CC_PRIVATE_CCSTUBS_H diff --git a/src/ccaes.c b/src/ccaes.c index bb4aab9..93ee632 100644 --- a/src/ccaes.c +++ b/src/ccaes.c @@ -1,102 +1,491 @@ #include -#include +#include +#include +#include #include -static const struct ccmode_gcm ccaes_gcm_encrypt = { - .size = sizeof(ccgcm_state), - .encdec = CCMODE_GCM_ENCRYPTOR, +typedef struct { + uint8_t bytes[4][4]; +} ccaes_state_t; + +typedef struct { + uint8_t bytes[4]; +} ccaes_word_t; + +CCMODE_GCM_FACTORY(aes, encrypt); +CCMODE_GCM_FACTORY(aes, decrypt); + +CCMODE_CBC_FACTORY(aes, encrypt); +CCMODE_CBC_FACTORY(aes, decrypt); + +CCMODE_CFB_FACTORY(aes, cfb, encrypt); +CCMODE_CFB_FACTORY(aes, cfb, decrypt); + +CCMODE_CFB_FACTORY(aes, cfb8, encrypt); +CCMODE_CFB_FACTORY(aes, cfb8, decrypt); + +CCMODE_XTS_FACTORY(aes, encrypt); +CCMODE_XTS_FACTORY(aes, decrypt); + +CCMODE_CCM_FACTORY(aes, encrypt); +CCMODE_CCM_FACTORY(aes, decrypt); + +CCMODE_CTR_FACTORY(aes); + +CCMODE_OFB_FACTORY(aes); + +static int ccaes_ecb_init(const struct ccmode_ecb* info, ccecb_ctx* ctx, size_t key_size, const void* key); +static int ccaes_ecb_encrypt(const ccecb_ctx* ctx, size_t block_count, const void* in, void* out); +static int ccaes_ecb_decrypt(const ccecb_ctx* ctx, size_t block_count, const void* in, void* out); + +struct the_real_ccecb_ctx { + uint8_t round_count; + + // allocate enough space for the maximum number of round keys + ccaes_word_t round_keys[4 * 15]; +}; + +static const struct ccmode_ecb ccaes_ecb_encrypt_info = { .block_size = 16, - .init = ccgcm_internal_init, - .set_iv = ccgcm_internal_set_iv, - .gmac = ccgcm_internal_gmac, - .gcm = ccgcm_internal_gcm, - .finalize = ccgcm_internal_finalize, - .reset = ccgcm_internal_reset, - .custom = NULL, + .size = sizeof(struct the_real_ccecb_ctx), + .init = ccaes_ecb_init, + .ecb = ccaes_ecb_encrypt, }; -static const struct ccmode_gcm ccaes_gcm_decrypt = { - .size = sizeof(ccgcm_state), - .encdec = CCMODE_GCM_DECRYPTOR, +static const struct ccmode_ecb ccaes_ecb_decrypt_info = { .block_size = 16, - .init = ccgcm_internal_init, - .set_iv = ccgcm_internal_set_iv, - .gmac = ccgcm_internal_gmac, - .gcm = ccgcm_internal_gcm, - .finalize = ccgcm_internal_finalize, - .reset = ccgcm_internal_reset, - .custom = NULL, + .size = sizeof(struct the_real_ccecb_ctx), + .init = ccaes_ecb_init, + .ecb = ccaes_ecb_decrypt, }; -const struct ccmode_ecb *ccaes_ecb_encrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_cbc *ccaes_cbc_encrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_cfb *ccaes_cfb_encrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_cfb8 *ccaes_cfb8_encrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_xts *ccaes_xts_encrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_gcm* ccaes_gcm_encrypt_mode(void) { - return &ccaes_gcm_encrypt; +const struct ccmode_ecb* ccaes_ecb_encrypt_mode(void) { + return &ccaes_ecb_encrypt_info; }; -const struct ccmode_ccm *ccaes_ccm_encrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_ecb *ccaes_ecb_decrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_cbc *ccaes_cbc_decrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_cfb *ccaes_cfb_decrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_cfb8 *ccaes_cfb8_decrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_xts *ccaes_xts_decrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -const struct ccmode_gcm* ccaes_gcm_decrypt_mode(void) { - return &ccaes_gcm_decrypt; +const struct ccmode_ecb* ccaes_ecb_decrypt_mode(void) { + return &ccaes_ecb_decrypt_info; }; -const struct ccmode_ccm *ccaes_ccm_decrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} +static const uint8_t ccaes_s_box[] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, +}; -const struct ccmode_ctr *ccaes_ctr_crypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} +static const uint8_t ccaes_s_box_inverse[] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, +}; -const struct ccmode_ofb *ccaes_ofb_crypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} +static const uint8_t gmul_2[] = { + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, + 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, + 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, + 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, + 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, + 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, + 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, + 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, + 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, + 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, + 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, + 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5, +}; -const struct ccmode_siv *ccaes_siv_encrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} +static const uint8_t gmul_3[] = { + 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, + 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, + 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, + 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, + 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, + 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, + 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, + 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, + 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, + 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, + 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, + 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, + 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, + 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, + 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, + 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a, +}; -const struct ccmode_siv *ccaes_siv_decrypt_mode(void) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} +static const uint8_t gmul_9[] = { + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, + 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, + 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, + 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, + 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, + 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, + 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, + 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, + 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, + 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, + 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, + 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, + 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, + 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, + 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46, +}; + +static const uint8_t gmul_11[] = { + 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, + 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, + 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, + 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, + 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, + 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, + 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, + 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, + 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, + 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, + 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, + 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, + 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, + 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, + 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, + 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3, +}; + +static const uint8_t gmul_13[] = { + 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, + 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, + 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, + 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, + 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, + 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, + 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, + 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, + 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, + 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, + 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, + 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, + 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, + 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, + 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, + 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97, +}; + +static const uint8_t gmul_14[] = { + 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, + 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, + 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, + 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, + 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, + 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, + 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, + 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, + 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, + 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, + 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, + 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, + 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, + 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, + 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, + 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d, +}; + + +static const uint8_t ccaes_round_constant[] = { + 0x01, + 0x02, + 0x04, + 0x08, + 0x10, + 0x20, + 0x40, + 0x80, + 0x1b, + 0x36, +}; + +CC_INLINE +size_t ccaes_round_count(const size_t key_len) { + if (key_len == 16) + return 10; + if (key_len == 24) + return 12; + if (key_len == 32) + return 14; + return 0; +}; + +CC_INLINE +ccaes_word_t ccaes_rot_word(const ccaes_word_t word) { + return (ccaes_word_t) { + .bytes = { word.bytes[1], word.bytes[2], word.bytes[3], word.bytes[0] }, + }; +}; + +CC_INLINE +ccaes_word_t ccaes_xor_word(const ccaes_word_t x, const ccaes_word_t y) { + return (ccaes_word_t) { + .bytes = { x.bytes[0] ^ y.bytes[0], x.bytes[1] ^ y.bytes[1], x.bytes[2] ^ y.bytes[2], x.bytes[3] ^ y.bytes[3] }, + }; +}; + +CC_INLINE +void ccaes_sub_bytes(const size_t len, const uint8_t* const in, uint8_t* const out) { + for (size_t i = 0; i < len; ++i) + out[i] = ccaes_s_box[in[i]]; +}; + +CC_INLINE +void ccaes_sub_bytes_inverse(const size_t len, const uint8_t* const in, uint8_t* const out) { + for (size_t i = 0; i < len; ++i) + out[i] = ccaes_s_box_inverse[in[i]]; +}; + +CC_INLINE +void ccaes_shift_rows(ccaes_state_t* state) { + // i = current row index AND number of times to shift left + for (uint8_t i = 0; i < 4; ++i) { + // shifter: shifts the row left once each iteration + for (uint8_t j = 0; j < i; ++j) { + uint8_t tmp = state->bytes[i][0]; + state->bytes[i][0] = state->bytes[i][1]; + state->bytes[i][1] = state->bytes[i][2]; + state->bytes[i][2] = state->bytes[i][3]; + state->bytes[i][3] = tmp; + } + } +}; + +CC_INLINE +void ccaes_shift_rows_inverse(ccaes_state_t* state) { + // i = current row index AND number of times to shift right + for (uint8_t i = 0; i < 4; ++i) { + // shifter: shifts the row right once each iteration + for (uint8_t j = 0; j < i; ++j) { + uint8_t tmp = state->bytes[i][3]; + state->bytes[i][3] = state->bytes[i][2]; + state->bytes[i][2] = state->bytes[i][1]; + state->bytes[i][1] = state->bytes[i][0]; + state->bytes[i][0] = tmp; + } + } +}; + +CC_INLINE +void ccaes_mix_columns(ccaes_state_t* state) { + // https://en.wikipedia.org/wiki/Rijndael_MixColumns#Implementation_example + + ccaes_state_t result = {0}; + + // hopefully the compiler is smart enough to unroll this loop + for (uint8_t i = 0; i < 4; ++i) { + #define GF1(index) (state->bytes[index][i]) + #define GF2(index) (gmul_2[GF1(index)]) + #define GF3(index) (gmul_3[GF1(index)]) + + result.bytes[0][i] = GF2(0) ^ GF3(1) ^ GF1(2) ^ GF1(3); + result.bytes[1][i] = GF1(0) ^ GF2(1) ^ GF3(2) ^ GF1(3); + result.bytes[2][i] = GF1(0) ^ GF1(1) ^ GF2(2) ^ GF3(3); + result.bytes[3][i] = GF3(0) ^ GF1(1) ^ GF1(2) ^ GF2(3); + + #undef GF1 + #undef GF2 + #undef GF3 + } + + *state = result; +}; + +CC_INLINE +void ccaes_mix_columns_inverse(ccaes_state_t* state) { + // https://en.wikipedia.org/wiki/Rijndael_MixColumns#InverseMixColumns + + ccaes_state_t result = {0}; + + for (uint8_t i = 0; i < 4; ++i) { + #define GF1(index) (state->bytes[index][i]) + #define GF2(index) (gmul_2[GF1(index)]) + #define GF9(index) (gmul_9[GF1(index)]) + #define GF11(index) (gmul_11[GF1(index)]) + #define GF13(index) (gmul_13[GF1(index)]) + #define GF14(index) (gmul_14[GF1(index)]) + + result.bytes[0][i] = GF14(0) ^ GF11(1) ^ GF13(2) ^ GF9(3); + result.bytes[1][i] = GF9(0) ^ GF14(1) ^ GF11(2) ^ GF13(3); + result.bytes[2][i] = GF13(0) ^ GF9(1) ^ GF14(2) ^ GF11(3); + result.bytes[3][i] = GF11(0) ^ GF13(1) ^ GF9(2) ^ GF14(3); + + #undef GF1 + #undef GF2 + #undef GF9 + #undef GF11 + #undef GF13 + #undef GF14 + } + + *state = result; +}; + +CC_INLINE +void ccaes_add_round_key(ccaes_state_t* state, const ccaes_word_t* const round_key) { + for (uint8_t i = 0; i < 4; ++i) + for (uint8_t j = 0; j < 4; ++j) + state->bytes[j][i] ^= round_key[i].bytes[j]; +}; + +CC_INLINE +int ccaes_expand_key(const size_t key_len, const uint8_t* const key, ccaes_word_t* const expanded_keys) { + const size_t Nr = ccaes_round_count(key_len); + const size_t Nk = key_len / 4; + ccaes_word_t tmp = {0}; + + for (size_t i = 0; i < Nk; ++i) + expanded_keys[i] = (ccaes_word_t) { .bytes = { key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3], }, }; + + for (size_t i = Nk; i < 4 * (Nr + 1); ++i) { + tmp = expanded_keys[i - 1]; + + if (i % Nk == 0) { + tmp = ccaes_rot_word(tmp); + ccaes_sub_bytes(4, tmp.bytes, tmp.bytes); + tmp.bytes[0] ^= ccaes_round_constant[(i / Nk) - 1]; + } else if (Nk > 6 && i % Nk == 4) { + ccaes_sub_bytes(4, tmp.bytes, tmp.bytes); + } + + expanded_keys[i] = ccaes_xor_word(expanded_keys[i - Nk], tmp); + } + + return 0; +}; + +static int ccaes_ecb_init(const struct ccmode_ecb* info, ccecb_ctx* _ctx, size_t key_size, const void* key) { + int status = CCERR_OK; + struct the_real_ccecb_ctx* ctx = (struct the_real_ccecb_ctx*)_ctx; + + // validate the key size and determine round count + ctx->round_count = ccaes_round_count(key_size); + if (ctx->round_count == 0) + return CCERR_PARAMETER; // i'm guessing that's the right error code + + // initialize the context by performing key expansion + status = ccaes_expand_key(key_size, key, (ccaes_word_t*)ctx->round_keys); + + return status; +}; + +static int ccaes_ecb_encrypt(const ccecb_ctx* _ctx, size_t block_count, const void* in, void* out) { + const uint8_t* input = in; + uint8_t* output = out; + struct the_real_ccecb_ctx* ctx = (struct the_real_ccecb_ctx*)_ctx; + + for (size_t block_index = 0; block_index < block_count; ++block_index) { + ccaes_state_t state = { + .bytes = { + { input[ 0], input[ 4], input[ 8], input[12], }, + { input[ 1], input[ 5], input[ 9], input[13], }, + { input[ 2], input[ 6], input[10], input[14], }, + { input[ 3], input[ 7], input[11], input[15], }, + }, + }; + + ccaes_add_round_key(&state, &ctx->round_keys[0]); + + for (uint8_t round = 1; round < ctx->round_count; ++round) { + ccaes_sub_bytes(16, (const uint8_t*)state.bytes, (uint8_t*)state.bytes); + ccaes_shift_rows(&state); + ccaes_mix_columns(&state); + ccaes_add_round_key(&state, &ctx->round_keys[4 * round]); + } + + ccaes_sub_bytes(16, (const uint8_t*)state.bytes, (uint8_t*)state.bytes); + ccaes_shift_rows(&state); + ccaes_add_round_key(&state, &ctx->round_keys[4 * ctx->round_count]); + + for (uint8_t i = 0; i < 4; ++i) + for (uint8_t j = 0; j < 4; ++j) + output[(i * 4) + j] = state.bytes[j][i]; + + input += 16; + output += 16; + } + + return CCERR_OK; +}; + +static int ccaes_ecb_decrypt(const ccecb_ctx* _ctx, size_t block_count, const void* in, void* out) { + const uint8_t* input = in; + uint8_t* output = out; + struct the_real_ccecb_ctx* ctx = (struct the_real_ccecb_ctx*)_ctx; + + for (size_t block_index = 0; block_index < block_count; ++block_index) { + ccaes_state_t state = { + .bytes = { + { input[ 0], input[ 4], input[ 8], input[12], }, + { input[ 1], input[ 5], input[ 9], input[13], }, + { input[ 2], input[ 6], input[10], input[14], }, + { input[ 3], input[ 7], input[11], input[15], }, + }, + }; + + ccaes_add_round_key(&state, &ctx->round_keys[4 * ctx->round_count]); + ccaes_shift_rows_inverse(&state); + ccaes_sub_bytes_inverse(16, (const uint8_t*)state.bytes, (uint8_t*)state.bytes); + + for (uint8_t round = ctx->round_count - 1; round >= 1; --round) { + ccaes_add_round_key(&state, &ctx->round_keys[4 * round]); + ccaes_mix_columns_inverse(&state); + ccaes_shift_rows_inverse(&state); + ccaes_sub_bytes_inverse(16, (const uint8_t*)state.bytes, (uint8_t*)state.bytes); + } + + ccaes_add_round_key(&state, &ctx->round_keys[0]); + + for (uint8_t i = 0; i < 4; ++i) + for (uint8_t j = 0; j < 4; ++j) + output[(i * 4) + j] = state.bytes[j][i]; + + input += 16; + output += 16; + } + + return CCERR_OK; +}; + +const struct ccmode_siv* ccaes_siv_encrypt_mode(void) { + CC_STUB(NULL); +}; + +const struct ccmode_siv* ccaes_siv_decrypt_mode(void) { + CC_STUB(NULL); +}; diff --git a/src/ccaes_extra.c b/src/ccaes_extra.c deleted file mode 100644 index cc29093..0000000 --- a/src/ccaes_extra.c +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include - -CC_INLINE -int ccaes_expand_key(const size_t key_len, const uint8_t* const key, ccaes_word_t* const expanded_keys) { - const size_t Nr = ccaes_round_count(key_len); - const size_t Nk = key_len / 4; - ccaes_word_t tmp = {0}; - - for (size_t i = 0; i < Nk; ++i) - expanded_keys[i] = (ccaes_word_t) { .bytes = { key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3], }, }; - - for (size_t i = Nk; i < 4 * (Nr + 1); ++i) { - tmp = expanded_keys[i - 1]; - - if (i % Nk == 0) { - tmp = ccaes_rot_word(tmp); - ccaes_sub_bytes(4, tmp.bytes, tmp.bytes); - tmp.bytes[0] ^= ccaes_round_constant[(i / Nk) - 1]; - } else if (Nk > 6 && i % Nk == 4) { - ccaes_sub_bytes(4, tmp.bytes, tmp.bytes); - } - - expanded_keys[i] = ccaes_xor_word(expanded_keys[i - Nk], tmp); - } - - return 0; -}; - -ccaes_block_128_t ccaes_block_cipher(const ccaes_block_128_t input, const size_t key_len, const uint8_t* const key) { - if (key_len != 16 && key_len != 24 && key_len != 32) - return (ccaes_block_128_t) {0}; - - const size_t Nr = ccaes_round_count(key_len); - - ccaes_word_t expanded_keys[4 * (Nr + 1)]; - memset(expanded_keys, 0, sizeof expanded_keys); - - ccaes_expand_key(key_len, key, expanded_keys); - - ccaes_state_t state = { - .bytes = { - { input.block[15], input.block[11], input.block[ 7], input.block[ 3], }, - { input.block[14], input.block[10], input.block[ 6], input.block[ 2], }, - { input.block[13], input.block[ 9], input.block[ 5], input.block[ 1], }, - { input.block[12], input.block[ 8], input.block[ 4], input.block[ 0], }, - }, - }; - - state = ccaes_add_round_key(state, &expanded_keys[0]); - - for (size_t round = 1; round < Nr; ++round) { - ccaes_sub_bytes(16, (const uint8_t*)state.bytes, (uint8_t*)state.bytes); - state = ccaes_shift_rows(state); - state = ccaes_mix_columns(state); - state = ccaes_add_round_key(state, &expanded_keys[4 * round]); - } - - ccaes_sub_bytes(16, (const uint8_t*)state.bytes, (uint8_t*)state.bytes); - state = ccaes_shift_rows(state); - state = ccaes_add_round_key(state, &expanded_keys[4 * Nr]); - - return (ccaes_block_128_t) { - .block = { - state.bytes[3][3], - state.bytes[2][3], - state.bytes[1][3], - state.bytes[0][3], - - state.bytes[3][2], - state.bytes[2][2], - state.bytes[1][2], - state.bytes[0][2], - - state.bytes[3][1], - state.bytes[2][1], - state.bytes[1][1], - state.bytes[0][1], - - state.bytes[3][0], - state.bytes[2][0], - state.bytes[1][0], - state.bytes[0][0], - }, - }; -}; diff --git a/src/cccbc.c b/src/cccbc.c new file mode 100644 index 0000000..8348544 --- /dev/null +++ b/src/cccbc.c @@ -0,0 +1,67 @@ +#include + +int ccmode_cbc_init(const struct ccmode_cbc* cbc, cccbc_ctx* _ctx, size_t rawkey_len, const void* rawkey) { + int status = CCERR_OK; + struct _ccmode_cbc_key* ctx = (struct _ccmode_cbc_key*)_ctx; + ctx->ecb = cbc->custom; + + ccecb_ctx* ecb_ctx = (ccecb_ctx*)((char*)ctx->u + ccn_sizeof_size(ctx->ecb->block_size)); + if ((status = ctx->ecb->init(ctx->ecb, ecb_ctx, rawkey_len, rawkey)) != CCERR_OK) + goto out; + + // `_ccmode_cbc_key` includes space for a single block in the context, which i *think* is supposed to be scratch space. + cc_zero(ccn_sizeof_size(ctx->ecb->block_size), ctx->u); + +out: + return status; +}; + +int ccmode_cbc_encrypt(const cccbc_ctx* _ctx, cccbc_iv* _iv, size_t nblocks, const void* in, void* out) { + int status = CCERR_OK; + struct _ccmode_cbc_key* ctx = (struct _ccmode_cbc_key*)_ctx; + ccecb_ctx* ecb_ctx = (ccecb_ctx*)((char*)ctx->u + ccn_sizeof_size(ctx->ecb->block_size)); + const uint8_t* input = in; + uint8_t* output = out; + uint8_t* scratch_space = (uint8_t*)ctx->u; + uint8_t* iv = (uint8_t*)_iv; + + for (size_t i = 0; i < nblocks; ++i) { + cc_xor(ctx->ecb->block_size, scratch_space, input, iv); + + if ((status = ctx->ecb->ecb(ecb_ctx, 1, scratch_space, output)) != CCERR_OK) + goto out; + + cc_copy(ctx->ecb->block_size, iv, output); + + input += ctx->ecb->block_size; + output += ctx->ecb->block_size; + } + +out: + return status; +}; + +int ccmode_cbc_decrypt(const cccbc_ctx* _ctx, cccbc_iv* _iv, size_t nblocks, const void* in, void* out) { + int status = CCERR_OK; + struct _ccmode_cbc_key* ctx = (struct _ccmode_cbc_key*)_ctx; + ccecb_ctx* ecb_ctx = (ccecb_ctx*)((char*)ctx->u + ccn_sizeof_size(ctx->ecb->block_size)); + const uint8_t* input = in; + uint8_t* output = out; + uint8_t* scratch_space = (uint8_t*)ctx->u; + uint8_t* iv = (uint8_t*)_iv; + + for (size_t i = 0; i < nblocks; ++i) { + if ((status = ctx->ecb->ecb(ecb_ctx, 1, input, scratch_space)) != CCERR_OK) + goto out; + + cc_xor(ctx->ecb->block_size, output, scratch_space, iv); + + cc_copy(ctx->ecb->block_size, iv, input); + + input += ctx->ecb->block_size; + output += ctx->ecb->block_size; + } + +out: + return status; +}; diff --git a/src/ccccm.c b/src/ccccm.c new file mode 100644 index 0000000..501a986 --- /dev/null +++ b/src/ccccm.c @@ -0,0 +1,30 @@ +#include +#include + +int ccmode_ccm_init(const struct ccmode_ccm* ccm, ccccm_ctx* _ctx, size_t rawkey_len, const void* rawkey) { + CC_STUB_ERR(); +}; + +int ccmode_ccm_set_iv(ccccm_ctx* _ctx, ccccm_nonce* _nonce_ctx, size_t nonce_len, const void* nonce, size_t mac_size, size_t auth_len, size_t data_len) { + CC_STUB_ERR(); +}; + +int ccmode_ccm_cbcmac(ccccm_ctx* _ctx, ccccm_nonce* _nonce_ctx, size_t nbytes, const void* in) { + CC_STUB_ERR(); +}; + +int ccmode_ccm_decrypt(ccccm_ctx *_ctx, ccccm_nonce* _nonce_ctx, size_t nbytes, const void* in, void* out) { + CC_STUB_ERR(); +}; + +int ccmode_ccm_encrypt(ccccm_ctx *_ctx, ccccm_nonce* _nonce_ctx, size_t nbytes, const void* in, void* out) { + CC_STUB_ERR(); +}; + +int ccmode_ccm_finalize(ccccm_ctx* _ctx, ccccm_nonce* _nonce_ctx, void* mac) { + CC_STUB_ERR(); +}; + +int ccmode_ccm_reset(ccccm_ctx* _ctx, ccccm_nonce* _nonce_ctx) { + CC_STUB_ERR(); +}; diff --git a/src/cccfb.c b/src/cccfb.c new file mode 100644 index 0000000..26cf245 --- /dev/null +++ b/src/cccfb.c @@ -0,0 +1,14 @@ +#include +#include + +int ccmode_cfb_init(const struct ccmode_cfb* cfb, cccfb_ctx* _ctx, size_t rawkey_len, const void* rawkey, const void* iv) { + CC_STUB_ERR(); +}; + +int ccmode_cfb_decrypt(cccfb_ctx* _ctx, size_t nbytes, const void* in, void* out) { + CC_STUB_ERR(); +}; + +int ccmode_cfb_encrypt(cccfb_ctx* _ctx, size_t nbytes, const void* in, void* out) { + CC_STUB_ERR(); +}; diff --git a/src/cccfb8.c b/src/cccfb8.c new file mode 100644 index 0000000..472f525 --- /dev/null +++ b/src/cccfb8.c @@ -0,0 +1,14 @@ +#include +#include + +int ccmode_cfb8_init(const struct ccmode_cfb8* cfb8, cccfb8_ctx* _ctx, size_t rawkey_len, const void* rawkey, const void* iv) { + CC_STUB_ERR(); +}; + +int ccmode_cfb8_decrypt(cccfb8_ctx* _ctx, size_t nbytes, const void* in, void* out) { + CC_STUB_ERR(); +}; + +int ccmode_cfb8_encrypt(cccfb8_ctx* _ctx, size_t nbytes, const void* in, void* out) { + CC_STUB_ERR(); +}; diff --git a/src/ccckg.c b/src/ccckg.c new file mode 100644 index 0000000..afdc8a6 --- /dev/null +++ b/src/ccckg.c @@ -0,0 +1,38 @@ +#include +#include + +size_t ccckg_sizeof_commitment(ccec_const_cp_t cp, const struct ccdigest_info* digest_info) { + CC_STUB(0); +}; + +size_t ccckg_sizeof_share(ccec_const_cp_t cp, const struct ccdigest_info* digest_info) { + CC_STUB(0); +}; + +size_t ccckg_sizeof_opening(ccec_const_cp_t cp, const struct ccdigest_info* digest_info) { + CC_STUB(0); +}; + +size_t ccckg_sizeof_ctx(ccec_const_cp_t cp, const struct ccdigest_info* digest_info) { + CC_STUB(0); +}; + +int ccckg_init(ccckg_ctx_t ctx, ccec_const_cp_t cp, const struct ccdigest_info* digest_info, struct ccrng_state* rng) { + CC_STUB_ERR(); +}; + +int ccckg_contributor_commit(ccckg_ctx_t ctx, size_t commitment_length, void* commitment) { + CC_STUB_ERR(); +}; + +int ccckg_contributor_finish(ccckg_ctx_t ctx, size_t share_length, const void* share, size_t opening_length, void* opening, ccec_pub_ctx_t ec_pub, size_t shared_key_length, void* shared_key) { + CC_STUB_ERR(); +}; + +int ccckg_owner_finish(ccckg_ctx_t ctx, size_t opening_length, const void* opening, ccec_full_ctx_t ec_full, size_t shared_key_length, void* shared_key) { + CC_STUB_ERR(); +}; + +int ccckg_owner_generate_share(ccckg_ctx_t ctx, size_t commitment_length, const void* commitment, size_t share_length, void* share) { + CC_STUB_ERR(); +}; diff --git a/src/ccctr.c b/src/ccctr.c new file mode 100644 index 0000000..c583c7f --- /dev/null +++ b/src/ccctr.c @@ -0,0 +1,14 @@ +#include +#include + +int ccmode_ctr_init(const struct ccmode_ctr* ctr, ccctr_ctx* _ctx, size_t rawkey_len, const void* rawkey, const void* iv) { + CC_STUB_ERR(); +}; + +int ccmode_ctr_crypt(ccctr_ctx* ctx, size_t nbytes, const void* in, void* out) { + CC_STUB_ERR(); +}; + +int ccmode_ctr_setctr(const struct ccmode_ctr* ctr, ccctr_ctx* ctx, const void* iv) { + CC_STUB_ERR(); +}; diff --git a/src/ccgcm.c b/src/ccgcm.c index 6584d3f..f5729f1 100644 --- a/src/ccgcm.c +++ b/src/ccgcm.c @@ -1,37 +1,299 @@ -#include +#include +#include +#include +#include #include +#include -// `input` is assumed to be in normal byte order (big-endian; most significant byte at lowest address) -ccaes_block_128_t ccgcm_ghash_128(const ccaes_block_128_t hash_subkey, const size_t input_len, const uint8_t* const input) { - const size_t m = (input_len + 15) / 16; - ccaes_block_128_t y = {0}; +#define CCGCM_MODE_INITIALIZE 0 +#define CCGCM_MODE_IV 1 +#define CCGCM_MODE_AAD 2 +#define CCGCM_MODE_CIPHERTEXT 3 +#define CCGCM_MODE_FINALIZE 4 - for (size_t i = 0; i < m; ++i) { - const ccaes_block_128_t x = ccaes_normalize_128(input_len - (i * 16), input + (i * 16)); - y = ccaes_multiply_128(ccaes_xor_128(y, x), hash_subkey); +#define CTX_U_BUFFER(index) ((uint8_t*)ctx->u + (index * ccn_sizeof_size(ctx->ecb->block_size))) +#define CTX_U_BLOCK(index) ((cc128_t*)CTX_U_BUFFER(index)) + +CC_INLINE +int perform_block_cipher(struct _ccmode_gcm_key* ctx, const cc128_t* input, cc128_t* output) { + int status = CCERR_OK; + uint8_t* temp = CTX_U_BUFFER(4); + cc128_store_be(input, 16, temp); + if ((status = ctx->ecb->ecb(ctx->ecb_key, 1, temp, temp)) != CCERR_OK) + goto out; + cc128_load_be(16, temp, output); +out: + return status; +}; + +int ccmode_gcm_init(const struct ccmode_gcm* gcm, ccgcm_ctx* _ctx, size_t rawkey_len, const void* rawkey) { + int status = CCERR_OK; + struct _ccmode_gcm_key* ctx = (struct _ccmode_gcm_key*)_ctx; + cc128_t* hash_subkey = (cc128_t*)ctx->H; + + ctx->ecb = gcm->custom; + ctx->ecb_key = ctx->u + (5 * ccn_sizeof_size(ctx->ecb->block_size)); + + if ((status = ctx->ecb->init(ctx->ecb, ctx->ecb_key, rawkey_len, rawkey)) != CCERR_OK) + goto out; + + ctx->encdec = gcm->encdec; + ctx->flags = 0; + ctx->buf_nbytes = 0; + ctx->aad_nbytes = 0; + ctx->text_nbytes = 0; + ctx->state = CCGCM_MODE_INITIALIZE; + + cc_zero(5 * ccn_sizeof_size(ctx->ecb->block_size), CTX_U_BUFFER(0)); + + cc_zero(sizeof(ctx->H), ctx->H); + cc_zero(sizeof(ctx->X), ctx->X); + cc_zero(sizeof(ctx->Y), ctx->Y); + cc_zero(sizeof(ctx->Y_0), ctx->Y_0); + cc_zero(sizeof(ctx->buf), ctx->buf); + + if ((status = perform_block_cipher(ctx, hash_subkey, hash_subkey)) != CCERR_OK) + goto out; + +out: + return status; +}; + +int ccmode_gcm_set_iv(ccgcm_ctx* _ctx, size_t iv_size, const void* iv) { + int status = CCERR_OK; + struct _ccmode_gcm_key* ctx = (struct _ccmode_gcm_key*)_ctx; + cc128_t* initial_cb = (cc128_t*)ctx->Y_0; + cc128_t* hash_subkey = (cc128_t*)ctx->H; + cc128_t* cache = (cc128_t*)ctx->buf; + + const uint8_t* iv_buf = iv; + + if (ctx->state == CCGCM_MODE_INITIALIZE) + ctx->state = CCGCM_MODE_IV; + + if (ctx->state != CCGCM_MODE_IV) + return CCMODE_INVALID_CALL_SEQUENCE; + + for (size_t i = 0; i < iv_size; ++i) { + // `aad_nbytes` is used as the IV length when we're in IV mode + const size_t current_block_index = 15 - (ctx->aad_nbytes % 16); + + cache->bytes[current_block_index] = iv_buf[i]; + + if (current_block_index == 0) { + cc128_xor(initial_cb, cache, initial_cb); + cc128_mul(initial_cb, hash_subkey, initial_cb); + cc_zero(16, cache->bytes); + } + + ++ctx->aad_nbytes; } - return y; + return status; +}; + +CC_INLINE +int ccgcm_process_iv(struct _ccmode_gcm_key* ctx) { + int status = CCERR_OK; + uint8_t* current_iv = CTX_U_BUFFER(0); + cc128_t* initial_cb = (cc128_t*)ctx->Y_0; + cc128_t* hash_subkey = (cc128_t*)ctx->H; + cc128_t* cache = (cc128_t*)ctx->buf; + cc128_t* cb = (cc128_t*)ctx->Y; + cc128_t* processed_cb = CTX_U_BLOCK(1); + + if (ctx->aad_nbytes == 12) { + // we only do this when IV is 12 bytes because the only time + // the IV is incremented for reuse is when it's set through + // `ccgcm_init_with_iv` + for (size_t i = 0; i < 12; ++i) + current_iv[i] = cache->bytes[15 - i]; + + cache->bytes[0] = 1; + cc_copy(16, initial_cb->bytes, cache->bytes); + } else { + if (ctx->aad_nbytes % 16 != 0) { + cc128_xor(initial_cb, cache, initial_cb); + cc128_mul(initial_cb, hash_subkey, initial_cb); + cc_zero(16, cache->bytes); + } + + const size_t iv_bits = ctx->aad_nbytes * 8; + + for (size_t i = 0; i < sizeof(size_t); ++i) + cache->bytes[i] = (iv_bits >> (i * 8)) & 0xff; + + cc128_xor(initial_cb, cache, initial_cb); + cc128_mul(initial_cb, hash_subkey, initial_cb); + } + + cc_zero(16, cache->bytes); + + cc128_lsw_increment(initial_cb, cb); + if ((status = perform_block_cipher(ctx, cb, processed_cb)) != CCERR_OK) + return status; + + ctx->aad_nbytes = 0; + + return status; +}; + +int ccmode_gcm_aad(ccgcm_ctx* _ctx, size_t buf_len, const void* in) { + int status = CCERR_OK; + struct _ccmode_gcm_key* ctx = (struct _ccmode_gcm_key*)_ctx; + const uint8_t* in_buf = in; + cc128_t* cache = (cc128_t*)ctx->buf; + cc128_t* hash = (cc128_t*)ctx->X; + cc128_t* hash_subkey = (cc128_t*)ctx->H; + + if (ctx->state == CCGCM_MODE_IV) { + if ((status = ccgcm_process_iv(ctx)) != CCERR_OK) + goto out; + ctx->state = CCGCM_MODE_AAD; + } + + if (ctx->state != CCGCM_MODE_AAD) + return CCMODE_INVALID_CALL_SEQUENCE; + + for (size_t i = 0; i < buf_len; ++i) { + const size_t current_block_index = 15 - (ctx->aad_nbytes % 16); + + cache->bytes[current_block_index] = in_buf[i]; + + if (current_block_index == 0) { + cc128_xor(hash, cache, hash); + cc128_mul(hash, hash_subkey, hash); + cc_zero(16, cache->bytes); + } + + ++ctx->aad_nbytes; + } + +out: + return status; +}; + +CC_INLINE +int ccgcm_process_aad(struct _ccmode_gcm_key* ctx) { + cc128_t* cache = (cc128_t*)ctx->buf; + cc128_t* hash = (cc128_t*)ctx->X; + cc128_t* hash_subkey = (cc128_t*)ctx->H; + + if (ctx->aad_nbytes % 16 != 0) { + cc128_xor(hash, cache, hash); + cc128_mul(hash, hash_subkey, hash); + cc_zero(16, cache->bytes); + } + + return CCERR_OK; +}; + +int ccmode_gcm_encrypt(ccgcm_ctx* _ctx, size_t buf_len, const void* in, void* out) { + int status = CCERR_OK; + struct _ccmode_gcm_key* ctx = (struct _ccmode_gcm_key*)_ctx; + + const uint8_t* in_buf = in; + uint8_t* out_buf = out; + bool decrypting = ctx->encdec == CCMODE_GCM_DECRYPTOR; + cc128_t* cache = (cc128_t*)ctx->buf; + cc128_t* hash = (cc128_t*)ctx->X; + cc128_t* hash_subkey = (cc128_t*)ctx->H; + cc128_t* cb = (cc128_t*)ctx->Y; + cc128_t* processed_cb = CTX_U_BLOCK(1); + + if (ctx->state == CCGCM_MODE_IV) { + if ((status = ccgcm_process_iv(ctx)) != CCERR_OK) + return status; + ctx->state = CCGCM_MODE_AAD; + } + + if (ctx->state == CCGCM_MODE_AAD) { + if ((status = ccgcm_process_aad(ctx)) != CCERR_OK) + return status; + ctx->state = CCGCM_MODE_CIPHERTEXT; + } + + if (ctx->state != CCGCM_MODE_CIPHERTEXT) + return CCMODE_INVALID_CALL_SEQUENCE; + + for (size_t i = 0; i < buf_len; ++i) { + const size_t current_block_index = 15 - (ctx->text_nbytes % 16); + + if (decrypting) { + cache->bytes[current_block_index] = in_buf[i]; + } + out_buf[i] = in_buf[i] ^ processed_cb->bytes[current_block_index]; + if (!decrypting) { + cache->bytes[current_block_index] = out_buf[i]; + } + + if (current_block_index == 0) { + cc128_xor(hash, cache, hash); + cc128_mul(hash, hash_subkey, hash); + cc_zero(16, cache->bytes); + } + + ++ctx->text_nbytes; + + if (ctx->text_nbytes % 16 == 0) { + cc128_lsw_increment(cb, cb); + if ((status = perform_block_cipher(ctx, cb, processed_cb)) != CCERR_OK) + return status; + } + } + + return status; +}; + +int ccmode_gcm_decrypt(ccgcm_ctx* _ctx, size_t nbytes, const void* in, void* out) { + return ccmode_gcm_encrypt(_ctx, nbytes, in, out); +}; + +CC_INLINE +int ccgcm_process_ciphertext(struct _ccmode_gcm_key* ctx) { + cc128_t* cache = (cc128_t*)ctx->buf; + cc128_t* hash = (cc128_t*)ctx->X; + cc128_t* hash_subkey = (cc128_t*)ctx->H; + + if (ctx->text_nbytes % 16 != 0) { + cc128_xor(hash, cache, hash); + cc128_mul(hash, hash_subkey, hash); + cc_zero(16, cache->bytes); + } + + return CCERR_OK; }; // `input` is assumed to be in normal byte order (big-endian; most significant byte at lowest address) // `output` is in the same order as `input` -int ccgcm_gctr_128(const ccaes_block_cipher_function_t block_cipher_function, const size_t key_len, const uint8_t* const key, const ccaes_block_128_t icb, const size_t input_len, const uint8_t* const input, uint8_t* const output) { +CC_INLINE +int ccgcm_gctr_128(struct _ccmode_gcm_key* ctx, const size_t input_len, const uint8_t* const input, uint8_t* const output) { if (input_len == 0) - return 0; + return CCERR_OK; + int status = CCERR_OK; const size_t n = (input_len + 15) / 16; - ccaes_block_128_t cb = icb; + cc128_t* cache = (cc128_t*)ctx->buf; + cc128_t* hash = (cc128_t*)ctx->X; + cc128_t* hash_subkey = (cc128_t*)ctx->H; + cc128_t* cb = (cc128_t*)ctx->Y; + cc128_t* processed_cb = CTX_U_BLOCK(1); + cc128_t* temp = CTX_U_BLOCK(4); + cc128_t* initial_cb = (cc128_t*)ctx->Y_0; size_t current_len = input_len; const uint8_t* current_input = input; uint8_t* current_output = output; - for (size_t i = 0; i < n - 1; ++i) { - const ccaes_block_128_t x = ccaes_normalize_128(current_len, current_input); - const ccaes_block_128_t y = ccaes_xor_128(x, block_cipher_function(cb, key_len, key)); - ccaes_write_block_128(y, current_len, current_output); + cc_copy(16, cb->bytes, initial_cb->bytes); - cb = ccaes_increment_128(cb, 32); + for (size_t i = 0; i < n - 1; ++i) { + cc128_load_be(current_len, current_input, cache); + if ((status = perform_block_cipher(ctx, cb, processed_cb)) != CCERR_OK) + return status; + cc128_xor(cache, processed_cb, cache); + cc128_store_be(cache, current_len, current_output); + + cc128_lsw_increment(cb, cb); current_len -= 16; current_input += 16; @@ -39,264 +301,145 @@ int ccgcm_gctr_128(const ccaes_block_cipher_function_t block_cipher_function, co } const size_t final_block_bytes = input_len - ((n - 1) * 8); - const ccaes_block_128_t final_block = ccaes_normalize_128(current_len, current_input); - const ccaes_block_128_t final_y = ccaes_xor_128(final_block, ccaes_most_significant_bits_128(block_cipher_function(cb, key_len, key), final_block_bytes * 8)); - ccaes_write_block_128(final_y, current_len, current_output); + cc128_load_be(current_len, current_input, cache); - return 0; + if ((status = perform_block_cipher(ctx, cb, processed_cb)) != CCERR_OK) + return status; + cc128_msbits(processed_cb, final_block_bytes * 8, temp); + cc128_xor(cache, temp, cache); + cc128_store_be(cache, current_len, current_output); + + return status; }; -// -// ~~~actual AES-GCM implementation~~~ -// +int ccmode_gcm_finalize(ccgcm_ctx* _ctx, size_t tag_size, void* tag) { + int status = CCERR_OK; + struct _ccmode_gcm_key* ctx = (struct _ccmode_gcm_key*)_ctx; + cc128_t* cache = (cc128_t*)ctx->buf; + cc128_t* hash = (cc128_t*)ctx->X; + cc128_t* hash_subkey = (cc128_t*)ctx->H; + uint8_t* hash_buf = CTX_U_BUFFER(2); + uint8_t* result_buf = CTX_U_BUFFER(3); -int ccgcm_internal_init(const struct ccmode_gcm* gcm, ccgcm_ctx* ctx, size_t key_len, const void* key) { - ccgcm_state* state = (ccgcm_state*)ctx; - - // our block cipher function only accepts 128-bit, 192-bit, or 256-bit keys - if (key_len != 16 && key_len != 24 && key_len != 32) - return -1; - - *state = (ccgcm_state) {0}; - - state->decrypting = gcm->encdec == CCMODE_GCM_DECRYPTOR; - state->mode = CCGCM_MODE_INITIALIZE; - - state->key = key; - state->key_len = key_len; - - state->hash_subkey = ccaes_block_cipher((ccaes_block_128_t){0}, state->key_len, state->key); - - return 0; -}; - -void ccgcm_process_iv(ccgcm_state* state) { - if (state->total_iv_length == 12) { - // we only do this when IV is 12 bytes because the only time - // the IV is incremented for reuse is when it's set through - // `ccgcm_init_with_iv` - for (size_t i = 0; i < 12; ++i) - state->current_iv[i] = state->cache.block[15 - i]; - - state->cache.block[0] = 1; - state->initial_cb = state->cache; - } else { - if (state->total_iv_length % 16 != 0) { - state->initial_cb = ccaes_multiply_128(ccaes_xor_128(state->initial_cb, state->cache), state->hash_subkey); - state->cache = (ccaes_block_128_t) {0}; - } - - const size_t iv_bits = state->total_iv_length * 8; - ccaes_block_128_t length_block = {0}; - - for (size_t i = 0; i < sizeof(size_t); ++i) - length_block.block[i] = (iv_bits >> (i * 8)) & 0xff; - - state->initial_cb = ccaes_multiply_128(ccaes_xor_128(state->initial_cb, length_block), state->hash_subkey); + if (ctx->state == CCGCM_MODE_IV) { + if ((status = ccgcm_process_iv(ctx)) != CCERR_OK) + return status; + ctx->state = CCGCM_MODE_AAD; } - state->cache = (ccaes_block_128_t) {0}; + if (ctx->state == CCGCM_MODE_AAD) { + if ((status = ccgcm_process_aad(ctx)) != CCERR_OK) + return status; + ctx->state = CCGCM_MODE_CIPHERTEXT; + } - state->cb = ccaes_increment_128(state->initial_cb, 32); - state->processed_cb = ccaes_block_cipher(state->cb, state->key_len, state->key); -}; + if (ctx->state == CCGCM_MODE_CIPHERTEXT) { + if ((status = ccgcm_process_ciphertext(ctx)) != CCERR_OK) + return status; + ctx->state = CCGCM_MODE_FINALIZE; + } -int ccgcm_internal_set_iv(ccgcm_ctx* ctx, size_t iv_size, const void* iv) { - ccgcm_state* state = (ccgcm_state*)ctx; - - const uint8_t* iv_buf = iv; - - if (state->mode == CCGCM_MODE_INITIALIZE) - state->mode = CCGCM_MODE_IV; - - if (state->mode != CCGCM_MODE_IV) + if (ctx->state != CCGCM_MODE_FINALIZE) return CCMODE_INVALID_CALL_SEQUENCE; - for (size_t i = 0; i < iv_size; ++i) { - const size_t current_block_index = 15 - (state->total_iv_length % 16); - - state->cache.block[current_block_index] = iv_buf[i]; - - if (current_block_index == 0) { - state->initial_cb = ccaes_multiply_128(ccaes_xor_128(state->initial_cb, state->cache), state->hash_subkey); - state->cache = (ccaes_block_128_t) {0}; - } - - ++state->total_iv_length; - } - - return 0; -}; - -CC_INLINE -void ccgcm_process_aad(ccgcm_state* state) { - if (state->total_aad_length % 16 != 0) { - state->hash = ccaes_multiply_128(ccaes_xor_128(state->hash, state->cache), state->hash_subkey); - state->cache = (ccaes_block_128_t) {0}; - } -}; - -int ccgcm_internal_gmac(ccgcm_ctx* ctx, size_t buf_len, const void* in) { - ccgcm_state* state = (ccgcm_state*)ctx; - - const uint8_t* in_buf = in; - - if (state->mode == CCGCM_MODE_IV) { - ccgcm_process_iv(state); - state->mode = CCGCM_MODE_AAD; - } - - if (state->mode != CCGCM_MODE_AAD) - return CCMODE_INVALID_CALL_SEQUENCE; - - for (size_t i = 0; i < buf_len; ++i) { - const size_t current_block_index = 15 - (state->total_aad_length % 16); - - state->cache.block[current_block_index] = in_buf[i]; - - if (current_block_index == 0) { - state->hash = ccaes_multiply_128(ccaes_xor_128(state->hash, state->cache), state->hash_subkey); - state->cache = (ccaes_block_128_t) {0}; - } - - ++state->total_aad_length; - } - - return 0; -}; - -CC_INLINE -void ccgcm_process_ciphertext(ccgcm_state* state) { - if (state->total_cipher_length % 16 != 0) { - state->hash = ccaes_multiply_128(ccaes_xor_128(state->hash, state->cache), state->hash_subkey); - state->cache = (ccaes_block_128_t) {0}; - } -}; - -int ccgcm_internal_gcm(ccgcm_ctx* ctx, size_t buf_len, const void* in, void* out) { - ccgcm_state* state = (ccgcm_state*)ctx; - - const uint8_t* in_buf = in; - uint8_t* out_buf = out; - - if (state->mode == CCGCM_MODE_IV) { - ccgcm_process_iv(state); - state->mode = CCGCM_MODE_AAD; - } - - if (state->mode == CCGCM_MODE_AAD) { - ccgcm_process_aad(state); - state->mode = CCGCM_MODE_CIPHERTEXT; - } - - if (state->mode != CCGCM_MODE_CIPHERTEXT) - return CCMODE_INVALID_CALL_SEQUENCE; - - for (size_t i = 0; i < buf_len; ++i) { - const size_t current_block_index = 15 - (state->total_cipher_length % 16); - - out_buf[i] = in_buf[i] ^ state->processed_cb.block[current_block_index]; - - const uint8_t cipher_byte = state->decrypting ? in_buf[i] : out_buf[i]; - - state->cache.block[current_block_index] = cipher_byte; - - if (current_block_index == 0) { - state->hash = ccaes_multiply_128(ccaes_xor_128(state->hash, state->cache), state->hash_subkey); - state->cache = (ccaes_block_128_t) {0}; - } - - ++state->total_cipher_length; - - if (state->total_cipher_length % 16 == 0) { - state->cb = ccaes_increment_128(state->cb, 32); - state->processed_cb = ccaes_block_cipher(state->cb, state->key_len, state->key); - } - } - - return 0; -}; - -int ccgcm_internal_finalize(ccgcm_ctx* ctx, size_t tag_size, void* tag) { - ccgcm_state* state = (ccgcm_state*)ctx; - - if (state->mode == CCGCM_MODE_IV) { - ccgcm_process_iv(state); - state->mode = CCGCM_MODE_AAD; - } - - if (state->mode == CCGCM_MODE_AAD) { - ccgcm_process_aad(state); - state->mode = CCGCM_MODE_CIPHERTEXT; - } - - if (state->mode == CCGCM_MODE_CIPHERTEXT) { - ccgcm_process_ciphertext(state); - state->mode = CCGCM_MODE_FINALIZE; - } - - if (state->mode != CCGCM_MODE_FINALIZE) - return CCMODE_INVALID_CALL_SEQUENCE; - - const size_t aad_bits = state->total_aad_length * 8; - const size_t cipher_bits = state->total_cipher_length * 8; + const size_t aad_bits = ctx->aad_nbytes * 8; + const size_t cipher_bits = ctx->text_nbytes * 8; uint8_t* tag_buf = tag; - ccaes_block_128_t length_block = {0}; + for (size_t i = 0; i < sizeof(size_t); ++i) + cache->bytes[8 + i] = (aad_bits >> (i * 8)) & 0xff; for (size_t i = 0; i < sizeof(size_t); ++i) - length_block.block[8 + i] = (aad_bits >> (i * 8)) & 0xff; + cache->bytes[i] = (cipher_bits >> (i * 8)) & 0xff; - for (size_t i = 0; i < sizeof(size_t); ++i) - length_block.block[i] = (cipher_bits >> (i * 8)) & 0xff; + cc128_xor(hash, cache, hash); + cc128_mul(hash, hash_subkey, hash); - state->hash = ccaes_multiply_128(ccaes_xor_128(state->hash, length_block), state->hash_subkey); + cc128_store_be(hash, 16, hash_buf); + cc_zero(16, result_buf); - const uint8_t hash_buf[16] = { - state->hash.block[15], - state->hash.block[14], - state->hash.block[13], - state->hash.block[12], - state->hash.block[11], - state->hash.block[10], - state->hash.block[ 9], - state->hash.block[ 8], - state->hash.block[ 7], - state->hash.block[ 6], - state->hash.block[ 5], - state->hash.block[ 4], - state->hash.block[ 3], - state->hash.block[ 2], - state->hash.block[ 1], - state->hash.block[ 0], - }; + ccgcm_gctr_128(ctx, 16, hash_buf, result_buf); - uint8_t result_buf[16] = {0}; - - ccgcm_gctr_128(ccaes_block_cipher, state->key_len, state->key, state->initial_cb, sizeof hash_buf, hash_buf, result_buf); + if (ctx->encdec == CCMODE_GCM_DECRYPTOR) + status = cc_cmp_safe(tag_size < 16 ? tag_size : 16, tag_buf, result_buf) == 0 ? CCERR_OK : CCMODE_INTEGRITY_FAILURE; for (size_t i = 0; i < 16 && i < tag_size; ++i) tag_buf[i] = result_buf[i]; + return status; +}; + +int ccmode_gcm_reset(ccgcm_ctx* _ctx) { + struct _ccmode_gcm_key* ctx = (struct _ccmode_gcm_key*)_ctx; + + // *don't* zero the ECB key (it's preserved across resets) + //cc_zero(ccn_sizeof_size(ctx->ecb->size), ctx->ecb_key); + + ctx->buf_nbytes = 0; + ctx->aad_nbytes = 0; + ctx->text_nbytes = 0; + ctx->state = CCGCM_MODE_INITIALIZE; + + // skip the first block because that contains the current IV (which is preserved across resets) + cc_zero(4 * ccn_sizeof_size(ctx->ecb->block_size), CTX_U_BUFFER(1)); + + // *don't* zero the hash subkey (it's preserved across resets) + //cc_zero(sizeof(ctx->H), ctx->H); + cc_zero(sizeof(ctx->X), ctx->X); + cc_zero(sizeof(ctx->Y), ctx->Y); + cc_zero(sizeof(ctx->Y_0), ctx->Y_0); + cc_zero(sizeof(ctx->buf), ctx->buf); + + return CCERR_OK; +}; + +int ccgcm_init_with_iv(const struct ccmode_gcm* mode, ccgcm_ctx* ctx, size_t key_nbytes, const void* key, const void* iv) { + int status = CCERR_OK; + + if ((status = ccgcm_init(mode, ctx, key_nbytes, key)) != CCERR_OK) + return status; + + if ((status = ccgcm_set_iv(mode, ctx, 12, iv)) != CCERR_OK) + return status; + return 0; }; -int ccgcm_internal_reset(ccgcm_ctx* ctx) { - ccgcm_state* state = (ccgcm_state*)ctx; +int ccgcm_inc_iv(const struct ccmode_gcm* mode, ccgcm_ctx* _ctx, void* iv) { + uint8_t* iv_buf = iv; + struct _ccmode_gcm_key* ctx = (struct _ccmode_gcm_key*)_ctx; + cc128_t* cache = (cc128_t*)ctx->buf; + uint8_t* current_iv = CTX_U_BUFFER(0); - ccgcm_state new_state = { - .decrypting = state->decrypting, - .mode = CCGCM_MODE_INITIALIZE, - .key_len = state->key_len, - .key = state->key, - // aggregate initialization automatically zeroes all other members - }; + cc_zero(16, cache->bytes); - memcpy(new_state.current_iv, state->current_iv, sizeof state->current_iv); - memcpy(new_state.hash_subkey.block, state->hash_subkey.block, sizeof state->hash_subkey); + for (size_t i = 0; i < 12; ++i) + cache->bytes[15 - i] = current_iv[i]; - *state = new_state; + for (size_t i = 0; i < 8; ++i) { + cache->bytes[4 + i] += 1; + if (cache->bytes[4 + i] != 0) + break; + } + + ctx->aad_nbytes = 12; + + ccgcm_process_iv(ctx); + + memcpy(iv_buf, current_iv, 12); return 0; }; + +int ccgcm_set_iv_legacy(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, size_t iv_nbytes, const void *iv) { + printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); +}; + +int ccgcm_one_shot(const struct ccmode_gcm* mode, size_t key_len, const void* key, size_t iv_len, const void* iv, size_t adata_len, const void* adata, size_t nbytes, const void* in, void* out, size_t tag_len, void* tag) { + CC_STUB_ERR(); +}; + +int ccgcm_one_shot_legacy(const struct ccmode_gcm* mode, size_t key_len, const void* key, size_t iv_len, const void* iv, size_t adata_len, const void* adata, size_t nbytes, const void* in, void* out, size_t tag_len, void* tag) { + CC_STUB_ERR(); +}; diff --git a/src/ccmode.c b/src/ccmode.c index cafd78a..7ac7f7b 100644 --- a/src/ccmode.c +++ b/src/ccmode.c @@ -1,55 +1,80 @@ #include -#include -#include +#include -int ccgcm_one_shot(const struct ccmode_gcm *mode, - size_t key_len, const void *key, - size_t iv_len, const void *iv, - size_t adata_len, const void *adata, - size_t nbytes, const void *in, void *out, - size_t tag_len, void *tag) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -int ccgcm_one_shot_legacy(const struct ccmode_gcm *mode, - size_t key_len, const void *key, - size_t iv_len, const void *iv, - size_t adata_len, const void *adata, - size_t nbytes, const void *in, void *out, - size_t tag_len, void *tag) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); -} - -int ccgcm_init_with_iv(const struct ccmode_gcm* mode, ccgcm_ctx* ctx, size_t key_nbytes, const void* key, const void* iv) { - ccgcm_init(mode, ctx, key_nbytes, key); - ccgcm_set_iv(mode, ctx, 12, iv); - return 0; +void ccmode_factory_cbc_encrypt(struct ccmode_cbc* cbc, const struct ccmode_ecb* ecb) { + *cbc = (struct ccmode_cbc) CCMODE_FACTORY_CBC_ENCRYPT(ecb); }; -int ccgcm_inc_iv(const struct ccmode_gcm* mode, ccgcm_ctx* ctx, void* iv) { - uint8_t* iv_buf = iv; - ccgcm_state* state = (ccgcm_state*)ctx; - - state->cache = (ccaes_block_128_t) {0}; - - for (size_t i = 0; i < 12; ++i) - state->cache.block[15 - i] = state->current_iv[i]; - - for (size_t i = 0; i < 8; ++i) { - state->cache.block[4 + i] += 1; - if (state->cache.block[4 + i] != 0) - break; - } - - state->total_iv_length = 12; - - ccgcm_process_iv(state); - - memcpy(iv_buf, state->current_iv, 12); - - return 0; +void ccmode_factory_cbc_decrypt(struct ccmode_cbc* cbc, const struct ccmode_ecb* ecb) { + *cbc = (struct ccmode_cbc) CCMODE_FACTORY_CBC_DECRYPT(ecb); }; -int ccgcm_set_iv_legacy(const struct ccmode_gcm *mode, ccgcm_ctx *ctx, size_t iv_nbytes, const void *iv) { - printf("DARLING CRYPTO STUB: %s\n", __PRETTY_FUNCTION__); +void ccmode_factory_gcm_encrypt(struct ccmode_gcm* gcm, const struct ccmode_ecb* ecb_encrypt) { + *gcm = (struct ccmode_gcm) { + .size = sizeof(struct _ccmode_gcm_key) + GCM_ECB_KEY_SIZE(ecb_encrypt), + .encdec = CCMODE_GCM_ENCRYPTOR, + .block_size = 1, + .init = ccmode_gcm_init, + .set_iv = ccmode_gcm_set_iv, + .gmac = ccmode_gcm_aad, + .gcm = ccmode_gcm_encrypt, + .finalize = ccmode_gcm_finalize, + .reset = ccmode_gcm_reset, + .custom = ecb_encrypt, + }; +}; + +void ccmode_factory_gcm_decrypt(struct ccmode_gcm* gcm, const struct ccmode_ecb* ecb_encrypt) { + *gcm = (struct ccmode_gcm) { + .size = sizeof(struct _ccmode_gcm_key) + GCM_ECB_KEY_SIZE(ecb_encrypt), + .encdec = CCMODE_GCM_DECRYPTOR, + .block_size = 1, + .init = ccmode_gcm_init, + .set_iv = ccmode_gcm_set_iv, + .gmac = ccmode_gcm_aad, + .gcm = ccmode_gcm_decrypt, + .finalize = ccmode_gcm_finalize, + .reset = ccmode_gcm_reset, + .custom = ecb_encrypt, + }; +}; + +void ccmode_factory_cfb_encrypt(struct ccmode_cfb* cfb, const struct ccmode_ecb* ecb) { + *cfb = (struct ccmode_cfb) CCMODE_FACTORY_CFB_ENCRYPT(ecb); +}; + +void ccmode_factory_cfb_decrypt(struct ccmode_cfb* cfb, const struct ccmode_ecb* ecb) { + *cfb = (struct ccmode_cfb) CCMODE_FACTORY_CFB_DECRYPT(ecb); +}; + +void ccmode_factory_cfb8_encrypt(struct ccmode_cfb8* cfb8, const struct ccmode_ecb* ecb) { + *cfb8 = (struct ccmode_cfb8) CCMODE_FACTORY_CFB8_ENCRYPT(ecb); +}; + +void ccmode_factory_cfb8_decrypt(struct ccmode_cfb8* cfb8, const struct ccmode_ecb* ecb) { + *cfb8 = (struct ccmode_cfb8) CCMODE_FACTORY_CFB8_DECRYPT(ecb); +}; + +void ccmode_factory_ctr_crypt(struct ccmode_ctr* ctr, const struct ccmode_ecb* ecb_encrypt) { + *ctr = (struct ccmode_ctr) CCMODE_FACTORY_CTR_CRYPT(ecb_encrypt); +}; + +void ccmode_factory_ccm_encrypt(struct ccmode_ccm* ccm, const struct ccmode_ecb* ecb_encrypt) { + *ccm = (struct ccmode_ccm) CCMODE_FACTORY_CCM_ENCRYPT(ecb_encrypt); +}; + +void ccmode_factory_ccm_decrypt(struct ccmode_ccm* ccm, const struct ccmode_ecb* ecb_encrypt) { + *ccm = (struct ccmode_ccm) CCMODE_FACTORY_CCM_DECRYPT(ecb_encrypt); +}; + +void ccmode_factory_ofb_crypt(struct ccmode_ofb* ofb, const struct ccmode_ecb* ecb) { + *ofb = (struct ccmode_ofb) CCMODE_FACTORY_OFB_CRYPT(ecb); +}; + +void ccmode_factory_xts_encrypt(struct ccmode_xts* xts, const struct ccmode_ecb* ecb, const struct ccmode_ecb* ecb_encrypt) { + *xts = (struct ccmode_xts) CCMODE_FACTORY_XTS_ENCRYPT(ecb, ecb_encrypt); +}; + +void ccmode_factory_xts_decrypt(struct ccmode_xts* xts, const struct ccmode_ecb* ecb, const struct ccmode_ecb* ecb_encrypt) { + *xts = (struct ccmode_xts) CCMODE_FACTORY_XTS_DECRYPT(ecb, ecb_encrypt); }; diff --git a/src/ccn.c b/src/ccn.c index 7296a1b..e80cad2 100644 --- a/src/ccn.c +++ b/src/ccn.c @@ -501,10 +501,10 @@ void ccn_zero_multi(cc_size n, cc_unit *r, ...) { void ccn_print(cc_size n, const cc_unit *s) { printf("size: %zu\n", n); - for (int i = 0; i < n; i++) + for (cc_size i = 0; i < n; i++) { #if CCN_UNIT_SIZE == 8 - printf("%llx\n", s[i]); + printf("%llx\n", (unsigned long long)s[i]); #elif CCN_UNIT_SIZE == 4 printf("%x\n", s[i]); #endif diff --git a/src/ccofb.c b/src/ccofb.c new file mode 100644 index 0000000..b244a21 --- /dev/null +++ b/src/ccofb.c @@ -0,0 +1,9 @@ +#include +#include + +int ccmode_ofb_init(const struct ccmode_ofb* ofb, ccofb_ctx* _ctx, size_t rawkey_len, const void* rawkey, const void* iv) { + CC_STUB_ERR(); +}; +int ccmode_ofb_crypt(ccofb_ctx* _ctx, size_t nbytes, const void* in, void* out) { + CC_STUB_ERR(); +}; diff --git a/src/ccxts.c b/src/ccxts.c new file mode 100644 index 0000000..0999c07 --- /dev/null +++ b/src/ccxts.c @@ -0,0 +1,18 @@ +#include +#include + +int ccmode_xts_init(const struct ccmode_xts* xts, ccxts_ctx* _ctx, size_t key_nbytes, const void* data_key, const void* tweak_key) { + CC_STUB_ERR(); +}; + +void ccmode_xts_key_sched(const struct ccmode_xts* xts, ccxts_ctx* _ctx, size_t key_nbytes, const void* data_key, const void* tweak_key) { + CC_STUB_VOID(); +}; + +void* ccmode_xts_crypt(const ccxts_ctx* _ctx, ccxts_tweak* tweak, size_t nblocks, const void* in, void* out) { + CC_STUB(NULL); +}; + +int ccmode_xts_set_tweak(const ccxts_ctx* _ctx, ccxts_tweak* tweak, const void* iv) { + CC_STUB_ERR(); +};