Commit 31b0f854 authored by Davide Galassi's avatar Davide Galassi

CMAC: incremental update implementation

parent b8f39caf
...@@ -15,12 +15,14 @@ ...@@ -15,12 +15,14 @@
extern "C"{ extern "C"{
#endif #endif
#define CRY_CMAC_BLOCK_SIZE 16
struct cry_cmac_ctx { struct cry_cmac_ctx {
void *ciph_ctx; /**< Block cipher context */ void *ciph_ctx; /**< Block cipher context */
const struct cry_ciph_itf *ciph_itf; /**< Block cipher interface */ const struct cry_ciph_itf *ciph_itf; /**< Block cipher interface */
unsigned char k1[16]; size_t blklen; /**< Pending block size */
unsigned char k2[16]; unsigned char blk[CRY_CMAC_BLOCK_SIZE]; /**< Pending block */
unsigned char mac[16]; unsigned char mac[CRY_CMAC_BLOCK_SIZE]; /**< Current MAC */
}; };
typedef struct cry_cmac_ctx cry_cmac_ctx; typedef struct cry_cmac_ctx cry_cmac_ctx;
......
#include <cry/cmac.h> #include <cry/cmac.h>
#include <string.h> #include <string.h>
#include "misc.h"
static void xor_128(unsigned char *o, const unsigned char *a, static void xor_128(unsigned char *o, const unsigned char *a,
const unsigned char *b) const unsigned char *b)
{ {
size_t i; size_t i;
for (i = 0; i < 16; i++) for (i = 0; i < CRY_CMAC_BLOCK_SIZE; i++)
o[i] = a[i] ^ b[i]; o[i] = a[i] ^ b[i];
} }
static void cbc_compute_subkeys(cry_cmac_ctx *ctx) static void cbc_compute_subkeys(cry_cmac_ctx *ctx,
unsigned char *k1, unsigned char *k2)
{ {
unsigned char blank[16] = {0}; unsigned char blank[CRY_CMAC_BLOCK_SIZE] = {0};
unsigned char msb; unsigned char msb;
size_t i; size_t i;
unsigned char *k1 = ctx->k1;
unsigned char *k2 = ctx->k2;
ctx->ciph_itf->encrypt(ctx->ciph_ctx, k1, blank, 16); ctx->ciph_itf->encrypt(ctx->ciph_ctx, k1, blank, CRY_CMAC_BLOCK_SIZE);
msb = (k1[0] & 0x80); msb = (k1[0] & 0x80);
for (i = 0; i < 16; i++) { for (i = 0; i < CRY_CMAC_BLOCK_SIZE; i++) {
k1[i] <<= 1; k1[i] <<= 1;
if (i < 15 && ((k1[i + 1] & 0x80) != 0)) if (i < CRY_CMAC_BLOCK_SIZE-1 && ((k1[i + 1] & 0x80) != 0))
k1[i] |= 1; k1[i] |= 1;
} }
if (msb != 0) if (msb != 0)
k1[15] ^= 0x87; k1[CRY_CMAC_BLOCK_SIZE-1] ^= 0x87;
msb = (k1[0] & 0x80); msb = (k1[0] & 0x80);
for (i = 0; i < 16; i++) { for (i = 0; i < CRY_CMAC_BLOCK_SIZE; i++) {
k2[i] = k1[i] << 1; k2[i] = k1[i] << 1;
if (i < 15 && ((k1[i + 1] & 0x80) != 0)) if (i < CRY_CMAC_BLOCK_SIZE-1 && ((k1[i + 1] & 0x80) != 0))
k2[i] |= 1; k2[i] |= 1;
} }
if (msb != 0) if (msb != 0)
k2[15] ^= 0x87; k2[CRY_CMAC_BLOCK_SIZE-1] ^= 0x87;
} }
static void pad(unsigned char *pad, const unsigned char *last, size_t size)
{
size_t i;
for (i = 0; i < 16; i++) {
if (i < size)
pad[i] = last[i];
else if (i == size)
pad[i] = 0x80;
else
pad[i] = 0x00;
}
}
void cry_cmac_init(cry_cmac_ctx *ctx, void *ciph_ctx, void cry_cmac_init(cry_cmac_ctx *ctx, void *ciph_ctx,
...@@ -62,45 +51,68 @@ void cry_cmac_init(cry_cmac_ctx *ctx, void *ciph_ctx, ...@@ -62,45 +51,68 @@ void cry_cmac_init(cry_cmac_ctx *ctx, void *ciph_ctx,
ctx->ciph_ctx = ciph_ctx; ctx->ciph_ctx = ciph_ctx;
ctx->ciph_itf = ciph_itf; ctx->ciph_itf = ciph_itf;
ciph_itf->key_set(ciph_ctx, key, keylen); ciph_itf->key_set(ciph_ctx, key, keylen);
cbc_compute_subkeys(ctx);
} }
void cry_cmac_update(cry_cmac_ctx *ctx, const unsigned char *data, size_t len) void cry_cmac_update(cry_cmac_ctx *ctx, const unsigned char *data, size_t len)
{ {
unsigned char block[16], last[16], padded[16]; unsigned char block[CRY_CMAC_BLOCK_SIZE];
size_t n, i; size_t n, i;
int flag;
n = (len + 15) / 16; /* n is number of rounds */ /* There was an incomplete block */
if (n == 0) { if (ctx->blklen > 0) {
n = 1; n = CRY_MIN(len, CRY_CMAC_BLOCK_SIZE - ctx->blklen);
flag = 0; memcpy(ctx->blk + ctx->blklen, data, n);
} else { len -= n;
if ((len % 16) == 0) data += n;
flag = 1; /* last block is a complete block */ ctx->blklen += n;
else if (ctx->blklen < CRY_CMAC_BLOCK_SIZE || len == 0)
flag = 0; /* last block is not complete block */ return; /* may be the last block */
xor_128(block, ctx->mac, ctx->blk);
ctx->ciph_itf->encrypt(ctx->ciph_ctx, ctx->mac, block, CRY_CMAC_BLOCK_SIZE);
} }
if (flag) { /* Compute number of rounds */
/* last block is complete block */ n = (len + CRY_CMAC_BLOCK_SIZE-1) / CRY_CMAC_BLOCK_SIZE;
xor_128(last, &data[16*(n-1)], ctx->k1); if (n == 0)
} else { return;
pad(padded, &data[16*(n-1)], len % 16); n--;
xor_128(last, padded, ctx->k2);
}
memset(ctx->mac, 0, 16); /* last block shall be processed in the digest */
for (i = 0; i < (n - 1); i++) { for (i = 0; i < n; i++) {
xor_128(block, ctx->mac, &data[16*i]); xor_128(block, ctx->mac, &data[CRY_CMAC_BLOCK_SIZE*i]);
ctx->ciph_itf->encrypt(ctx->ciph_ctx, ctx->mac, block, 16); ctx->ciph_itf->encrypt(ctx->ciph_ctx, ctx->mac, block, CRY_CMAC_BLOCK_SIZE);
} }
xor_128(block, ctx->mac, last); /* last block is not complete block */
ctx->ciph_itf->encrypt(ctx->ciph_ctx, ctx->mac, block, 16); ctx->blklen = len % CRY_CMAC_BLOCK_SIZE;
if (ctx->blklen == 0)
ctx->blklen = CRY_CMAC_BLOCK_SIZE;
memcpy(ctx->blk, &data[CRY_CMAC_BLOCK_SIZE*n], ctx->blklen);
}
static void pad(unsigned char *blk, size_t size)
{
size_t i;
blk[size] = 0x80;
for (i = size + 1; i < CRY_CMAC_BLOCK_SIZE; i++)
blk[i] = 0x00;
} }
void cry_cmac_digest(cry_cmac_ctx *ctx, unsigned char *mac) void cry_cmac_digest(cry_cmac_ctx *ctx, unsigned char *mac)
{ {
unsigned char k1[CRY_CMAC_BLOCK_SIZE], k2[CRY_CMAC_BLOCK_SIZE], last[CRY_CMAC_BLOCK_SIZE];
cbc_compute_subkeys(ctx, k1, k2);
if (ctx->blklen == CRY_CMAC_BLOCK_SIZE) {
xor_128(last, ctx->blk, k1);
} else {
pad(ctx->blk, ctx->blklen);
xor_128(last, ctx->blk, k2);
}
xor_128(ctx->blk, ctx->mac, last);
ctx->ciph_itf->encrypt(ctx->ciph_ctx, ctx->mac, ctx->blk, CRY_CMAC_BLOCK_SIZE);
memcpy(mac, ctx->mac, sizeof(ctx->mac)); memcpy(mac, ctx->mac, sizeof(ctx->mac));
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment