version 1.13, 2017/10/27 01:01:17 |
version 1.14, 2017/11/28 06:04:51 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* ----------------------------------------------------------------------- |
/* ----------------------------------------------------------------------- |
* |
* |
* umac.c -- C Implementation UMAC Message Authentication |
* umac.c -- C Implementation UMAC Message Authentication |
* |
* |
* Version 0.93b of rfc4418.txt -- 2006 July 18 |
* Version 0.93b of rfc4418.txt -- 2006 July 18 |
|
|
* Please report bugs and suggestions to the UMAC webpage. |
* Please report bugs and suggestions to the UMAC webpage. |
* |
* |
* Copyright (c) 1999-2006 Ted Krovetz |
* Copyright (c) 1999-2006 Ted Krovetz |
* |
* |
* Permission to use, copy, modify, and distribute this software and |
* Permission to use, copy, modify, and distribute this software and |
* its documentation for any purpose and with or without fee, is hereby |
* its documentation for any purpose and with or without fee, is hereby |
* granted provided that the above copyright notice appears in all copies |
* granted provided that the above copyright notice appears in all copies |
|
|
* holder not be used in advertising or publicity pertaining to |
* holder not be used in advertising or publicity pertaining to |
* distribution of the software without specific, written prior permission. |
* distribution of the software without specific, written prior permission. |
* |
* |
* Comments should be directed to Ted Krovetz (tdk@acm.org) |
* Comments should be directed to Ted Krovetz (tdk@acm.org) |
* |
* |
* ---------------------------------------------------------------------- */ |
* ---------------------------------------------------------------------- */ |
|
|
/* ////////////////////// IMPORTANT NOTES ///////////////////////////////// |
/* ////////////////////// IMPORTANT NOTES ///////////////////////////////// |
|
|
} |
} |
|
|
/* The final UHASH result is XOR'd with the output of a pseudorandom |
/* The final UHASH result is XOR'd with the output of a pseudorandom |
* function. Here, we use AES to generate random output and |
* function. Here, we use AES to generate random output and |
* xor the appropriate bytes depending on the last bits of nonce. |
* xor the appropriate bytes depending on the last bits of nonce. |
* This scheme is optimized for sequential, increasing big-endian nonces. |
* This scheme is optimized for sequential, increasing big-endian nonces. |
*/ |
*/ |
|
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
/* The NH-based hash functions used in UMAC are described in the UMAC paper |
/* The NH-based hash functions used in UMAC are described in the UMAC paper |
* and specification, both of which can be found at the UMAC website. |
* and specification, both of which can be found at the UMAC website. |
* The interface to this implementation has two |
* The interface to this implementation has two |
* versions, one expects the entire message being hashed to be passed |
* versions, one expects the entire message being hashed to be passed |
* in a single buffer and returns the hash result immediately. The second |
* in a single buffer and returns the hash result immediately. The second |
* allows the message to be passed in a sequence of buffers. In the |
* allows the message to be passed in a sequence of buffers. In the |
* muliple-buffer interface, the client calls the routine nh_update() as |
* muliple-buffer interface, the client calls the routine nh_update() as |
* many times as necessary. When there is no more data to be fed to the |
* many times as necessary. When there is no more data to be fed to the |
* hash, the client calls nh_final() which calculates the hash output. |
* hash, the client calls nh_final() which calculates the hash output. |
* Before beginning another hash calculation the nh_reset() routine |
* Before beginning another hash calculation the nh_reset() routine |
* must be called. The single-buffer routine, nh(), is equivalent to |
* must be called. The single-buffer routine, nh(), is equivalent to |
* the sequence of calls nh_update() and nh_final(); however it is |
* the sequence of calls nh_update() and nh_final(); however it is |
* optimized and should be prefered whenever the multiple-buffer interface |
* optimized and should be prefered whenever the multiple-buffer interface |
* is not necessary. When using either interface, it is the client's |
* is not necessary. When using either interface, it is the client's |
* responsability to pass no more than L1_KEY_LEN bytes per hash result. |
* responsability to pass no more than L1_KEY_LEN bytes per hash result. |
* |
* |
* The routine nh_init() initializes the nh_ctx data structure and |
* The routine nh_init() initializes the nh_ctx data structure and |
* must be called once, before any other PDF routine. |
* must be called once, before any other PDF routine. |
*/ |
*/ |
|
|
/* The "nh_aux" routines do the actual NH hashing work. They |
/* The "nh_aux" routines do the actual NH hashing work. They |
* expect buffers to be multiples of L1_PAD_BOUNDARY. These routines |
* expect buffers to be multiples of L1_PAD_BOUNDARY. These routines |
* produce output for all STREAMS NH iterations in one call, |
* produce output for all STREAMS NH iterations in one call, |
* allowing the parallel implementation of the streams. |
* allowing the parallel implementation of the streams. |
*/ |
*/ |
|
|
|
|
#if (UMAC_OUTPUT_LEN == 4) |
#if (UMAC_OUTPUT_LEN == 4) |
|
|
static void nh_aux(void *kp, const 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 |
* is expected to be endian compensated in memory at key setup. |
* is expected to be endian compensated in memory at key setup. |
*/ |
*/ |
{ |
{ |
UINT64 h; |
UINT64 h; |
|
|
if (hc->next_data_empty != 0) { |
if (hc->next_data_empty != 0) { |
nh_len = ((hc->next_data_empty + (L1_PAD_BOUNDARY - 1)) & |
nh_len = ((hc->next_data_empty + (L1_PAD_BOUNDARY - 1)) & |
~(L1_PAD_BOUNDARY - 1)); |
~(L1_PAD_BOUNDARY - 1)); |
zero_pad(hc->data + hc->next_data_empty, |
zero_pad(hc->data + hc->next_data_empty, |
nh_len - hc->next_data_empty); |
nh_len - hc->next_data_empty); |
nh_transform(hc, hc->data, nh_len); |
nh_transform(hc, hc->data, nh_len); |
hc->bytes_hashed += hc->next_data_empty; |
hc->bytes_hashed += hc->next_data_empty; |
|
|
* buffers are presented sequentially. In the sequential interface, the |
* buffers are presented sequentially. In the sequential interface, the |
* UHASH client calls the routine uhash_update() as many times as necessary. |
* UHASH client calls the routine uhash_update() as many times as necessary. |
* When there is no more data to be fed to UHASH, the client calls |
* When there is no more data to be fed to UHASH, the client calls |
* uhash_final() which |
* uhash_final() which |
* calculates the UHASH output. Before beginning another UHASH calculation |
* calculates the UHASH output. Before beginning another UHASH calculation |
* the uhash_reset() routine must be called. The all-at-once UHASH routine, |
* the uhash_reset() routine must be called. The all-at-once UHASH routine, |
* uhash(), is equivalent to the sequence of calls uhash_update() and |
* uhash(), is equivalent to the sequence of calls uhash_update() and |
* uhash_final(); however it is optimized and should be |
* uhash_final(); however it is optimized and should be |
* used whenever the sequential interface is not necessary. |
* used whenever the sequential interface is not necessary. |
* |
* |
* The routine uhash_init() initializes the uhash_ctx data structure and |
* The routine uhash_init() initializes the uhash_ctx data structure and |
* must be called once, before any other UHASH routine. |
* must be called once, before any other UHASH routine. |
*/ |
*/ |
|
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
/* ----- Constants and uhash_ctx ---------------------------------------- */ |
/* ----- Constants and uhash_ctx ---------------------------------------- */ |
|
|
|
|
for (i = 0; i < STREAMS; i++) { |
for (i = 0; i < STREAMS; i++) { |
if ((UINT32)(data[i] >> 32) == 0xfffffffful) { |
if ((UINT32)(data[i] >> 32) == 0xfffffffful) { |
hc->poly_accum[i] = poly64(hc->poly_accum[i], |
hc->poly_accum[i] = poly64(hc->poly_accum[i], |
hc->poly_key_8[i], p64 - 1); |
hc->poly_key_8[i], p64 - 1); |
hc->poly_accum[i] = poly64(hc->poly_accum[i], |
hc->poly_accum[i] = poly64(hc->poly_accum[i], |
hc->poly_key_8[i], (data[i] - 59)); |
hc->poly_key_8[i], (data[i] - 59)); |
|
|
if (ahc->poly_accum[i] >= p64) |
if (ahc->poly_accum[i] >= p64) |
ahc->poly_accum[i] -= p64; |
ahc->poly_accum[i] -= p64; |
t = ip_aux(0,ahc->ip_keys+(i*4), ahc->poly_accum[i]); |
t = ip_aux(0,ahc->ip_keys+(i*4), ahc->poly_accum[i]); |
STORE_UINT32_BIG((UINT32 *)res+i, |
STORE_UINT32_BIG((UINT32 *)res+i, |
ip_reduce_p36(t) ^ ahc->ip_trans[i]); |
ip_reduce_p36(t) ^ ahc->ip_trans[i]); |
} |
} |
} |
} |
|
|
for (i = 0; i < STREAMS; i++) |
for (i = 0; i < STREAMS; i++) |
memcpy(ahc->ip_keys+4*i, buf+(8*i+4)*sizeof(UINT64), |
memcpy(ahc->ip_keys+4*i, buf+(8*i+4)*sizeof(UINT64), |
4*sizeof(UINT64)); |
4*sizeof(UINT64)); |
endian_convert_if_le(ahc->ip_keys, sizeof(UINT64), |
endian_convert_if_le(ahc->ip_keys, sizeof(UINT64), |
sizeof(ahc->ip_keys)); |
sizeof(ahc->ip_keys)); |
for (i = 0; i < STREAMS*4; i++) |
for (i = 0; i < STREAMS*4; i++) |
ahc->ip_keys[i] %= p36; /* Bring into Z_p36 */ |
ahc->ip_keys[i] %= p36; /* Bring into Z_p36 */ |
|
|
*/ |
*/ |
if (len <= L1_KEY_LEN) { |
if (len <= L1_KEY_LEN) { |
if (len == 0) /* If zero length messages will not */ |
if (len == 0) /* If zero length messages will not */ |
nh_len = L1_PAD_BOUNDARY; /* be seen, comment out this case */ |
nh_len = L1_PAD_BOUNDARY; /* be seen, comment out this case */ |
else |
else |
nh_len = ((len + (L1_PAD_BOUNDARY - 1)) & ~(L1_PAD_BOUNDARY - 1)); |
nh_len = ((len + (L1_PAD_BOUNDARY - 1)) & ~(L1_PAD_BOUNDARY - 1)); |
extra_zeroes_needed = nh_len - len; |
extra_zeroes_needed = nh_len - len; |
|
|
|
|
/* The UMAC interface has two interfaces, an all-at-once interface where |
/* The UMAC interface has two interfaces, an all-at-once interface where |
* the entire message to be authenticated is passed to UMAC in one buffer, |
* the entire message to be authenticated is passed to UMAC in one buffer, |
* and a sequential interface where the message is presented a little at a |
* and a sequential interface where the message is presented a little at a |
* time. The all-at-once is more optimaized than the sequential version and |
* time. The all-at-once is more optimaized than the sequential version and |
* should be preferred when the sequential interface is not required. |
* should be preferred when the sequential interface is not required. |
*/ |
*/ |
struct umac_ctx { |
struct umac_ctx { |
uhash_ctx hash; /* Hash function for message compression */ |
uhash_ctx hash; /* Hash function for message compression */ |
|
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
struct umac_ctx *umac_new(const 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. |
*/ |
*/ |
{ |
{ |
|
|
/* ---------------------------------------------------------------------- */ |
/* ---------------------------------------------------------------------- */ |
|
|
#if 0 |
#if 0 |
int umac(struct umac_ctx *ctx, u_char *input, |
int umac(struct umac_ctx *ctx, u_char *input, |
long len, u_char tag[], |
long len, u_char tag[], |
u_char nonce[8]) |
u_char nonce[8]) |
/* All-in-one version simply calls umac_update() and umac_final(). */ |
/* All-in-one version simply calls umac_update() and umac_final(). */ |