Skip to content

Commit

Permalink
lib/crypto: optimize aes_ccm_128
Browse files Browse the repository at this point in the history
- We avoid variables in order to do a lazy cleanup
  in aes_ccm_128_digest() via ZERO_STRUCTP(ctx)
- We use the optimized aes_block_xor() function
- We reuse A_i instead of rebuilding it everything completely.
- Align AES_BLOCK_SIZE arrays to 8 bytes

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11451

Signed-off-by: Stefan Metzmacher <[email protected]>
Reviewed-by: Jeremy Allison <[email protected]>
  • Loading branch information
metze-samba authored and jrasamba committed Aug 27, 2015
1 parent 8795ad2 commit 7e8333d
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 47 deletions.
117 changes: 72 additions & 45 deletions lib/crypto/aes_ccm_128.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,11 @@
#define M_ ((AES_CCM_128_M - 2) / 2)
#define L_ (AES_CCM_128_L - 1)

static inline void aes_ccm_128_xor(const uint8_t in1[AES_BLOCK_SIZE],
const uint8_t in2[AES_BLOCK_SIZE],
uint8_t out[AES_BLOCK_SIZE])
{
uint8_t i;

for (i = 0; i < AES_BLOCK_SIZE; i++) {
out[i] = in1[i] ^ in2[i];
}
}

void aes_ccm_128_init(struct aes_ccm_128_context *ctx,
const uint8_t K[AES_BLOCK_SIZE],
const uint8_t N[AES_CCM_128_NONCE_SIZE],
size_t a_total, size_t m_total)
{
uint8_t B_0[AES_BLOCK_SIZE];

ZERO_STRUCTP(ctx);

AES_set_encrypt_key(K, 128, &ctx->aes_key);
Expand All @@ -52,22 +39,23 @@ void aes_ccm_128_init(struct aes_ccm_128_context *ctx,
/*
* prepare B_0
*/
B_0[0] = L_;
B_0[0] += 8 * M_;
ctx->B_i[0] = L_;
ctx->B_i[0] += 8 * M_;
if (a_total > 0) {
B_0[0] += 64;
ctx->B_i[0] += 64;
}
memcpy(&B_0[1], ctx->nonce, AES_CCM_128_NONCE_SIZE);
RSIVAL(B_0, (AES_BLOCK_SIZE - AES_CCM_128_L), m_total);
memcpy(&ctx->B_i[1], ctx->nonce, AES_CCM_128_NONCE_SIZE);
RSIVAL(ctx->B_i, (AES_BLOCK_SIZE - AES_CCM_128_L), m_total);

/*
* prepare X_1
*/
AES_encrypt(B_0, ctx->X_i, &ctx->aes_key);
AES_encrypt(ctx->B_i, ctx->X_i, &ctx->aes_key);

/*
* prepare B_1
*/
ZERO_STRUCT(ctx->B_i);
if (a_total >= UINT32_MAX) {
RSSVAL(ctx->B_i, 0, 0xFFFF);
RSBVAL(ctx->B_i, 2, (uint64_t)a_total);
Expand All @@ -81,6 +69,12 @@ void aes_ccm_128_init(struct aes_ccm_128_context *ctx,
ctx->B_i_ofs = 2;
}

/*
* prepare A_i
*/
ctx->A_i[0] = L_;
memcpy(&ctx->A_i[1], ctx->nonce, AES_CCM_128_NONCE_SIZE);

ctx->S_i_ofs = AES_BLOCK_SIZE;
}

Expand All @@ -89,51 +83,70 @@ void aes_ccm_128_update(struct aes_ccm_128_context *ctx,
{
size_t *remain;

if (v_len == 0) {
return;
}

if (ctx->a_remain > 0) {
remain = &ctx->a_remain;
} else {
remain = &ctx->m_remain;
}

while (v_len > 0) {
if (unlikely(v_len > *remain)) {
abort();
}

if (ctx->B_i_ofs > 0) {
size_t n = MIN(AES_BLOCK_SIZE - ctx->B_i_ofs, v_len);
bool more = true;

memcpy(&ctx->B_i[ctx->B_i_ofs], v, n);
v += n;
v_len -= n;
ctx->B_i_ofs += n;
*remain -= n;
}

if (ctx->B_i_ofs == AES_BLOCK_SIZE) {
more = false;
} else if (*remain == 0) {
more = false;
}

if (more) {
continue;
}
if ((ctx->B_i_ofs == AES_BLOCK_SIZE) || (*remain == 0)) {
aes_block_xor(ctx->X_i, ctx->B_i, ctx->B_i);
AES_encrypt(ctx->B_i, ctx->X_i, &ctx->aes_key);
ctx->B_i_ofs = 0;
}

aes_ccm_128_xor(ctx->X_i, ctx->B_i, ctx->B_i);
while (v_len >= AES_BLOCK_SIZE) {
aes_block_xor(ctx->X_i, v, ctx->B_i);
AES_encrypt(ctx->B_i, ctx->X_i, &ctx->aes_key);
v += AES_BLOCK_SIZE;
v_len -= AES_BLOCK_SIZE;
*remain -= AES_BLOCK_SIZE;
}

if (v_len > 0) {
ZERO_STRUCT(ctx->B_i);
memcpy(ctx->B_i, v, v_len);
ctx->B_i_ofs += v_len;
*remain -= v_len;
v = NULL;
v_len = 0;
}

if (*remain > 0) {
return;
}

if (ctx->B_i_ofs > 0) {
aes_block_xor(ctx->X_i, ctx->B_i, ctx->B_i);
AES_encrypt(ctx->B_i, ctx->X_i, &ctx->aes_key);
ctx->B_i_ofs = 0;
}
}

static void aes_ccm_128_S_i(struct aes_ccm_128_context *ctx,
uint8_t S_i[AES_BLOCK_SIZE],
size_t i)
static inline void aes_ccm_128_S_i(struct aes_ccm_128_context *ctx,
uint8_t S_i[AES_BLOCK_SIZE],
size_t i)
{
uint8_t A_i[AES_BLOCK_SIZE];

A_i[0] = L_;
memcpy(&A_i[1], ctx->nonce, AES_CCM_128_NONCE_SIZE);
RSIVAL(A_i, (AES_BLOCK_SIZE - AES_CCM_128_L), i);

AES_encrypt(A_i, S_i, &ctx->aes_key);
RSIVAL(ctx->A_i, (AES_BLOCK_SIZE - AES_CCM_128_L), i);
AES_encrypt(ctx->A_i, S_i, &ctx->aes_key);
}

void aes_ccm_128_crypt(struct aes_ccm_128_context *ctx,
Expand All @@ -146,6 +159,15 @@ void aes_ccm_128_crypt(struct aes_ccm_128_context *ctx,
ctx->S_i_ofs = 0;
}

if (likely(ctx->S_i_ofs == 0 && m_len >= AES_BLOCK_SIZE)) {
aes_block_xor(m, ctx->S_i, m);
m += AES_BLOCK_SIZE;
m_len -= AES_BLOCK_SIZE;
ctx->S_i_ctr += 1;
aes_ccm_128_S_i(ctx, ctx->S_i, ctx->S_i_ctr);
continue;
}

m[0] ^= ctx->S_i[ctx->S_i_ofs];
m += 1;
m_len -= 1;
Expand All @@ -156,15 +178,20 @@ void aes_ccm_128_crypt(struct aes_ccm_128_context *ctx,
void aes_ccm_128_digest(struct aes_ccm_128_context *ctx,
uint8_t digest[AES_BLOCK_SIZE])
{
uint8_t S_0[AES_BLOCK_SIZE];
if (unlikely(ctx->a_remain != 0)) {
abort();
}
if (unlikely(ctx->m_remain != 0)) {
abort();
}

aes_ccm_128_S_i(ctx, S_0, 0);
/* prepare S_0 */
aes_ccm_128_S_i(ctx, ctx->S_i, 0);

/*
* note X_i is T here
*/
aes_ccm_128_xor(ctx->X_i, S_0, digest);
aes_block_xor(ctx->X_i, ctx->S_i, digest);

ZERO_STRUCT(S_0);
ZERO_STRUCTP(ctx);
}
8 changes: 6 additions & 2 deletions lib/crypto/aes_ccm_128.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,20 @@

struct aes_ccm_128_context {
AES_KEY aes_key;

uint8_t nonce[AES_CCM_128_NONCE_SIZE];

size_t a_remain;
size_t m_remain;

uint64_t __align;

uint8_t X_i[AES_BLOCK_SIZE];
uint8_t B_i[AES_BLOCK_SIZE];
size_t B_i_ofs;

uint8_t A_i[AES_BLOCK_SIZE];
uint8_t S_i[AES_BLOCK_SIZE];

size_t B_i_ofs;
size_t S_i_ofs;
size_t S_i_ctr;
};
Expand Down

0 comments on commit 7e8333d

Please sign in to comment.