Skip to content

Commit a80a6d2

Browse files
committed
Streaming encryption/decryption: do not wait for full blocks
Return outputs whose length matches the inputs, simplifying usage.
1 parent ed9a9c7 commit a80a6d2

File tree

14 files changed

+789
-512
lines changed

14 files changed

+789
-512
lines changed

src/aegis128l/aegis128l_common.h

Lines changed: 145 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,29 @@ aegis128l_absorb(const uint8_t *const src, aes_block_t *const state)
7575
aegis128l_update(state, msg0, msg1);
7676
}
7777

78+
static inline void
79+
aegis128l_absorb_rate(const uint8_t *const src, aes_block_t *const state)
80+
{
81+
aes_block_t msg0, msg1;
82+
83+
msg0 = AES_BLOCK_LOAD(src);
84+
msg1 = AES_BLOCK_LOAD(src + AES_BLOCK_LENGTH);
85+
aegis128l_update(state, msg0, msg1);
86+
}
87+
88+
static inline void
89+
aegis128l_squeeze_keystream(uint8_t *const dst, aes_block_t *const state)
90+
{
91+
aes_block_t tmp0, tmp1;
92+
93+
tmp0 = AES_BLOCK_XOR(state[6], state[1]);
94+
tmp0 = AES_BLOCK_XOR(tmp0, AES_BLOCK_AND(state[2], state[3]));
95+
tmp1 = AES_BLOCK_XOR(state[5], state[2]);
96+
tmp1 = AES_BLOCK_XOR(tmp1, AES_BLOCK_AND(state[6], state[7]));
97+
AES_BLOCK_STORE(dst, tmp0);
98+
AES_BLOCK_STORE(dst + AES_BLOCK_LENGTH, tmp1);
99+
}
100+
78101
static void
79102
aegis128l_enc(uint8_t *const dst, const uint8_t *const src, aes_block_t *const state)
80103
{
@@ -356,42 +379,61 @@ state_encrypt_update(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *
356379

357380
*written = 0;
358381
st->mlen += mlen;
382+
383+
if (clen_max < mlen) {
384+
errno = ERANGE;
385+
return -1;
386+
}
387+
388+
// Handle leftover keystream from previous call
359389
if (st->pos != 0) {
360-
const size_t available = (sizeof st->buf) - st->pos;
390+
const size_t available = RATE - st->pos;
361391
const size_t n = mlen < available ? mlen : available;
392+
size_t j;
393+
uint8_t tmp;
362394

363-
if (n != 0) {
364-
memcpy(st->buf + st->pos, m + i, n);
365-
m += n;
366-
mlen -= n;
367-
st->pos += n;
395+
for (j = 0; j < n; j++) {
396+
tmp = m[j];
397+
c[j] = m[j] ^ st->buf[st->pos + j];
398+
st->buf[st->pos + j] = tmp;
368399
}
369-
if (st->pos == sizeof st->buf) {
370-
if (clen_max < RATE) {
371-
errno = ERANGE;
372-
return -1;
373-
}
374-
clen_max -= RATE;
375-
aegis128l_enc(c, st->buf, blocks);
376-
*written += RATE;
377-
c += RATE;
378-
st->pos = 0;
379-
} else {
400+
st->pos += n;
401+
*written += n;
402+
m += n;
403+
c += n;
404+
mlen -= n;
405+
406+
if (st->pos < RATE) {
407+
// Still consuming keystream from previous call
408+
memcpy(st->blocks, blocks, sizeof blocks);
380409
return 0;
381410
}
411+
412+
// Full block accumulated, update state
413+
aegis128l_absorb_rate(st->buf, blocks);
414+
st->pos = 0;
382415
}
383-
if (clen_max < (mlen & ~(size_t) (RATE - 1))) {
384-
errno = ERANGE;
385-
return -1;
386-
}
416+
387417
for (i = 0; i + RATE <= mlen; i += RATE) {
388418
aegis128l_enc(c + i, m + i, blocks);
389419
}
390420
*written += i;
391-
left = mlen % RATE;
421+
422+
left = mlen - i;
392423
if (left != 0) {
393-
memcpy(st->buf, m + i, left);
424+
size_t j;
425+
uint8_t tmp;
426+
427+
// Generate keystream without updating state
428+
aegis128l_squeeze_keystream(st->buf, blocks);
429+
430+
for (j = 0; j < left; j++) {
431+
tmp = m[i + j];
432+
c[i + j] = m[i + j] ^ st->buf[j];
433+
st->buf[j] = tmp;
434+
}
394435
st->pos = left;
436+
*written += left;
395437
}
396438

397439
memcpy(st->blocks, blocks, sizeof blocks);
@@ -407,25 +449,20 @@ state_encrypt_detached_final(aegis128l_state *st_, uint8_t *c, size_t clen_max,
407449
_aegis128l_state *const st =
408450
(_aegis128l_state *) ((((uintptr_t) &st_->opaque) + (ALIGNMENT - 1)) &
409451
~(uintptr_t) (ALIGNMENT - 1));
410-
CRYPTO_ALIGN(ALIGNMENT) uint8_t src[RATE];
411-
CRYPTO_ALIGN(ALIGNMENT) uint8_t dst[RATE];
412452

413453
memcpy(blocks, st->blocks, sizeof blocks);
414454

415455
*written = 0;
416-
if (clen_max < st->pos) {
417-
errno = ERANGE;
418-
return -1;
419-
}
456+
457+
// Ciphertext was already output during _update; absorb cached plaintext into state
420458
if (st->pos != 0) {
421-
memset(src, 0, sizeof src);
422-
memcpy(src, st->buf, st->pos);
423-
aegis128l_enc(dst, src, blocks);
424-
memcpy(c, dst, st->pos);
459+
CRYPTO_ALIGN(ALIGNMENT) uint8_t tmp[RATE];
460+
memset(tmp, 0, sizeof tmp);
461+
memcpy(tmp, st->buf, st->pos);
462+
aegis128l_absorb_rate(tmp, blocks);
425463
}
426-
aegis128l_mac(mac, maclen, st->adlen, st->mlen, blocks);
427464

428-
*written = st->pos;
465+
aegis128l_mac(mac, maclen, st->adlen, st->mlen, blocks);
429466

430467
memcpy(st->blocks, blocks, sizeof blocks);
431468

@@ -440,25 +477,26 @@ state_encrypt_final(aegis128l_state *st_, uint8_t *c, size_t clen_max, size_t *w
440477
_aegis128l_state *const st =
441478
(_aegis128l_state *) ((((uintptr_t) &st_->opaque) + (ALIGNMENT - 1)) &
442479
~(uintptr_t) (ALIGNMENT - 1));
443-
CRYPTO_ALIGN(ALIGNMENT) uint8_t src[RATE];
444-
CRYPTO_ALIGN(ALIGNMENT) uint8_t dst[RATE];
445480

446481
memcpy(blocks, st->blocks, sizeof blocks);
447482

448483
*written = 0;
449-
if (clen_max < st->pos + maclen) {
484+
if (clen_max < maclen) {
450485
errno = ERANGE;
451486
return -1;
452487
}
488+
489+
// Ciphertext was already output during _update; absorb cached plaintext into state
453490
if (st->pos != 0) {
454-
memset(src, 0, sizeof src);
455-
memcpy(src, st->buf, st->pos);
456-
aegis128l_enc(dst, src, blocks);
457-
memcpy(c, dst, st->pos);
491+
CRYPTO_ALIGN(ALIGNMENT) uint8_t tmp[RATE];
492+
memset(tmp, 0, sizeof tmp);
493+
memcpy(tmp, st->buf, st->pos);
494+
aegis128l_absorb_rate(tmp, blocks);
458495
}
459-
aegis128l_mac(c + st->pos, maclen, st->adlen, st->mlen, blocks);
460496

461-
*written = st->pos + maclen;
497+
aegis128l_mac(c, maclen, st->adlen, st->mlen, blocks);
498+
499+
*written = maclen;
462500

463501
memcpy(st->blocks, blocks, sizeof blocks);
464502

@@ -473,60 +511,83 @@ state_decrypt_detached_update(aegis128l_state *st_, uint8_t *m, size_t mlen_max,
473511
_aegis128l_state *const st =
474512
(_aegis128l_state *) ((((uintptr_t) &st_->opaque) + (ALIGNMENT - 1)) &
475513
~(uintptr_t) (ALIGNMENT - 1));
476-
CRYPTO_ALIGN(ALIGNMENT) uint8_t dst[RATE];
477-
size_t i = 0;
478-
size_t left;
514+
size_t i = 0;
515+
size_t left;
479516

480517
memcpy(blocks, st->blocks, sizeof blocks);
481518

482519
*written = 0;
483520
st->mlen += clen;
484521

522+
if (m != NULL && mlen_max < clen) {
523+
errno = ERANGE;
524+
return -1;
525+
}
526+
527+
// Handle leftover keystream from previous call
485528
if (st->pos != 0) {
486-
const size_t available = (sizeof st->buf) - st->pos;
529+
const size_t available = RATE - st->pos;
487530
const size_t n = clen < available ? clen : available;
488-
489-
if (n != 0) {
490-
memcpy(st->buf + st->pos, c, n);
491-
c += n;
492-
clen -= n;
493-
st->pos += n;
531+
size_t j;
532+
533+
for (j = 0; j < n; j++) {
534+
if (m != NULL) {
535+
m[j] = c[j] ^ st->buf[st->pos + j];
536+
st->buf[st->pos + j] = m[j];
537+
} else {
538+
uint8_t plaintext = c[j] ^ st->buf[st->pos + j];
539+
st->buf[st->pos + j] = plaintext;
540+
}
494541
}
495-
if (st->pos < (sizeof st->buf)) {
542+
st->pos += n;
543+
*written += n;
544+
if (m != NULL) {
545+
m += n;
546+
}
547+
c += n;
548+
clen -= n;
549+
550+
if (st->pos < RATE) {
551+
// Still consuming keystream
552+
memcpy(st->blocks, blocks, sizeof blocks);
496553
return 0;
497554
}
555+
556+
// Full block accumulated, update state
557+
aegis128l_absorb_rate(st->buf, blocks);
498558
st->pos = 0;
499-
if (m != NULL) {
500-
if (mlen_max < RATE) {
501-
errno = ERANGE;
502-
return -1;
503-
}
504-
mlen_max -= RATE;
505-
aegis128l_dec(m, st->buf, blocks);
506-
m += RATE;
507-
} else {
508-
aegis128l_dec(dst, st->buf, blocks);
509-
}
510-
*written += RATE;
511559
}
560+
512561
if (m != NULL) {
513-
if (mlen_max < (clen & ~(size_t) (RATE - 1))) {
514-
errno = ERANGE;
515-
return -1;
516-
}
517562
for (i = 0; i + RATE <= clen; i += RATE) {
518563
aegis128l_dec(m + i, c + i, blocks);
519564
}
520565
} else {
566+
CRYPTO_ALIGN(ALIGNMENT) uint8_t dst[RATE];
521567
for (i = 0; i + RATE <= clen; i += RATE) {
522568
aegis128l_dec(dst, c + i, blocks);
523569
}
524570
}
525571
*written += i;
526-
left = clen % RATE;
527-
if (left) {
528-
memcpy(st->buf, c + i, left);
572+
573+
left = clen - i;
574+
if (left != 0) {
575+
size_t j;
576+
577+
// Generate keystream without updating state
578+
aegis128l_squeeze_keystream(st->buf, blocks);
579+
580+
for (j = 0; j < left; j++) {
581+
if (m != NULL) {
582+
m[i + j] = c[i + j] ^ st->buf[j];
583+
st->buf[j] = m[i + j];
584+
} else {
585+
uint8_t plaintext = c[i + j] ^ st->buf[j];
586+
st->buf[j] = plaintext;
587+
}
588+
}
529589
st->pos = left;
590+
*written += left;
530591
}
531592

532593
memcpy(st->blocks, blocks, sizeof blocks);
@@ -538,40 +599,32 @@ static int
538599
state_decrypt_detached_final(aegis128l_state *st_, uint8_t *m, size_t mlen_max, size_t *written,
539600
const uint8_t *mac, size_t maclen)
540601
{
541-
aegis_blocks blocks;
542-
CRYPTO_ALIGN(16) uint8_t computed_mac[32];
543-
CRYPTO_ALIGN(ALIGNMENT) uint8_t dst[RATE];
544-
_aegis128l_state *const st =
602+
aegis_blocks blocks;
603+
CRYPTO_ALIGN(16) uint8_t computed_mac[32];
604+
_aegis128l_state *const st =
545605
(_aegis128l_state *) ((((uintptr_t) &st_->opaque) + (ALIGNMENT - 1)) &
546606
~(uintptr_t) (ALIGNMENT - 1));
547607
int ret;
548608

549609
memcpy(blocks, st->blocks, sizeof blocks);
550610

551611
*written = 0;
612+
613+
// Plaintext was already output during _update; absorb cached plaintext into state
552614
if (st->pos != 0) {
553-
if (m != NULL) {
554-
if (mlen_max < st->pos) {
555-
errno = ERANGE;
556-
return -1;
557-
}
558-
aegis128l_declast(m, st->buf, st->pos, blocks);
559-
} else {
560-
aegis128l_declast(dst, st->buf, st->pos, blocks);
561-
}
615+
CRYPTO_ALIGN(ALIGNMENT) uint8_t tmp[RATE];
616+
memset(tmp, 0, sizeof tmp);
617+
memcpy(tmp, st->buf, st->pos);
618+
aegis128l_absorb_rate(tmp, blocks);
562619
}
620+
563621
aegis128l_mac(computed_mac, maclen, st->adlen, st->mlen, blocks);
564622
ret = -1;
565623
if (maclen == 16) {
566624
ret = aegis_verify_16(computed_mac, mac);
567625
} else if (maclen == 32) {
568626
ret = aegis_verify_32(computed_mac, mac);
569627
}
570-
if (ret == 0) {
571-
*written = st->pos;
572-
} else {
573-
memset(m, 0, st->pos);
574-
}
575628

576629
memcpy(st->blocks, blocks, sizeof blocks);
577630

src/aegis128x2/aegis128x2.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
#include "aegis128x2.h"
77
#include "aegis128x2_aesni.h"
88
#include "aegis128x2_altivec.h"
9-
#include "aegis128x2_neon_aes.h"
109
#include "aegis128x2_avx2.h"
10+
#include "aegis128x2_neon_aes.h"
1111

1212
#ifndef HAS_HW_AES
1313
# include "aegis128x2_soft.h"

src/aegis128x2/aegis128x2_avx2.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
# ifdef HAVE_VAESINTRIN_H
1111

1212
# ifdef __clang__
13-
# pragma clang attribute push(__attribute__((target("aes,vaes,avx2"))), apply_to = function)
13+
# pragma clang attribute push(__attribute__((target("aes,vaes,avx2"))), \
14+
apply_to = function)
1415
# elif defined(__GNUC__)
1516
# pragma GCC target("aes,vaes,avx2")
1617
# endif

0 commit comments

Comments
 (0)