Skip to content

Commit

Permalink
Start implementing AEGIS-MAC
Browse files Browse the repository at this point in the history
  • Loading branch information
jedisct1 committed May 10, 2024
1 parent 666b752 commit 8ce9878
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 13 deletions.
43 changes: 43 additions & 0 deletions src/aegis128l/aegis128l.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,49 @@ aegis128l_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen, con
implementation->decrypt_unauthenticated(m, c, clen, npub, k);
}

void
aegis128l_mac_init(aegis128l_state *st_, const uint8_t *k)
{
const uint8_t npub[aegis128l_NPUBBYTES] = { 0 };

memset(st_, 0, sizeof *st_);
implementation->state_init(st_, NULL, 0, npub, k);
}

int
aegis128l_mac_update(aegis128l_state *st_, const uint8_t *m, size_t mlen)
{
return implementation->state_mac_update(st_, m, mlen);
}

int
aegis128l_mac_final(aegis128l_state *st_, uint8_t *mac, size_t maclen)
{
if (maclen != 16 && maclen != 32) {
errno = EINVAL;
return -1;
}
return implementation->state_mac_final(st_, mac, maclen);
}

int
aegis128l_mac_verify(aegis128l_state *st_, const uint8_t *mac, size_t maclen)
{
uint8_t expected_mac[32];

switch (maclen) {
case 16:
implementation->state_mac_final(st_, expected_mac, maclen);
return aegis_verify_16(expected_mac, mac);
case 32:
implementation->state_mac_final(st_, expected_mac, maclen);
return aegis_verify_32(expected_mac, mac);
default:
errno = EINVAL;
return -1;
}
}

int
aegis128l_pick_best_implementation(void)
{
Expand Down
2 changes: 2 additions & 0 deletions src/aegis128l/aegis128l_aesni.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ struct aegis128l_implementation aegis128l_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_update = state_mac_update,
.state_mac_final = state_mac_final,
};

# ifdef __clang__
Expand Down
2 changes: 2 additions & 0 deletions src/aegis128l/aegis128l_armcrypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ struct aegis128l_implementation aegis128l_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_update = state_mac_update,
.state_mac_final = state_mac_final,
};

# ifdef __clang__
Expand Down
47 changes: 47 additions & 0 deletions src/aegis128l/aegis128l_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,53 @@ state_init(aegis128l_state *st_, const uint8_t *ad, size_t adlen, const uint8_t
st->adlen = adlen;
}

static int
state_mac_update(aegis128l_state *st_, const uint8_t *ad, size_t adlen)
{
_aegis128l_state *const st =
(_aegis128l_state *) ((((uintptr_t) &st_->opaque) + (RATE - 1)) & ~(uintptr_t) (RATE - 1));
size_t i;
size_t left;

left = st->adlen % RATE;
st->adlen += adlen;
if (left != 0) {
if (left + adlen < RATE) {
memcpy(st->buf + left, ad, adlen);
return 0;
}
memcpy(st->buf + left, ad, RATE - left);
aegis128l_absorb(st->buf, st->state);
ad += RATE - left;
adlen -= RATE - left;
}
for (i = 0; i + RATE <= adlen; i += RATE) {
aegis128l_absorb(ad + i, st->state);
}
if (i < adlen) {
memset(st->buf, 0, RATE);
memcpy(st->buf, ad + i, adlen - i);
}
return 0;
}

static int
state_mac_final(aegis128l_state *st_, uint8_t *mac, size_t maclen)
{
_aegis128l_state *const st =
(_aegis128l_state *) ((((uintptr_t) &st_->opaque) + (RATE - 1)) & ~(uintptr_t) (RATE - 1));
size_t left;

left = st->adlen % RATE;
if (left != 0) {
memset(st->buf + left, 0, RATE - left);
aegis128l_absorb(st->buf, st->state);
}
aegis128l_mac(mac, maclen, st->adlen, 0, st->state);

return 0;
}

static int
state_encrypt_update(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *written,
const uint8_t *m, size_t mlen)
Expand Down
2 changes: 2 additions & 0 deletions src/aegis128l/aegis128l_soft.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ struct aegis128l_implementation aegis128l_soft_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_update = state_mac_update,
.state_mac_final = state_mac_final,
};

#endif
2 changes: 2 additions & 0 deletions src/aegis128l/implementations.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ typedef struct aegis128l_implementation {
size_t *written, const uint8_t *c, size_t clen);
int (*state_decrypt_detached_final)(aegis128l_state *st_, uint8_t *m, size_t mlen_max,
size_t *written, const uint8_t *mac, size_t maclen);
int (*state_mac_update)(aegis128l_state *st_, const uint8_t *ad, size_t adlen);
int (*state_mac_final)(aegis128l_state *st_, uint8_t *mac, size_t maclen);
} aegis128l_implementation;

#endif
48 changes: 48 additions & 0 deletions src/include/aegis128l.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,54 @@ void aegis128l_encrypt_unauthenticated(uint8_t *c, const uint8_t *m, size_t mlen
void aegis128l_decrypt_unauthenticated(uint8_t *m, const uint8_t *c, size_t clen,
const uint8_t *npub, const uint8_t *k);

/*
* Initialize a state for generating a MAC.
*
* st_: state to initialize
* k: key input buffer (16 bytes)
*
* - The same key MUST NOT be used both for MAC and encryption.
* - The nonce is not used in the MAC mode (fixed to zero).
* - 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 aegis128l_mac_init(aegis128l_state *st_, const uint8_t *k);

/*
* Update the MAC state with input data.
*
* st_: state to update
* m: input data
* mlen: length of the input data
*
* This function can be called multiple times.
*
* Once the full input has been absorb, call either `_mac_final` or `_mac_verify`.
*/
int aegis128l_mac_update(aegis128l_state *st_, const uint8_t *m, size_t mlen);

/*
* Finalize the MAC and generate the authentication tag.
*
* st_: state to finalize
* mac: authentication tag output buffer
* maclen: length of the authentication tag to generate (16 or 32. 32 is recommended).
*/
int aegis128l_mac_final(aegis128l_state *st_, uint8_t *mac, size_t maclen);

/*
* Verify a MAC in constant time.
*
* st_: state to verify
* mac: authentication tag to verify
* maclen: length of the authentication tag (16 or 32)
*
* Returns 0 if the tag is authentic, -1 otherwise.
*/
int aegis128l_mac_verify(aegis128l_state *st_, const uint8_t *mac, size_t maclen);

#ifdef __cplusplus
}
#endif
Expand Down
18 changes: 5 additions & 13 deletions src/test/benchmark.zig
Original file line number Diff line number Diff line change
Expand Up @@ -202,27 +202,19 @@ fn bench_aegis128x4() !void {

fn bench_aegis128l_mac() !void {
var key: [aegis.aegis128l_KEYBYTES]u8 = undefined;
var nonce: [aegis.aegis128l_NPUBBYTES]u8 = undefined;
var buf: [msg_len]u8 = undefined;
var st0: aegis.aegis128l_state = undefined;

random.bytes(&key);
random.bytes(&nonce);
random.bytes(&buf);
aegis.aegis128l_mac_init(&st0, &key);

var timer = try Timer.start();
const start = timer.lap();
for (0..iterations) |_| {
_ = aegis.aegis128l_encrypt_detached(
null,
&buf,
aegis.aegis128l_ABYTES_MAX,
null,
0,
&buf,
msg_len,
&nonce,
&key,
);
var st = st0;
_ = aegis.aegis128l_mac_update(&st, &buf, msg_len);
_ = aegis.aegis128l_mac_final(&st, &buf, aegis.aegis128l_ABYTES_MIN);
}
const end = timer.read();
mem.doNotOptimizeAway(buf[0]);
Expand Down
32 changes: 32 additions & 0 deletions src/test/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -624,3 +624,35 @@ test "aegis128l - Random stream" {
aegis.aegis128l_stream(&msg2, msg2.len, &nonce, &key);
try testing.expect(!std.mem.eql(u8, &msg, &msg2));
}

test "aegis128l - MAC" {
const key = [32]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
const msg = [_]u8{ 1, 2, 3 } ** 30;
const msg2 = [_]u8{ 4, 5, 6, 7, 8 } ** 30;
var st0: aegis.aegis128l_state = undefined;
aegis.aegis128l_mac_init(&st0, &key);

var st = st0;
var ret = aegis.aegis128l_mac_update(&st, &msg, msg.len);
try testing.expectEqual(ret, 0);
ret = aegis.aegis128l_mac_update(&st, &msg2, msg2.len);
try testing.expectEqual(ret, 0);
var mac: [32]u8 = undefined;
ret = aegis.aegis128l_mac_final(&st, &mac, mac.len);
try testing.expectEqual(ret, 0);

st = st0;
ret = aegis.aegis128l_mac_update(&st, &msg, msg.len);
try testing.expectEqual(ret, 0);
ret = aegis.aegis128l_mac_update(&st, &msg2, msg2.len);
try testing.expectEqual(ret, 0);
ret = aegis.aegis128l_mac_verify(&st, &mac, mac.len);
try testing.expectEqual(ret, 0);

st = st0;
const msg3 = msg ++ msg2;
ret = aegis.aegis128l_mac_update(&st, &msg3, msg3.len);
try testing.expectEqual(ret, 0);
ret = aegis.aegis128l_mac_verify(&st, &mac, mac.len);
try testing.expectEqual(ret, 0);
}

0 comments on commit 8ce9878

Please sign in to comment.