diff --git a/src/aegis128x4/aegis128x4.c b/src/aegis128x4/aegis128x4.c index 4a8cb0e..dd13616 100644 --- a/src/aegis128x4/aegis128x4.c +++ b/src/aegis128x4/aegis128x4.c @@ -177,19 +177,19 @@ aegis128x4_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, co } void -aegis128x4_mac_init(aegis128x4_state *st_, const uint8_t *k, const uint8_t *npub) +aegis128x4_mac_init(aegis128x4_mac_state *st_, const uint8_t *k, const uint8_t *npub) { - implementation->state_init(st_, NULL, 0, npub, k); + implementation->state_mac_init(st_, npub, k); } int -aegis128x4_mac_update(aegis128x4_state *st_, const uint8_t *m, size_t mlen) +aegis128x4_mac_update(aegis128x4_mac_state *st_, const uint8_t *m, size_t mlen) { return implementation->state_mac_update(st_, m, mlen); } int -aegis128x4_mac_final(aegis128x4_state *st_, uint8_t *mac, size_t maclen) +aegis128x4_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen) { if (maclen != 16 && maclen != 32) { errno = EINVAL; @@ -199,7 +199,7 @@ aegis128x4_mac_final(aegis128x4_state *st_, uint8_t *mac, size_t maclen) } int -aegis128x4_mac_verify(aegis128x4_state *st_, const uint8_t *mac, size_t maclen) +aegis128x4_mac_verify(aegis128x4_mac_state *st_, const uint8_t *mac, size_t maclen) { uint8_t expected_mac[32]; @@ -217,9 +217,15 @@ aegis128x4_mac_verify(aegis128x4_state *st_, const uint8_t *mac, size_t maclen) } void -aegis128x4_mac_state_clone(aegis128x4_state *dst, const aegis128x4_state *src) +aegis128x4_mac_reset(aegis128x4_mac_state *st_) { - implementation->state_clone(dst, src); + implementation->state_mac_reset(st_); +} + +void +aegis128x4_mac_state_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src) +{ + implementation->state_mac_clone(dst, src); } int diff --git a/src/aegis128x4/aegis128x4_aesni.c b/src/aegis128x4/aegis128x4_aesni.c index 1664139..9c838a3 100644 --- a/src/aegis128x4/aegis128x4_aesni.c +++ b/src/aegis128x4/aegis128x4_aesni.c @@ -107,9 +107,11 @@ struct aegis128x4_implementation aegis128x4_aesni_implementation = { .state_encrypt_final = state_encrypt_final, .state_decrypt_detached_update = state_decrypt_detached_update, .state_decrypt_detached_final = state_decrypt_detached_final, + .state_mac_init = state_mac_init, .state_mac_update = state_mac_update, .state_mac_final = state_mac_final, - .state_clone = state_clone, + .state_mac_reset = state_mac_reset, + .state_mac_clone = state_mac_clone, }; # ifdef __clang__ diff --git a/src/aegis128x4/aegis128x4_altivec.c b/src/aegis128x4/aegis128x4_altivec.c index 3782021..dbe33dc 100644 --- a/src/aegis128x4/aegis128x4_altivec.c +++ b/src/aegis128x4/aegis128x4_altivec.c @@ -101,9 +101,11 @@ struct aegis128x4_implementation aegis128x4_altivec_implementation = { .state_encrypt_final = state_encrypt_final, .state_decrypt_detached_update = state_decrypt_detached_update, .state_decrypt_detached_final = state_decrypt_detached_final, + .state_mac_init = state_mac_init, .state_mac_update = state_mac_update, .state_mac_final = state_mac_final, - .state_clone = state_clone, + .state_mac_reset = state_mac_reset, + .state_mac_clone = state_mac_clone, }; # ifdef __clang__ diff --git a/src/aegis128x4/aegis128x4_armcrypto.c b/src/aegis128x4/aegis128x4_armcrypto.c index ebfe6db..e88398c 100644 --- a/src/aegis128x4/aegis128x4_armcrypto.c +++ b/src/aegis128x4/aegis128x4_armcrypto.c @@ -109,9 +109,11 @@ struct aegis128x4_implementation aegis128x4_armcrypto_implementation = { .state_encrypt_final = state_encrypt_final, .state_decrypt_detached_update = state_decrypt_detached_update, .state_decrypt_detached_final = state_decrypt_detached_final, + .state_mac_init = state_mac_init, .state_mac_update = state_mac_update, .state_mac_final = state_mac_final, - .state_clone = state_clone, + .state_mac_reset = state_mac_reset, + .state_mac_clone = state_mac_clone, }; # ifdef __clang__ diff --git a/src/aegis128x4/aegis128x4_avx2.c b/src/aegis128x4/aegis128x4_avx2.c index f95e081..4a32fdd 100644 --- a/src/aegis128x4/aegis128x4_avx2.c +++ b/src/aegis128x4/aegis128x4_avx2.c @@ -99,9 +99,11 @@ struct aegis128x4_implementation aegis128x4_avx2_implementation = { .state_encrypt_final = state_encrypt_final, .state_decrypt_detached_update = state_decrypt_detached_update, .state_decrypt_detached_final = state_decrypt_detached_final, + .state_mac_init = state_mac_init, .state_mac_update = state_mac_update, .state_mac_final = state_mac_final, - .state_clone = state_clone, + .state_mac_reset = state_mac_reset, + .state_mac_clone = state_mac_clone, }; # ifdef __clang__ diff --git a/src/aegis128x4/aegis128x4_avx512.c b/src/aegis128x4/aegis128x4_avx512.c index 86c7cd1..2372d35 100644 --- a/src/aegis128x4/aegis128x4_avx512.c +++ b/src/aegis128x4/aegis128x4_avx512.c @@ -72,9 +72,11 @@ struct aegis128x4_implementation aegis128x4_avx512_implementation = { .state_encrypt_final = state_encrypt_final, .state_decrypt_detached_update = state_decrypt_detached_update, .state_decrypt_detached_final = state_decrypt_detached_final, + .state_mac_init = state_mac_init, .state_mac_update = state_mac_update, .state_mac_final = state_mac_final, - .state_clone = state_clone, + .state_mac_reset = state_mac_reset, + .state_mac_clone = state_mac_clone, }; # ifdef __clang__ diff --git a/src/aegis128x4/aegis128x4_common.h b/src/aegis128x4/aegis128x4_common.h index 16cc63a..19384ef 100644 --- a/src/aegis128x4/aegis128x4_common.h +++ b/src/aegis128x4/aegis128x4_common.h @@ -192,6 +192,76 @@ aegis128x4_declast(uint8_t *const dst, const uint8_t *const src, size_t len, aegis128x4_update(state, msg0, msg1); } +static void +aegis128x4_mac_nr(uint8_t *mac, size_t maclen, uint64_t adlen, aes_block_t *state) +{ + uint8_t t[2 * AES_BLOCK_LENGTH]; + uint8_t r[RATE]; + aes_block_t tmp; + int i; + const int d = AES_BLOCK_LENGTH / 16; + + tmp = AES_BLOCK_LOAD_64x2(0, adlen << 3); + tmp = AES_BLOCK_XOR(tmp, state[2]); + + for (i = 0; i < 7; i++) { + aegis128x4_update(state, tmp, tmp); + } + + memset(r, 0, sizeof r); + if (maclen == 16) { +#if AES_BLOCK_LENGTH > 16 + tmp = AES_BLOCK_XOR(state[6], AES_BLOCK_XOR(state[5], state[4])); + tmp = AES_BLOCK_XOR(tmp, AES_BLOCK_XOR(state[3], state[2])); + tmp = AES_BLOCK_XOR(tmp, AES_BLOCK_XOR(state[1], state[0])); + AES_BLOCK_STORE(t, tmp); + for (i = 0; i < d / 2; i++) { + memcpy(r, t + i * 32, 32); + aegis128x4_absorb(r, state); + } + tmp = AES_BLOCK_LOAD_64x2(d, maclen); + tmp = AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + aegis128x4_update(state, tmp, tmp); + } +#endif + tmp = AES_BLOCK_XOR(state[6], AES_BLOCK_XOR(state[5], state[4])); + tmp = AES_BLOCK_XOR(tmp, AES_BLOCK_XOR(state[3], state[2])); + tmp = AES_BLOCK_XOR(tmp, AES_BLOCK_XOR(state[1], state[0])); + AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + } else if (maclen == 32) { +#if AES_BLOCK_LENGTH > 16 + tmp = AES_BLOCK_XOR(state[3], state[2]); + tmp = AES_BLOCK_XOR(tmp, AES_BLOCK_XOR(state[1], state[0])); + AES_BLOCK_STORE(t, tmp); + tmp = AES_BLOCK_XOR(state[7], state[6]); + tmp = AES_BLOCK_XOR(tmp, AES_BLOCK_XOR(state[5], state[4])); + AES_BLOCK_STORE(t + AES_BLOCK_LENGTH, tmp); + for (i = 1; i < d; i++) { + memcpy(r, t + i * 16, 16); + memcpy(r + 16, t + AES_BLOCK_LENGTH + i * 16, 16); + aegis128x4_absorb(r, state); + } + tmp = AES_BLOCK_LOAD_64x2(d, maclen); + tmp = AES_BLOCK_XOR(tmp, state[2]); + for (i = 0; i < 7; i++) { + aegis128x4_update(state, tmp, tmp); + } +#endif + tmp = AES_BLOCK_XOR(state[3], state[2]); + tmp = AES_BLOCK_XOR(tmp, AES_BLOCK_XOR(state[1], state[0])); + AES_BLOCK_STORE(t, tmp); + memcpy(mac, t, 16); + tmp = AES_BLOCK_XOR(state[7], state[6]); + tmp = AES_BLOCK_XOR(tmp, AES_BLOCK_XOR(state[5], state[4])); + AES_BLOCK_STORE(t, tmp); + memcpy(mac + 16, t, 16); + } else { + memset(mac, 0, maclen); + } +} + static int encrypt_detached(uint8_t *c, uint8_t *mac, size_t maclen, const uint8_t *m, size_t mlen, const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) @@ -351,6 +421,14 @@ typedef struct _aegis128x4_state { size_t pos; } _aegis128x4_state; +typedef struct _aegis128x4_mac_state { + aegis_blocks blocks0; + aegis_blocks blocks; + uint8_t buf[RATE]; + uint64_t adlen; + size_t pos; +} _aegis128x4_mac_state; + static void state_init(aegis128x4_state *st_, const uint8_t *ad, size_t adlen, const uint8_t *npub, const uint8_t *k) @@ -619,13 +697,33 @@ state_decrypt_detached_final(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, return ret; } +static void +state_mac_init(aegis128x4_mac_state *st_, const uint8_t *npub, const uint8_t *k) +{ + aegis_blocks blocks; + _aegis128x4_mac_state *const st = + (_aegis128x4_mac_state *) ((((uintptr_t) &st_->opaque) + (ALIGNMENT - 1)) & + ~(uintptr_t) (ALIGNMENT - 1)); + + COMPILER_ASSERT((sizeof *st) + ALIGNMENT <= sizeof *st_); + st->pos = 0; + + memcpy(blocks, st->blocks, sizeof blocks); + + aegis128x4_init(k, npub, blocks); + + memcpy(st->blocks0, blocks, sizeof blocks); + memcpy(st->blocks, blocks, sizeof blocks); + st->adlen = 0; +} + static int -state_mac_update(aegis128x4_state *st_, const uint8_t *ad, size_t adlen) +state_mac_update(aegis128x4_mac_state *st_, const uint8_t *ad, size_t adlen) { - aegis_blocks blocks; - _aegis128x4_state *const st = - (_aegis128x4_state *) ((((uintptr_t) &st_->opaque) + (ALIGNMENT - 1)) & - ~(uintptr_t) (ALIGNMENT - 1)); + aegis_blocks blocks; + _aegis128x4_mac_state *const st = + (_aegis128x4_mac_state *) ((((uintptr_t) &st_->opaque) + (ALIGNMENT - 1)) & + ~(uintptr_t) (ALIGNMENT - 1)); size_t i; size_t left; @@ -669,12 +767,12 @@ state_mac_update(aegis128x4_state *st_, const uint8_t *ad, size_t adlen) } static int -state_mac_final(aegis128x4_state *st_, uint8_t *mac, size_t maclen) +state_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen) { - aegis_blocks blocks; - _aegis128x4_state *const st = - (_aegis128x4_state *) ((((uintptr_t) &st_->opaque) + (ALIGNMENT - 1)) & - ~(uintptr_t) (ALIGNMENT - 1)); + aegis_blocks blocks; + _aegis128x4_mac_state *const st = + (_aegis128x4_mac_state *) ((((uintptr_t) &st_->opaque) + (ALIGNMENT - 1)) & + ~(uintptr_t) (ALIGNMENT - 1)); size_t left; memcpy(blocks, st->blocks, sizeof blocks); @@ -684,7 +782,7 @@ state_mac_final(aegis128x4_state *st_, uint8_t *mac, size_t maclen) memset(st->buf + left, 0, RATE - left); aegis128x4_absorb(st->buf, blocks); } - aegis128x4_mac(mac, maclen, st->adlen, 0, blocks); + aegis128x4_mac_nr(mac, maclen, st->adlen, blocks); memcpy(st->blocks, blocks, sizeof blocks); @@ -692,13 +790,24 @@ state_mac_final(aegis128x4_state *st_, uint8_t *mac, size_t maclen) } static void -state_clone(aegis128x4_state *dst, const aegis128x4_state *src) +state_mac_reset(aegis128x4_mac_state *st_) { - _aegis128x4_state *const dst_ = - (_aegis128x4_state *) ((((uintptr_t) &dst->opaque) + (ALIGNMENT - 1)) & - ~(uintptr_t) (ALIGNMENT - 1)); - const _aegis128x4_state *const src_ = - (const _aegis128x4_state *) ((((uintptr_t) &src->opaque) + (ALIGNMENT - 1)) & - ~(uintptr_t) (ALIGNMENT - 1)); + _aegis128x4_mac_state *const st = + (_aegis128x4_mac_state *) ((((uintptr_t) &st_->opaque) + (ALIGNMENT - 1)) & + ~(uintptr_t) (ALIGNMENT - 1)); + st->adlen = 0; + st->pos = 0; + memcpy(st->blocks, st->blocks0, sizeof(aegis_blocks)); +} + +static void +state_mac_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src) +{ + _aegis128x4_mac_state *const dst_ = + (_aegis128x4_mac_state *) ((((uintptr_t) &dst->opaque) + (ALIGNMENT - 1)) & + ~(uintptr_t) (ALIGNMENT - 1)); + const _aegis128x4_mac_state *const src_ = + (const _aegis128x4_mac_state *) ((((uintptr_t) &src->opaque) + (ALIGNMENT - 1)) & + ~(uintptr_t) (ALIGNMENT - 1)); *dst_ = *src_; -} \ No newline at end of file +} diff --git a/src/aegis128x4/implementations.h b/src/aegis128x4/implementations.h index 9d8d3e8..d1ec626 100644 --- a/src/aegis128x4/implementations.h +++ b/src/aegis128x4/implementations.h @@ -29,9 +29,11 @@ typedef struct aegis128x4_implementation { size_t *written, const uint8_t *c, size_t clen); int (*state_decrypt_detached_final)(aegis128x4_state *st_, uint8_t *m, size_t mlen_max, size_t *written, const uint8_t *mac, size_t maclen); - int (*state_mac_update)(aegis128x4_state *st_, const uint8_t *ad, size_t adlen); - int (*state_mac_final)(aegis128x4_state *st_, uint8_t *mac, size_t maclen); - void (*state_clone)(aegis128x4_state *dst, const aegis128x4_state *src); + void (*state_mac_init)(aegis128x4_mac_state *st_, const uint8_t *npub, const uint8_t *k); + int (*state_mac_update)(aegis128x4_mac_state *st_, const uint8_t *ad, size_t adlen); + int (*state_mac_final)(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen); + void (*state_mac_reset)(aegis128x4_mac_state *st); + void (*state_mac_clone)(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src); } aegis128x4_implementation; #endif diff --git a/src/include/aegis128x4.h b/src/include/aegis128x4.h index 6de9741..2de55e4 100644 --- a/src/include/aegis128x4.h +++ b/src/include/aegis128x4.h @@ -31,6 +31,11 @@ typedef struct aegis128x4_state { CRYPTO_ALIGN(64) uint8_t opaque[832]; } aegis128x4_state; +/* An AEGIS state, only for MAC updates */ +typedef struct aegis128x4_mac_state { + CRYPTO_ALIGN(32) uint8_t opaque[1664]; +} aegis128x4_mac_state; + /* The length of an AEGIS key, in bytes */ size_t aegis128x4_keybytes(void); @@ -258,13 +263,12 @@ void aegis128x4_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t cle * k: key input buffer (16 bytes) * * - The same key MUST NOT be used both for MAC and encryption. - * - The nonce MUST NOT be reused with the same key. * - If the key is secret, the MAC is secure against forgery. * - However, if the key is known, arbitrary inputs matching a tag can be efficiently computed. * * The recommended way to use the MAC mode is to generate a random key and keep it secret. */ -void aegis128x4_mac_init(aegis128x4_state *st_, const uint8_t *k, const uint8_t *npub); +void aegis128x4_mac_init(aegis128x4_mac_state *st_, const uint8_t *k, const uint8_t *npub); /* * Update the MAC state with input data. @@ -277,7 +281,7 @@ void aegis128x4_mac_init(aegis128x4_state *st_, const uint8_t *k, const uint8_t * * Once the full input has been absorb, call either `_mac_final` or `_mac_verify`. */ -int aegis128x4_mac_update(aegis128x4_state *st_, const uint8_t *m, size_t mlen); +int aegis128x4_mac_update(aegis128x4_mac_state *st_, const uint8_t *m, size_t mlen); /* * Finalize the MAC and generate the authentication tag. @@ -286,7 +290,7 @@ int aegis128x4_mac_update(aegis128x4_state *st_, const uint8_t *m, size_t mlen); * mac: authentication tag output buffer * maclen: length of the authentication tag to generate (16 or 32. 32 is recommended). */ -int aegis128x4_mac_final(aegis128x4_state *st_, uint8_t *mac, size_t maclen); +int aegis128x4_mac_final(aegis128x4_mac_state *st_, uint8_t *mac, size_t maclen); /* * Verify a MAC in constant time. @@ -297,7 +301,12 @@ int aegis128x4_mac_final(aegis128x4_state *st_, uint8_t *mac, size_t maclen); * * Returns 0 if the tag is authentic, -1 otherwise. */ -int aegis128x4_mac_verify(aegis128x4_state *st_, const uint8_t *mac, size_t maclen); +int aegis128x4_mac_verify(aegis128x4_mac_state *st_, const uint8_t *mac, size_t maclen); + +/* + * Reset an AEGIS_MAC state. + */ +void aegis128x4_mac_reset(aegis128x4_mac_state *st_); /* * Clone an AEGIS-MAC state. @@ -307,7 +316,7 @@ int aegis128x4_mac_verify(aegis128x4_state *st_, const uint8_t *mac, size_t macl * * This function MUST be used in order to clone states. */ -void aegis128x4_mac_state_clone(aegis128x4_state *dst, const aegis128x4_state *src); +void aegis128x4_mac_state_clone(aegis128x4_mac_state *dst, const aegis128x4_mac_state *src); #ifdef __cplusplus } diff --git a/src/test/main.zig b/src/test/main.zig index 06978b4..07a214a 100644 --- a/src/test/main.zig +++ b/src/test/main.zig @@ -708,10 +708,10 @@ test "aegis128x4 - MAC" { const nonce = [_]u8{0} ** 16; const msg = [_]u8{ 1, 2, 3 } ** 100 ++ [_]u8{0}; const msg2 = [_]u8{ 4, 5, 6, 7, 8 } ** 100; - var st0: aegis.aegis128x4_state = undefined; + var st0: aegis.aegis128x4_mac_state = undefined; aegis.aegis128x4_mac_init(&st0, &key, &nonce); - var st: aegis.aegis128x4_state = undefined; + var st: aegis.aegis128x4_mac_state = undefined; aegis.aegis128x4_mac_state_clone(&st, &st0); var ret = aegis.aegis128x4_mac_update(&st, &msg, msg.len); try testing.expectEqual(ret, 0); @@ -739,7 +739,7 @@ test "aegis128x4 - MAC" { var mac2: [mac.len]u8 = undefined; ret = aegis.aegis128x4_encrypt_detached(&mac2, &mac2, mac2.len, "", 0, &msg3, msg3.len, &nonce, &key); try testing.expectEqual(ret, 0); - try testing.expectEqualSlices(u8, &mac, &mac2); + try testing.expect(!std.mem.eql(u8, &mac, &mac2)); } test "aegis128l - MAC test vector" { @@ -800,6 +800,35 @@ test "aegis128x2 - MAC test vector" { try std.testing.expectEqualSlices(u8, &expected256, &mac256); } +test "aegis128x4 - MAC test vector" { + const key = [_]u8{ 0x10, 0x01 } ++ [_]u8{0x00} ** (16 - 2); + const nonce = [_]u8{ 0x10, 0x00, 0x02 } ++ [_]u8{0x00} ** (16 - 3); + var msg: [35]u8 = undefined; + for (&msg, 0..) |*byte, i| byte.* = @truncate(i); + var mac128: [16]u8 = undefined; + var mac256: [32]u8 = undefined; + var st: aegis.aegis128x4_mac_state = undefined; + var ret: c_int = undefined; + aegis.aegis128x4_mac_init(&st, &key, &nonce); + ret = aegis.aegis128x4_mac_update(&st, &msg, msg.len); + try testing.expectEqual(ret, 0); + ret = aegis.aegis128x4_mac_final(&st, &mac128, mac128.len); + try testing.expectEqual(ret, 0); + aegis.aegis128x4_mac_reset(&st); + ret = aegis.aegis128x4_mac_update(&st, &msg, msg.len); + try testing.expectEqual(ret, 0); + ret = aegis.aegis128x4_mac_final(&st, &mac256, mac256.len); + try testing.expectEqual(ret, 0); + const expected128_hex = "3742a0bf0a9e8604841fe520fc57621c"; + const expected256_hex = "3da44ead4e192d0df3c47c994c242b69dab2fdf0d98f58f96838d634ab945d3a"; + var expected128: [16]u8 = undefined; + var expected256: [32]u8 = undefined; + _ = try std.fmt.hexToBytes(&expected128, expected128_hex); + _ = try std.fmt.hexToBytes(&expected256, expected256_hex); + try std.testing.expectEqualSlices(u8, &expected128, &mac128); + try std.testing.expectEqualSlices(u8, &expected256, &mac256); +} + // Wycheproof tests const JsonTest = struct {