version 1.2.6.1, 2012/05/23 10:07:05 |
version 1.2.6.2, 2014/05/22 13:21:35 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
/* $OpenBSD: umac.c,v 1.4 2011/10/19 10:39:48 djm Exp $ */ |
/* $OpenBSD: umac.c,v 1.7.2.1 2013/11/08 01:33:56 djm Exp $ */ |
/* ----------------------------------------------------------------------- |
/* ----------------------------------------------------------------------- |
* |
* |
* umac.c -- C Implementation UMAC Message Authentication |
* umac.c -- C Implementation UMAC Message Authentication |
Line 138 typedef unsigned int UWORD; /* Register |
|
Line 138 typedef unsigned int UWORD; /* Register |
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
#if !defined(__OpenBSD__) |
#if !defined(__OpenBSD__) |
static UINT32 LOAD_UINT32_REVERSED(void *ptr) |
static UINT32 LOAD_UINT32_REVERSED(const void *ptr) |
{ |
{ |
UINT32 temp = *(UINT32 *)ptr; |
UINT32 temp = *(const UINT32 *)ptr; |
temp = (temp >> 24) | ((temp & 0x00FF0000) >> 8 ) |
temp = (temp >> 24) | ((temp & 0x00FF0000) >> 8 ) |
| ((temp & 0x0000FF00) << 8 ) | (temp << 24); |
| ((temp & 0x0000FF00) << 8 ) | (temp << 24); |
return (UINT32)temp; |
return (UINT32)temp; |
Line 159 static void STORE_UINT32_REVERSED(void * |
|
Line 159 static void STORE_UINT32_REVERSED(void * |
|
* thing on endian specific load and stores. |
* thing on endian specific load and stores. |
*/ |
*/ |
|
|
#define LOAD_UINT32_REVERSED(p) (swap32(*(UINT32 *)(p))) |
#define LOAD_UINT32_REVERSED(p) (swap32(*(const UINT32 *)(p))) |
#define STORE_UINT32_REVERSED(p,v) (*(UINT32 *)(p) = swap32(v)) |
#define STORE_UINT32_REVERSED(p,v) (*(UINT32 *)(p) = swap32(v)) |
#endif |
#endif |
|
|
#if (__LITTLE_ENDIAN__) |
#if (__LITTLE_ENDIAN__) |
#define LOAD_UINT32_LITTLE(ptr) (*(UINT32 *)(ptr)) |
#define LOAD_UINT32_LITTLE(ptr) (*(const UINT32 *)(ptr)) |
#define STORE_UINT32_BIG(ptr,x) STORE_UINT32_REVERSED(ptr,x) |
#define STORE_UINT32_BIG(ptr,x) STORE_UINT32_REVERSED(ptr,x) |
#else |
#else |
#define LOAD_UINT32_LITTLE(ptr) LOAD_UINT32_REVERSED(ptr) |
#define LOAD_UINT32_LITTLE(ptr) LOAD_UINT32_REVERSED(ptr) |
Line 189 typedef AES_KEY aes_int_key[1]; |
|
Line 189 typedef AES_KEY aes_int_key[1]; |
|
#define aes_encryption(in,out,int_key) \ |
#define aes_encryption(in,out,int_key) \ |
AES_encrypt((u_char *)(in),(u_char *)(out),(AES_KEY *)int_key) |
AES_encrypt((u_char *)(in),(u_char *)(out),(AES_KEY *)int_key) |
#define aes_key_setup(key,int_key) \ |
#define aes_key_setup(key,int_key) \ |
AES_set_encrypt_key((u_char *)(key),UMAC_KEY_LEN*8,int_key) |
AES_set_encrypt_key((const u_char *)(key),UMAC_KEY_LEN*8,int_key) |
|
|
/* The user-supplied UMAC key is stretched using AES in a counter |
/* The user-supplied UMAC key is stretched using AES in a counter |
* mode to supply all random bits needed by UMAC. The kdf function takes |
* mode to supply all random bits needed by UMAC. The kdf function takes |
Line 245 static void pdf_init(pdf_ctx *pc, aes_in |
|
Line 245 static void pdf_init(pdf_ctx *pc, aes_in |
|
aes_encryption(pc->nonce, pc->cache, pc->prf_key); |
aes_encryption(pc->nonce, pc->cache, pc->prf_key); |
} |
} |
|
|
static void pdf_gen_xor(pdf_ctx *pc, UINT8 nonce[8], UINT8 buf[8]) |
static void pdf_gen_xor(pdf_ctx *pc, const UINT8 nonce[8], UINT8 buf[8]) |
{ |
{ |
/* 'ndx' indicates that we'll be using the 0th or 1st eight bytes |
/* 'ndx' indicates that we'll be using the 0th or 1st eight bytes |
* of the AES output. If last time around we returned the ndx-1st |
* of the AES output. If last time around we returned the ndx-1st |
Line 259 static void pdf_gen_xor(pdf_ctx *pc, UIN |
|
Line 259 static void pdf_gen_xor(pdf_ctx *pc, UIN |
|
#elif (UMAC_OUTPUT_LEN > 8) |
#elif (UMAC_OUTPUT_LEN > 8) |
#define LOW_BIT_MASK 0 |
#define LOW_BIT_MASK 0 |
#endif |
#endif |
|
union { |
UINT8 tmp_nonce_lo[4]; |
UINT8 tmp_nonce_lo[4]; |
|
UINT32 align; |
|
} t; |
#if LOW_BIT_MASK != 0 |
#if LOW_BIT_MASK != 0 |
int ndx = nonce[7] & LOW_BIT_MASK; |
int ndx = nonce[7] & LOW_BIT_MASK; |
#endif |
#endif |
*(UINT32 *)tmp_nonce_lo = ((UINT32 *)nonce)[1]; |
*(UINT32 *)t.tmp_nonce_lo = ((const UINT32 *)nonce)[1]; |
tmp_nonce_lo[3] &= ~LOW_BIT_MASK; /* zero last bit */ |
t.tmp_nonce_lo[3] &= ~LOW_BIT_MASK; /* zero last bit */ |
|
|
if ( (((UINT32 *)tmp_nonce_lo)[0] != ((UINT32 *)pc->nonce)[1]) || |
if ( (((UINT32 *)t.tmp_nonce_lo)[0] != ((UINT32 *)pc->nonce)[1]) || |
(((UINT32 *)nonce)[0] != ((UINT32 *)pc->nonce)[0]) ) |
(((const UINT32 *)nonce)[0] != ((UINT32 *)pc->nonce)[0]) ) |
{ |
{ |
((UINT32 *)pc->nonce)[0] = ((UINT32 *)nonce)[0]; |
((UINT32 *)pc->nonce)[0] = ((const UINT32 *)nonce)[0]; |
((UINT32 *)pc->nonce)[1] = ((UINT32 *)tmp_nonce_lo)[0]; |
((UINT32 *)pc->nonce)[1] = ((UINT32 *)t.tmp_nonce_lo)[0]; |
aes_encryption(pc->nonce, pc->cache, pc->prf_key); |
aes_encryption(pc->nonce, pc->cache, pc->prf_key); |
} |
} |
|
|
Line 338 typedef struct { |
|
Line 340 typedef struct { |
|
|
|
#if (UMAC_OUTPUT_LEN == 4) |
#if (UMAC_OUTPUT_LEN == 4) |
|
|
static void nh_aux(void *kp, void *dp, void *hp, UINT32 dlen) |
static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen) |
/* NH hashing primitive. Previous (partial) hash result is loaded and |
/* NH hashing primitive. Previous (partial) hash result is loaded and |
* then stored via hp pointer. The length of the data pointed at by "dp", |
* then stored via hp pointer. The length of the data pointed at by "dp", |
* "dlen", is guaranteed to be divisible by L1_PAD_BOUNDARY (32). Key |
* "dlen", is guaranteed to be divisible by L1_PAD_BOUNDARY (32). Key |
Line 348 static void nh_aux(void *kp, void *dp, v |
|
Line 350 static void nh_aux(void *kp, void *dp, v |
|
UINT64 h; |
UINT64 h; |
UWORD c = dlen / 32; |
UWORD c = dlen / 32; |
UINT32 *k = (UINT32 *)kp; |
UINT32 *k = (UINT32 *)kp; |
UINT32 *d = (UINT32 *)dp; |
const UINT32 *d = (const UINT32 *)dp; |
UINT32 d0,d1,d2,d3,d4,d5,d6,d7; |
UINT32 d0,d1,d2,d3,d4,d5,d6,d7; |
UINT32 k0,k1,k2,k3,k4,k5,k6,k7; |
UINT32 k0,k1,k2,k3,k4,k5,k6,k7; |
|
|
Line 373 static void nh_aux(void *kp, void *dp, v |
|
Line 375 static void nh_aux(void *kp, void *dp, v |
|
|
|
#elif (UMAC_OUTPUT_LEN == 8) |
#elif (UMAC_OUTPUT_LEN == 8) |
|
|
static void nh_aux(void *kp, void *dp, void *hp, UINT32 dlen) |
static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen) |
/* Same as previous nh_aux, but two streams are handled in one pass, |
/* Same as previous nh_aux, but two streams are handled in one pass, |
* reading and writing 16 bytes of hash-state per call. |
* reading and writing 16 bytes of hash-state per call. |
*/ |
*/ |
Line 381 static void nh_aux(void *kp, void *dp, v |
|
Line 383 static void nh_aux(void *kp, void *dp, v |
|
UINT64 h1,h2; |
UINT64 h1,h2; |
UWORD c = dlen / 32; |
UWORD c = dlen / 32; |
UINT32 *k = (UINT32 *)kp; |
UINT32 *k = (UINT32 *)kp; |
UINT32 *d = (UINT32 *)dp; |
const UINT32 *d = (const UINT32 *)dp; |
UINT32 d0,d1,d2,d3,d4,d5,d6,d7; |
UINT32 d0,d1,d2,d3,d4,d5,d6,d7; |
UINT32 k0,k1,k2,k3,k4,k5,k6,k7, |
UINT32 k0,k1,k2,k3,k4,k5,k6,k7, |
k8,k9,k10,k11; |
k8,k9,k10,k11; |
Line 420 static void nh_aux(void *kp, void *dp, v |
|
Line 422 static void nh_aux(void *kp, void *dp, v |
|
|
|
#elif (UMAC_OUTPUT_LEN == 12) |
#elif (UMAC_OUTPUT_LEN == 12) |
|
|
static void nh_aux(void *kp, void *dp, void *hp, UINT32 dlen) |
static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen) |
/* Same as previous nh_aux, but two streams are handled in one pass, |
/* Same as previous nh_aux, but two streams are handled in one pass, |
* reading and writing 24 bytes of hash-state per call. |
* reading and writing 24 bytes of hash-state per call. |
*/ |
*/ |
Line 428 static void nh_aux(void *kp, void *dp, v |
|
Line 430 static void nh_aux(void *kp, void *dp, v |
|
UINT64 h1,h2,h3; |
UINT64 h1,h2,h3; |
UWORD c = dlen / 32; |
UWORD c = dlen / 32; |
UINT32 *k = (UINT32 *)kp; |
UINT32 *k = (UINT32 *)kp; |
UINT32 *d = (UINT32 *)dp; |
const UINT32 *d = (const UINT32 *)dp; |
UINT32 d0,d1,d2,d3,d4,d5,d6,d7; |
UINT32 d0,d1,d2,d3,d4,d5,d6,d7; |
UINT32 k0,k1,k2,k3,k4,k5,k6,k7, |
UINT32 k0,k1,k2,k3,k4,k5,k6,k7, |
k8,k9,k10,k11,k12,k13,k14,k15; |
k8,k9,k10,k11,k12,k13,k14,k15; |
Line 475 static void nh_aux(void *kp, void *dp, v |
|
Line 477 static void nh_aux(void *kp, void *dp, v |
|
|
|
#elif (UMAC_OUTPUT_LEN == 16) |
#elif (UMAC_OUTPUT_LEN == 16) |
|
|
static void nh_aux(void *kp, void *dp, void *hp, UINT32 dlen) |
static void nh_aux(void *kp, const void *dp, void *hp, UINT32 dlen) |
/* Same as previous nh_aux, but two streams are handled in one pass, |
/* Same as previous nh_aux, but two streams are handled in one pass, |
* reading and writing 24 bytes of hash-state per call. |
* reading and writing 24 bytes of hash-state per call. |
*/ |
*/ |
Line 483 static void nh_aux(void *kp, void *dp, v |
|
Line 485 static void nh_aux(void *kp, void *dp, v |
|
UINT64 h1,h2,h3,h4; |
UINT64 h1,h2,h3,h4; |
UWORD c = dlen / 32; |
UWORD c = dlen / 32; |
UINT32 *k = (UINT32 *)kp; |
UINT32 *k = (UINT32 *)kp; |
UINT32 *d = (UINT32 *)dp; |
const UINT32 *d = (const UINT32 *)dp; |
UINT32 d0,d1,d2,d3,d4,d5,d6,d7; |
UINT32 d0,d1,d2,d3,d4,d5,d6,d7; |
UINT32 k0,k1,k2,k3,k4,k5,k6,k7, |
UINT32 k0,k1,k2,k3,k4,k5,k6,k7, |
k8,k9,k10,k11,k12,k13,k14,k15, |
k8,k9,k10,k11,k12,k13,k14,k15, |
Line 544 static void nh_aux(void *kp, void *dp, v |
|
Line 546 static void nh_aux(void *kp, void *dp, v |
|
|
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
static void nh_transform(nh_ctx *hc, UINT8 *buf, UINT32 nbytes) |
static void nh_transform(nh_ctx *hc, const UINT8 *buf, UINT32 nbytes) |
/* This function is a wrapper for the primitive NH hash functions. It takes |
/* This function is a wrapper for the primitive NH hash functions. It takes |
* as argument "hc" the current hash context and a buffer which must be a |
* as argument "hc" the current hash context and a buffer which must be a |
* multiple of L1_PAD_BOUNDARY. The key passed to nh_aux is offset |
* multiple of L1_PAD_BOUNDARY. The key passed to nh_aux is offset |
Line 621 static void nh_init(nh_ctx *hc, aes_int_ |
|
Line 623 static void nh_init(nh_ctx *hc, aes_int_ |
|
|
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
static void nh_update(nh_ctx *hc, UINT8 *buf, UINT32 nbytes) |
static void nh_update(nh_ctx *hc, const UINT8 *buf, UINT32 nbytes) |
/* Incorporate nbytes of data into a nh_ctx, buffer whatever is not an */ |
/* Incorporate nbytes of data into a nh_ctx, buffer whatever is not an */ |
/* even multiple of HASH_BUF_BYTES. */ |
/* even multiple of HASH_BUF_BYTES. */ |
{ |
{ |
Line 716 static void nh_final(nh_ctx *hc, UINT8 * |
|
Line 718 static void nh_final(nh_ctx *hc, UINT8 * |
|
|
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
static void nh(nh_ctx *hc, UINT8 *buf, UINT32 padded_len, |
static void nh(nh_ctx *hc, const UINT8 *buf, UINT32 padded_len, |
UINT32 unpadded_len, UINT8 *result) |
UINT32 unpadded_len, UINT8 *result) |
/* All-in-one nh_update() and nh_final() equivalent. |
/* All-in-one nh_update() and nh_final() equivalent. |
* Assumes that padded_len is divisible by L1_PAD_BOUNDARY and result is |
* Assumes that padded_len is divisible by L1_PAD_BOUNDARY and result is |
Line 1054 static int uhash_free(uhash_ctx_t ctx) |
|
Line 1056 static int uhash_free(uhash_ctx_t ctx) |
|
#endif |
#endif |
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
static int uhash_update(uhash_ctx_t ctx, u_char *input, long len) |
static int uhash_update(uhash_ctx_t ctx, const u_char *input, long len) |
/* Given len bytes of data, we parse it into L1_KEY_LEN chunks and |
/* Given len bytes of data, we parse it into L1_KEY_LEN chunks and |
* hash each one with NH, calling the polyhash on each NH output. |
* hash each one with NH, calling the polyhash on each NH output. |
*/ |
*/ |
Line 1064 static int uhash_update(uhash_ctx_t ctx, |
|
Line 1066 static int uhash_update(uhash_ctx_t ctx, |
|
UINT8 *nh_result = (UINT8 *)&result_buf; |
UINT8 *nh_result = (UINT8 *)&result_buf; |
|
|
if (ctx->msg_len + len <= L1_KEY_LEN) { |
if (ctx->msg_len + len <= L1_KEY_LEN) { |
nh_update(&ctx->hash, (UINT8 *)input, len); |
nh_update(&ctx->hash, (const UINT8 *)input, len); |
ctx->msg_len += len; |
ctx->msg_len += len; |
} else { |
} else { |
|
|
Line 1079 static int uhash_update(uhash_ctx_t ctx, |
|
Line 1081 static int uhash_update(uhash_ctx_t ctx, |
|
/* bytes to complete the current nh_block. */ |
/* bytes to complete the current nh_block. */ |
if (bytes_hashed) { |
if (bytes_hashed) { |
bytes_remaining = (L1_KEY_LEN - bytes_hashed); |
bytes_remaining = (L1_KEY_LEN - bytes_hashed); |
nh_update(&ctx->hash, (UINT8 *)input, bytes_remaining); |
nh_update(&ctx->hash, (const UINT8 *)input, bytes_remaining); |
nh_final(&ctx->hash, nh_result); |
nh_final(&ctx->hash, nh_result); |
ctx->msg_len += bytes_remaining; |
ctx->msg_len += bytes_remaining; |
poly_hash(ctx,(UINT32 *)nh_result); |
poly_hash(ctx,(UINT32 *)nh_result); |
Line 1089 static int uhash_update(uhash_ctx_t ctx, |
|
Line 1091 static int uhash_update(uhash_ctx_t ctx, |
|
|
|
/* Hash directly from input stream if enough bytes */ |
/* Hash directly from input stream if enough bytes */ |
while (len >= L1_KEY_LEN) { |
while (len >= L1_KEY_LEN) { |
nh(&ctx->hash, (UINT8 *)input, L1_KEY_LEN, |
nh(&ctx->hash, (const UINT8 *)input, L1_KEY_LEN, |
L1_KEY_LEN, nh_result); |
L1_KEY_LEN, nh_result); |
ctx->msg_len += L1_KEY_LEN; |
ctx->msg_len += L1_KEY_LEN; |
len -= L1_KEY_LEN; |
len -= L1_KEY_LEN; |
Line 1100 static int uhash_update(uhash_ctx_t ctx, |
|
Line 1102 static int uhash_update(uhash_ctx_t ctx, |
|
|
|
/* pass remaining < L1_KEY_LEN bytes of input data to NH */ |
/* pass remaining < L1_KEY_LEN bytes of input data to NH */ |
if (len) { |
if (len) { |
nh_update(&ctx->hash, (UINT8 *)input, len); |
nh_update(&ctx->hash, (const UINT8 *)input, len); |
ctx->msg_len += len; |
ctx->msg_len += len; |
} |
} |
} |
} |
Line 1216 int umac_delete(struct umac_ctx *ctx) |
|
Line 1218 int umac_delete(struct umac_ctx *ctx) |
|
if (ctx) { |
if (ctx) { |
if (ALLOC_BOUNDARY) |
if (ALLOC_BOUNDARY) |
ctx = (struct umac_ctx *)ctx->free_ptr; |
ctx = (struct umac_ctx *)ctx->free_ptr; |
xfree(ctx); |
free(ctx); |
} |
} |
return (1); |
return (1); |
} |
} |
|
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
struct umac_ctx *umac_new(u_char key[]) |
struct umac_ctx *umac_new(const u_char key[]) |
/* Dynamically allocate a umac_ctx struct, initialize variables, |
/* Dynamically allocate a umac_ctx struct, initialize variables, |
* generate subkeys from key. Align to 16-byte boundary. |
* generate subkeys from key. Align to 16-byte boundary. |
*/ |
*/ |
Line 1232 struct umac_ctx *umac_new(u_char key[]) |
|
Line 1234 struct umac_ctx *umac_new(u_char key[]) |
|
size_t bytes_to_add; |
size_t bytes_to_add; |
aes_int_key prf_key; |
aes_int_key prf_key; |
|
|
octx = ctx = xmalloc(sizeof(*ctx) + ALLOC_BOUNDARY); |
octx = ctx = xcalloc(1, sizeof(*ctx) + ALLOC_BOUNDARY); |
if (ctx) { |
if (ctx) { |
if (ALLOC_BOUNDARY) { |
if (ALLOC_BOUNDARY) { |
bytes_to_add = ALLOC_BOUNDARY - |
bytes_to_add = ALLOC_BOUNDARY - |
Line 1240 struct umac_ctx *umac_new(u_char key[]) |
|
Line 1242 struct umac_ctx *umac_new(u_char key[]) |
|
ctx = (struct umac_ctx *)((u_char *)ctx + bytes_to_add); |
ctx = (struct umac_ctx *)((u_char *)ctx + bytes_to_add); |
} |
} |
ctx->free_ptr = octx; |
ctx->free_ptr = octx; |
aes_key_setup(key,prf_key); |
aes_key_setup(key, prf_key); |
pdf_init(&ctx->pdf, prf_key); |
pdf_init(&ctx->pdf, prf_key); |
uhash_init(&ctx->hash, prf_key); |
uhash_init(&ctx->hash, prf_key); |
} |
} |
Line 1250 struct umac_ctx *umac_new(u_char key[]) |
|
Line 1252 struct umac_ctx *umac_new(u_char key[]) |
|
|
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
int umac_final(struct umac_ctx *ctx, u_char tag[], u_char nonce[8]) |
int umac_final(struct umac_ctx *ctx, u_char tag[], const u_char nonce[8]) |
/* Incorporate any pending data, pad, and generate tag */ |
/* Incorporate any pending data, pad, and generate tag */ |
{ |
{ |
uhash_final(&ctx->hash, (u_char *)tag); |
uhash_final(&ctx->hash, (u_char *)tag); |
pdf_gen_xor(&ctx->pdf, (UINT8 *)nonce, (UINT8 *)tag); |
pdf_gen_xor(&ctx->pdf, (const UINT8 *)nonce, (UINT8 *)tag); |
|
|
return (1); |
return (1); |
} |
} |
|
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
int umac_update(struct umac_ctx *ctx, u_char *input, long len) |
int umac_update(struct umac_ctx *ctx, const u_char *input, long len) |
/* Given len bytes of data, we parse it into L1_KEY_LEN chunks and */ |
/* Given len bytes of data, we parse it into L1_KEY_LEN chunks and */ |
/* hash each one, calling the PDF on the hashed output whenever the hash- */ |
/* hash each one, calling the PDF on the hashed output whenever the hash- */ |
/* output buffer is full. */ |
/* output buffer is full. */ |