#include <sys/cdefs.h>
__KERNEL_RCSID(1, "$NetBSD: aes_bear64.c,v 1.1 2025/11/23 22:44:13 riastradh Exp $");
#include <sys/types.h>
#include <sys/endian.h>
#ifdef _KERNEL
#include <sys/systm.h>
#else
#include <assert.h>
#include <err.h>
#include <string.h>
#define KASSERT assert
#define panic(fmt, args...) err(1, fmt, args)
#endif
#include <crypto/aes/aes.h>
#include <crypto/aes/aes_bear64.h>
#include <crypto/aes/aes_impl.h>
static void
aesbear64_setkey(uint64_t rk[static 30], const void *key, uint32_t nrounds)
{
size_t key_len;
switch (nrounds) {
case 10:
key_len = 16;
break;
case 12:
key_len = 24;
break;
case 14:
key_len = 32;
break;
default:
panic("invalid AES nrounds: %u", nrounds);
}
br_aes_ct64_keysched(rk, key, key_len);
}
static void
aesbear64_setenckey(struct aesenc *enc, const uint8_t *key, uint32_t nrounds)
{
aesbear64_setkey(enc->aese_aes.aes_rk64, key, nrounds);
}
static void
aesbear64_setdeckey(struct aesdec *dec, const uint8_t *key, uint32_t nrounds)
{
aesbear64_setkey(dec->aesd_aes.aes_rk64, key, nrounds);
}
static void
aesbear64_enc(const struct aesenc *enc, const uint8_t in[static 16],
uint8_t out[static 16], uint32_t nrounds)
{
uint64_t sk_exp[120];
uint32_t w[4];
uint64_t q[8];
br_aes_ct64_skey_expand(sk_exp, nrounds, enc->aese_aes.aes_rk64);
w[0] = le32dec(in + 4*0);
w[1] = le32dec(in + 4*1);
w[2] = le32dec(in + 4*2);
w[3] = le32dec(in + 4*3);
br_aes_ct64_interleave_in(&q[0], &q[4], w);
q[1] = q[2] = q[3] = 0;
q[5] = q[6] = q[7] = 0;
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
br_aes_ct64_interleave_out(w, q[0], q[4]);
le32enc(out + 4*0, w[0]);
le32enc(out + 4*1, w[1]);
le32enc(out + 4*2, w[2]);
le32enc(out + 4*3, w[3]);
explicit_memset(sk_exp, 0, sizeof sk_exp);
explicit_memset(q, 0, sizeof q);
}
static void
aesbear64_dec(const struct aesdec *dec, const uint8_t in[static 16],
uint8_t out[static 16], uint32_t nrounds)
{
uint64_t sk_exp[120];
uint32_t w[4];
uint64_t q[8];
br_aes_ct64_skey_expand(sk_exp, nrounds, dec->aesd_aes.aes_rk64);
w[0] = le32dec(in + 4*0);
w[1] = le32dec(in + 4*1);
w[2] = le32dec(in + 4*2);
w[3] = le32dec(in + 4*3);
br_aes_ct64_interleave_in(&q[0], &q[4], w);
q[1] = q[2] = q[3] = 0;
q[5] = q[6] = q[7] = 0;
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_decrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
br_aes_ct64_interleave_out(w, q[0], q[4]);
le32enc(out + 4*0, w[0]);
le32enc(out + 4*1, w[1]);
le32enc(out + 4*2, w[2]);
le32enc(out + 4*3, w[3]);
explicit_memset(sk_exp, 0, sizeof sk_exp);
explicit_memset(q, 0, sizeof q);
}
static void
aesbear64_cbc_enc(const struct aesenc *enc, const uint8_t in[static 16],
uint8_t out[static 16], size_t nbytes, uint8_t iv[static 16],
uint32_t nrounds)
{
uint64_t sk_exp[120];
uint32_t w[4];
uint64_t q[8];
uint32_t cv0, cv1, cv2, cv3;
KASSERT(nbytes % 16 == 0);
if (nbytes == 0)
return;
br_aes_ct64_skey_expand(sk_exp, nrounds, enc->aese_aes.aes_rk64);
q[1] = q[2] = q[3] = 0;
q[5] = q[6] = q[7] = 0;
cv0 = le32dec(iv + 4*0);
cv1 = le32dec(iv + 4*1);
cv2 = le32dec(iv + 4*2);
cv3 = le32dec(iv + 4*3);
for (; nbytes; nbytes -= 16, in += 16, out += 16) {
w[0] = cv0 ^ le32dec(in + 4*0);
w[1] = cv1 ^ le32dec(in + 4*1);
w[2] = cv2 ^ le32dec(in + 4*2);
w[3] = cv3 ^ le32dec(in + 4*3);
br_aes_ct64_interleave_in(&q[0], &q[4], w);
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
br_aes_ct64_interleave_out(w, q[0], q[4]);
cv0 = w[0];
cv1 = w[1];
cv2 = w[2];
cv3 = w[3];
le32enc(out + 4*0, cv0);
le32enc(out + 4*1, cv1);
le32enc(out + 4*2, cv2);
le32enc(out + 4*3, cv3);
}
le32enc(iv + 4*0, cv0);
le32enc(iv + 4*1, cv1);
le32enc(iv + 4*2, cv2);
le32enc(iv + 4*3, cv3);
explicit_memset(sk_exp, 0, sizeof sk_exp);
explicit_memset(q, 0, sizeof q);
}
static void
aesbear64_cbc_dec(const struct aesdec *dec, const uint8_t in[static 16],
uint8_t out[static 16], size_t nbytes, uint8_t iv[static 16],
uint32_t nrounds)
{
uint64_t sk_exp[120];
uint32_t w[4];
uint64_t q[8];
uint32_t cv0, cv1, cv2, cv3, iv0, iv1, iv2, iv3;
unsigned i;
KASSERT(nbytes % 16 == 0);
if (nbytes == 0)
return;
br_aes_ct64_skey_expand(sk_exp, nrounds, dec->aesd_aes.aes_rk64);
iv0 = le32dec(iv + 4*0);
iv1 = le32dec(iv + 4*1);
iv2 = le32dec(iv + 4*2);
iv3 = le32dec(iv + 4*3);
cv0 = le32dec(in + nbytes - 16 + 4*0);
cv1 = le32dec(in + nbytes - 16 + 4*1);
cv2 = le32dec(in + nbytes - 16 + 4*2);
cv3 = le32dec(in + nbytes - 16 + 4*3);
le32enc(iv + 4*0, cv0);
le32enc(iv + 4*1, cv1);
le32enc(iv + 4*2, cv2);
le32enc(iv + 4*3, cv3);
if (nbytes % 64) {
unsigned n = (nbytes % 64)/16;
KASSERT(n == 1 || n == 2 || n == 3);
for (i = 4; i --> n;)
q[i] = q[4 + i] = 0;
KASSERT(i == n - 1);
w[0] = cv0;
w[1] = cv1;
w[2] = cv2;
w[3] = cv3;
br_aes_ct64_interleave_in(&q[i], &q[4 + i], w);
while (i --> 0) {
w[0] = le32dec(in + nbytes - 16*n + 16*i + 4*0);
w[1] = le32dec(in + nbytes - 16*n + 16*i + 4*1);
w[2] = le32dec(in + nbytes - 16*n + 16*i + 4*2);
w[3] = le32dec(in + nbytes - 16*n + 16*i + 4*3);
br_aes_ct64_interleave_in(&q[i], &q[4 + i], w);
}
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_decrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
for (i = n; i --> 1;) {
br_aes_ct64_interleave_out(w, q[i], q[4 + i]);
cv0 = le32dec(in + nbytes - 16*n + 16*(i - 1) + 4*0);
cv1 = le32dec(in + nbytes - 16*n + 16*(i - 1) + 4*1);
cv2 = le32dec(in + nbytes - 16*n + 16*(i - 1) + 4*2);
cv3 = le32dec(in + nbytes - 16*n + 16*(i - 1) + 4*3);
le32enc(out + nbytes - 16*n + 16*i + 4*0, w[0] ^ cv0);
le32enc(out + nbytes - 16*n + 16*i + 4*1, w[1] ^ cv1);
le32enc(out + nbytes - 16*n + 16*i + 4*2, w[2] ^ cv2);
le32enc(out + nbytes - 16*n + 16*i + 4*3, w[3] ^ cv3);
}
br_aes_ct64_interleave_out(w, q[0], q[4]);
nbytes -= nbytes % 64;
if (nbytes == 0)
goto out;
cv0 = le32dec(in + nbytes - 16 + 4*0);
cv1 = le32dec(in + nbytes - 16 + 4*1);
cv2 = le32dec(in + nbytes - 16 + 4*2);
cv3 = le32dec(in + nbytes - 16 + 4*3);
le32enc(out + nbytes + 4*0, cv0 ^ w[0]);
le32enc(out + nbytes + 4*1, cv1 ^ w[1]);
le32enc(out + nbytes + 4*2, cv2 ^ w[2]);
le32enc(out + nbytes + 4*3, cv3 ^ w[3]);
}
for (;;) {
KASSERT(nbytes >= 64);
w[0] = cv0;
w[1] = cv1;
w[2] = cv2;
w[3] = cv3;
br_aes_ct64_interleave_in(&q[3], &q[7], w);
for (i = 3; i --> 0;) {
w[0] = le32dec(in + nbytes - 64 + 16*i + 4*0);
w[1] = le32dec(in + nbytes - 64 + 16*i + 4*1);
w[2] = le32dec(in + nbytes - 64 + 16*i + 4*2);
w[3] = le32dec(in + nbytes - 64 + 16*i + 4*3);
br_aes_ct64_interleave_in(&q[i], &q[4 + i], w);
}
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_decrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
for (i = 4; i --> 1;) {
br_aes_ct64_interleave_out(w, q[i], q[4 + i]);
cv0 = le32dec(in + nbytes - 64 + 16*(i - 1) + 4*0);
cv1 = le32dec(in + nbytes - 64 + 16*(i - 1) + 4*1);
cv2 = le32dec(in + nbytes - 64 + 16*(i - 1) + 4*2);
cv3 = le32dec(in + nbytes - 64 + 16*(i - 1) + 4*3);
le32enc(out + nbytes - 64 + 16*i + 4*0, w[0] ^ cv0);
le32enc(out + nbytes - 64 + 16*i + 4*1, w[1] ^ cv1);
le32enc(out + nbytes - 64 + 16*i + 4*2, w[2] ^ cv2);
le32enc(out + nbytes - 64 + 16*i + 4*3, w[3] ^ cv3);
}
br_aes_ct64_interleave_out(w, q[0], q[4]);
nbytes -= 64;
if (nbytes == 0)
goto out;
cv0 = le32dec(in + nbytes - 16 + 4*0);
cv1 = le32dec(in + nbytes - 16 + 4*1);
cv2 = le32dec(in + nbytes - 16 + 4*2);
cv3 = le32dec(in + nbytes - 16 + 4*3);
le32enc(out + nbytes + 4*0, w[0] ^ cv0);
le32enc(out + nbytes + 4*1, w[1] ^ cv1);
le32enc(out + nbytes + 4*2, w[2] ^ cv2);
le32enc(out + nbytes + 4*3, w[3] ^ cv3);
}
out:
le32enc(out + 4*0, w[0] ^ iv0);
le32enc(out + 4*1, w[1] ^ iv1);
le32enc(out + 4*2, w[2] ^ iv2);
le32enc(out + 4*3, w[3] ^ iv3);
explicit_memset(sk_exp, 0, sizeof sk_exp);
explicit_memset(q, 0, sizeof q);
}
static inline void
aesbear64_xts_update(uint32_t *t0, uint32_t *t1, uint32_t *t2, uint32_t *t3)
{
uint32_t s0, s1, s2, s3;
s0 = *t0 >> 31;
s1 = *t1 >> 31;
s2 = *t2 >> 31;
s3 = *t3 >> 31;
*t0 = (*t0 << 1) ^ (-s3 & 0x87);
*t1 = (*t1 << 1) ^ s0;
*t2 = (*t2 << 1) ^ s1;
*t3 = (*t3 << 1) ^ s2;
}
static int
aesbear64_xts_update_selftest(void)
{
static const struct {
uint32_t in[4], out[4];
} cases[] = {
{ {1}, {2} },
{ {0x80000000U,0,0,0}, {0,1,0,0} },
{ {0,0x80000000U,0,0}, {0,0,1,0} },
{ {0,0,0x80000000U,0}, {0,0,0,1} },
{ {0,0,0,0x80000000U}, {0x87,0,0,0} },
{ {0,0x80000000U,0,0x80000000U}, {0x87,0,1,0} },
};
unsigned i;
uint32_t t0, t1, t2, t3;
for (i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) {
t0 = cases[i].in[0];
t1 = cases[i].in[1];
t2 = cases[i].in[2];
t3 = cases[i].in[3];
aesbear64_xts_update(&t0, &t1, &t2, &t3);
if (t0 != cases[i].out[0] ||
t1 != cases[i].out[1] ||
t2 != cases[i].out[2] ||
t3 != cases[i].out[3])
return -1;
}
return 0;
}
static void
aesbear64_xts_enc(const struct aesenc *enc, const uint8_t in[static 16],
uint8_t out[static 16], size_t nbytes, uint8_t tweak[static 16],
uint32_t nrounds)
{
uint64_t sk_exp[120];
uint32_t w[4];
uint64_t q[8];
uint32_t t0, t1, t2, t3, u0, u1, u2, u3;
unsigned i;
KASSERT(nbytes % 16 == 0);
if (nbytes == 0)
return;
br_aes_ct64_skey_expand(sk_exp, nrounds, enc->aese_aes.aes_rk64);
t0 = le32dec(tweak + 4*0);
t1 = le32dec(tweak + 4*1);
t2 = le32dec(tweak + 4*2);
t3 = le32dec(tweak + 4*3);
if (nbytes % 64) {
unsigned n = (nbytes % 64)/16;
for (i = 0, u0 = t0, u1 = t1, u2 = t2, u3 = t3; i < n; i++) {
w[0] = le32dec(in + 16*i + 4*0) ^ u0;
w[1] = le32dec(in + 16*i + 4*1) ^ u1;
w[2] = le32dec(in + 16*i + 4*2) ^ u2;
w[3] = le32dec(in + 16*i + 4*3) ^ u3;
aesbear64_xts_update(&u0, &u1, &u2, &u3);
br_aes_ct64_interleave_in(&q[i], &q[4 + i], w);
}
for (; i < 4; i++)
q[i] = q[4 + i] = 0;
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
for (i = 0, u0 = t0, u1 = t1, u2 = t2, u3 = t3; i < n; i++) {
br_aes_ct64_interleave_out(w, q[i], q[4 + i]);
le32enc(out + 16*i + 4*0, w[0] ^ u0);
le32enc(out + 16*i + 4*1, w[1] ^ u1);
le32enc(out + 16*i + 4*2, w[2] ^ u2);
le32enc(out + 16*i + 4*3, w[3] ^ u3);
aesbear64_xts_update(&u0, &u1, &u2, &u3);
}
t0 = u0, t1 = u1, t2 = u2, t3 = u3;
if ((nbytes -= 16*n) == 0)
goto out;
in += 16*n;
out += 16*n;
}
do {
KASSERT(nbytes >= 64);
for (i = 0, u0 = t0, u1 = t1, u2 = t2, u3 = t3; i < 4; i++) {
w[0] = le32dec(in + 16*i + 4*0) ^ u0;
w[1] = le32dec(in + 16*i + 4*1) ^ u1;
w[2] = le32dec(in + 16*i + 4*2) ^ u2;
w[3] = le32dec(in + 16*i + 4*3) ^ u3;
aesbear64_xts_update(&u0, &u1, &u2, &u3);
br_aes_ct64_interleave_in(&q[i], &q[4 + i], w);
}
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
for (i = 0, u0 = t0, u1 = t1, u2 = t2, u3 = t3; i < 4; i++) {
br_aes_ct64_interleave_out(w, q[i], q[4 + i]);
le32enc(out + 16*i + 4*0, w[0] ^ u0);
le32enc(out + 16*i + 4*1, w[1] ^ u1);
le32enc(out + 16*i + 4*2, w[2] ^ u2);
le32enc(out + 16*i + 4*3, w[3] ^ u3);
aesbear64_xts_update(&u0, &u1, &u2, &u3);
}
t0 = u0, t1 = u1, t2 = u2, t3 = u3;
in += 64;
out += 64;
} while (nbytes -= 64, nbytes);
out:
le32enc(tweak + 4*0, t0);
le32enc(tweak + 4*1, t1);
le32enc(tweak + 4*2, t2);
le32enc(tweak + 4*3, t3);
explicit_memset(sk_exp, 0, sizeof sk_exp);
explicit_memset(q, 0, sizeof q);
}
static void
aesbear64_xts_dec(const struct aesdec *dec, const uint8_t in[static 16],
uint8_t out[static 16], size_t nbytes, uint8_t tweak[static 16],
uint32_t nrounds)
{
uint64_t sk_exp[120];
uint32_t w[4];
uint64_t q[8];
uint32_t t0, t1, t2, t3, u0, u1, u2, u3;
unsigned i;
KASSERT(nbytes % 16 == 0);
if (nbytes == 0)
return;
br_aes_ct64_skey_expand(sk_exp, nrounds, dec->aesd_aes.aes_rk64);
t0 = le32dec(tweak + 4*0);
t1 = le32dec(tweak + 4*1);
t2 = le32dec(tweak + 4*2);
t3 = le32dec(tweak + 4*3);
if (nbytes % 64) {
unsigned n = (nbytes % 64)/16;
for (i = 0, u0 = t0, u1 = t1, u2 = t2, u3 = t3; i < n; i++) {
w[0] = le32dec(in + 16*i + 4*0) ^ u0;
w[1] = le32dec(in + 16*i + 4*1) ^ u1;
w[2] = le32dec(in + 16*i + 4*2) ^ u2;
w[3] = le32dec(in + 16*i + 4*3) ^ u3;
aesbear64_xts_update(&u0, &u1, &u2, &u3);
br_aes_ct64_interleave_in(&q[i], &q[4 + i], w);
}
for (; i < 4; i++)
q[i] = q[4 + i] = 0;
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_decrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
for (i = 0, u0 = t0, u1 = t1, u2 = t2, u3 = t3; i < n; i++) {
br_aes_ct64_interleave_out(w, q[i], q[4 + i]);
le32enc(out + 16*i + 4*0, w[0] ^ u0);
le32enc(out + 16*i + 4*1, w[1] ^ u1);
le32enc(out + 16*i + 4*2, w[2] ^ u2);
le32enc(out + 16*i + 4*3, w[3] ^ u3);
aesbear64_xts_update(&u0, &u1, &u2, &u3);
}
t0 = u0, t1 = u1, t2 = u2, t3 = u3;
if ((nbytes -= 16*n) == 0)
goto out;
in += 16*n;
out += 16*n;
}
do {
KASSERT(nbytes >= 64);
for (i = 0, u0 = t0, u1 = t1, u2 = t2, u3 = t3; i < 4; i++) {
w[0] = le32dec(in + 16*i + 4*0) ^ u0;
w[1] = le32dec(in + 16*i + 4*1) ^ u1;
w[2] = le32dec(in + 16*i + 4*2) ^ u2;
w[3] = le32dec(in + 16*i + 4*3) ^ u3;
aesbear64_xts_update(&u0, &u1, &u2, &u3);
br_aes_ct64_interleave_in(&q[i], &q[4 + i], w);
}
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_decrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
for (i = 0, u0 = t0, u1 = t1, u2 = t2, u3 = t3; i < 4; i++) {
br_aes_ct64_interleave_out(w, q[i], q[4 + i]);
le32enc(out + 16*i + 4*0, w[0] ^ u0);
le32enc(out + 16*i + 4*1, w[1] ^ u1);
le32enc(out + 16*i + 4*2, w[2] ^ u2);
le32enc(out + 16*i + 4*3, w[3] ^ u3);
aesbear64_xts_update(&u0, &u1, &u2, &u3);
}
t0 = u0, t1 = u1, t2 = u2, t3 = u3;
in += 64;
out += 64;
} while (nbytes -= 64, nbytes);
out:
le32enc(tweak + 4*0, t0);
le32enc(tweak + 4*1, t1);
le32enc(tweak + 4*2, t2);
le32enc(tweak + 4*3, t3);
explicit_memset(sk_exp, 0, sizeof sk_exp);
explicit_memset(q, 0, sizeof q);
}
static void
aesbear64_cbcmac_update1(const struct aesenc *enc, const uint8_t in[static 16],
size_t nbytes, uint8_t auth[static 16], uint32_t nrounds)
{
uint64_t sk_exp[120];
uint32_t w[4];
uint64_t q[8];
KASSERT(nbytes);
KASSERT(nbytes % 16 == 0);
br_aes_ct64_skey_expand(sk_exp, nrounds, enc->aese_aes.aes_rk64);
q[1] = q[2] = q[3] = 0;
q[5] = q[6] = q[7] = 0;
w[0] = le32dec(auth + 4*0);
w[1] = le32dec(auth + 4*1);
w[2] = le32dec(auth + 4*2);
w[3] = le32dec(auth + 4*3);
for (; nbytes; nbytes -= 16, in += 16) {
w[0] ^= le32dec(in + 4*0);
w[1] ^= le32dec(in + 4*1);
w[2] ^= le32dec(in + 4*2);
w[3] ^= le32dec(in + 4*3);
br_aes_ct64_interleave_in(&q[0], &q[4], w);
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
br_aes_ct64_interleave_out(w, q[0], q[4]);
}
le32enc(auth + 4*0, w[0]);
le32enc(auth + 4*1, w[1]);
le32enc(auth + 4*2, w[2]);
le32enc(auth + 4*3, w[3]);
explicit_memset(sk_exp, 0, sizeof sk_exp);
explicit_memset(q, 0, sizeof q);
}
static void
aesbear64_ccm_enc1(const struct aesenc *enc, const uint8_t *in, uint8_t *out,
size_t nbytes, uint8_t authctr[32], uint32_t nrounds)
{
uint64_t sk_exp[120];
uint32_t w[4];
uint64_t q[8];
uint32_t c0, c1, c2, c3be;
KASSERT(nbytes);
KASSERT(nbytes % 16 == 0);
br_aes_ct64_skey_expand(sk_exp, nrounds, enc->aese_aes.aes_rk64);
q[2] = q[3] = 0;
q[6] = q[7] = 0;
w[0] = le32dec(authctr + 4*0);
w[1] = le32dec(authctr + 4*1);
w[2] = le32dec(authctr + 4*2);
w[3] = le32dec(authctr + 4*3);
c0 = le32dec(authctr + 16 + 4*0);
c1 = le32dec(authctr + 16 + 4*1);
c2 = le32dec(authctr + 16 + 4*2);
c3be = bswap32(le32dec(authctr + 16 + 4*3));
for (; nbytes; nbytes -= 16, in += 16, out += 16) {
w[0] ^= le32dec(in + 4*0);
w[1] ^= le32dec(in + 4*1);
w[2] ^= le32dec(in + 4*2);
w[3] ^= le32dec(in + 4*3);
br_aes_ct64_interleave_in(&q[0], &q[4], w);
w[0] = c0;
w[1] = c1;
w[2] = c2;
w[3] = bswap32(++c3be);
br_aes_ct64_interleave_in(&q[1], &q[5], w);
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
br_aes_ct64_interleave_out(w, q[1], q[5]);
le32enc(out + 4*0, le32dec(in + 4*0) ^ w[0]);
le32enc(out + 4*1, le32dec(in + 4*1) ^ w[1]);
le32enc(out + 4*2, le32dec(in + 4*2) ^ w[2]);
le32enc(out + 4*3, le32dec(in + 4*3) ^ w[3]);
br_aes_ct64_interleave_out(w, q[0], q[4]);
}
le32enc(authctr + 4*0, w[0]);
le32enc(authctr + 4*1, w[1]);
le32enc(authctr + 4*2, w[2]);
le32enc(authctr + 4*3, w[3]);
le32enc(authctr + 16 + 4*3, bswap32(c3be));
explicit_memset(sk_exp, 0, sizeof sk_exp);
explicit_memset(q, 0, sizeof q);
}
static void
aesbear64_ccm_dec1(const struct aesenc *enc, const uint8_t *in, uint8_t *out,
size_t nbytes, uint8_t authctr[32], uint32_t nrounds)
{
uint64_t sk_exp[120];
uint32_t w[4];
uint64_t q[8];
uint32_t c0, c1, c2, c3be;
uint32_t b0, b1, b2, b3;
KASSERT(nbytes);
KASSERT(nbytes % 16 == 0);
br_aes_ct64_skey_expand(sk_exp, nrounds, enc->aese_aes.aes_rk64);
q[2] = q[3] = 0;
q[6] = q[7] = 0;
c0 = le32dec(authctr + 16 + 4*0);
c1 = le32dec(authctr + 16 + 4*1);
c2 = le32dec(authctr + 16 + 4*2);
c3be = bswap32(le32dec(authctr + 16 + 4*3));
w[0] = c0;
w[1] = c1;
w[2] = c2;
w[3] = bswap32(++c3be);
br_aes_ct64_interleave_in(&q[1], &q[5], w);
q[0] = q[4] = 0;
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
w[0] = le32dec(authctr + 4*0);
w[1] = le32dec(authctr + 4*1);
w[2] = le32dec(authctr + 4*2);
w[3] = le32dec(authctr + 4*3);
br_aes_ct64_interleave_in(&q[0], &q[4], w);
for (;; in += 16, out += 16) {
br_aes_ct64_interleave_out(w, q[1], q[5]);
b0 = le32dec(in + 4*0) ^ w[0];
b1 = le32dec(in + 4*1) ^ w[1];
b2 = le32dec(in + 4*2) ^ w[2];
b3 = le32dec(in + 4*3) ^ w[3];
br_aes_ct64_interleave_out(w, q[0], q[4]);
w[0] ^= b0;
w[1] ^= b1;
w[2] ^= b2;
w[3] ^= b3;
br_aes_ct64_interleave_in(&q[0], &q[4], w);
le32enc(out + 4*0, b0);
le32enc(out + 4*1, b1);
le32enc(out + 4*2, b2);
le32enc(out + 4*3, b3);
if ((nbytes -= 16) == 0)
break;
w[0] = c0;
w[1] = c1;
w[2] = c2;
w[3] = bswap32(++c3be);
br_aes_ct64_interleave_in(&q[1], &q[5], w);
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
}
br_aes_ct64_ortho(q);
br_aes_ct64_bitslice_encrypt(nrounds, sk_exp, q);
br_aes_ct64_ortho(q);
br_aes_ct64_interleave_out(w, q[0], q[4]);
le32enc(authctr + 4*0, w[0]);
le32enc(authctr + 4*1, w[1]);
le32enc(authctr + 4*2, w[2]);
le32enc(authctr + 4*3, w[3]);
le32enc(authctr + 16 + 4*3, bswap32(c3be));
explicit_memset(sk_exp, 0, sizeof sk_exp);
explicit_memset(q, 0, sizeof q);
}
static int
aesbear64_probe(void)
{
if (aesbear64_xts_update_selftest())
return -1;
return 0;
}
struct aes_impl aes_bear64_impl = {
.ai_name = "BearSSL aes_ct64",
.ai_probe = aesbear64_probe,
.ai_setenckey = aesbear64_setenckey,
.ai_setdeckey = aesbear64_setdeckey,
.ai_enc = aesbear64_enc,
.ai_dec = aesbear64_dec,
.ai_cbc_enc = aesbear64_cbc_enc,
.ai_cbc_dec = aesbear64_cbc_dec,
.ai_xts_enc = aesbear64_xts_enc,
.ai_xts_dec = aesbear64_xts_dec,
.ai_cbcmac_update1 = aesbear64_cbcmac_update1,
.ai_ccm_enc1 = aesbear64_ccm_enc1,
.ai_ccm_dec1 = aesbear64_ccm_dec1,
};