Lines Matching +full:umac +full:- +full:reset
1 /* $OpenBSD: umac.c,v 1.23 2023/03/07 01:30:52 djm Exp $ */
2 /* -----------------------------------------------------------------------
4 * umac.c -- C Implementation UMAC Message Authentication
6 * Version 0.93b of rfc4418.txt -- 2006 July 18
8 * For a full description of UMAC message authentication see the UMAC
9 * world-wide-web page at http://www.cs.ucdavis.edu/~rogaway/umac
10 * Please report bugs and suggestions to the UMAC webpage.
12 * Copyright (c) 1999-2006 Ted Krovetz
23 * ---------------------------------------------------------------------- */
29 * 2) If you set the switch to use SSE2, then all data must be 16-byte
32 * 3) When calling the function umac(), it is assumed that msg is in
38 * UMAC. Paulo Barreto's version is in the public domain and can be found
40 * "Barreto"). The only two files needed are rijndael-alg-fst.c and
41 * rijndael-alg-fst.h. Brian Gladman's version is distributed with the GNU
43 * includes a fast IA-32 assembly version. The OpenSSL crypo library is
47 * produced under gcc with optimizations set -O3 or higher. Dunno why.
51 /* ---------------------------------------------------------------------- */
52 /* --- User Switches ---------------------------------------------------- */
53 /* ---------------------------------------------------------------------- */
64 /* #define FORCE_C_ONLY 1 ANSI C and 64-bit integers req'd */
70 /* ---------------------------------------------------------------------- */
71 /* -- Global Includes --------------------------------------------------- */
72 /* ---------------------------------------------------------------------- */
83 #include "umac.h"
86 /* ---------------------------------------------------------------------- */
87 /* --- Primitive Data Types --- */
88 /* ---------------------------------------------------------------------- */
97 /* ---------------------------------------------------------------------- */
98 /* --- Constants -------------------------------------------------------- */
99 /* ---------------------------------------------------------------------- */
101 #define UMAC_KEY_LEN 16 /* UMAC takes 16 bytes of external key */
103 /* Message "words" are read from memory in an endian-specific manner. */
105 /* be set true if the host computer is little-endian. */
113 /* ---------------------------------------------------------------------- */
114 /* ---------------------------------------------------------------------- */
115 /* ----- Architecture Specific ------------------------------------------ */
116 /* ---------------------------------------------------------------------- */
117 /* ---------------------------------------------------------------------- */
120 /* ---------------------------------------------------------------------- */
121 /* ---------------------------------------------------------------------- */
122 /* ----- Primitive Routines --------------------------------------------- */
123 /* ---------------------------------------------------------------------- */
124 /* ---------------------------------------------------------------------- */
127 /* ---------------------------------------------------------------------- */
128 /* --- 32-bit by 32-bit to 64-bit Multiplication ------------------------ */
129 /* ---------------------------------------------------------------------- */
133 /* ---------------------------------------------------------------------- */
134 /* --- Endian Conversion --- Forcing assembly on some platforms */
135 /* ---------------------------------------------------------------------- */
148 /* ---------------------------------------------------------------------- */
149 /* ---------------------------------------------------------------------- */
150 /* ----- Begin KDF & PDF Section ---------------------------------------- */
151 /* ---------------------------------------------------------------------- */
152 /* ---------------------------------------------------------------------- */
154 /* UMAC uses AES with 16 byte block and key lengths */
159 #include "openbsd-compat/openssl-compat.h"
179 /* The user-supplied UMAC key is stretched using AES in a counter
180 * mode to supply all random bits needed by UMAC. The kdf function takes
193 in_buf[AES_BLOCK_LEN-9] = ndx; in kdf()
194 in_buf[AES_BLOCK_LEN-1] = i = 1; in kdf()
199 in_buf[AES_BLOCK_LEN-1] = ++i; in kdf()
200 nbytes -= AES_BLOCK_LEN; in kdf()
214 * This scheme is optimized for sequential, increasing big-endian nonces.
228 aes_key_setup(buf, pc->prf_key); in pdf_init()
231 memset(pc->nonce, 0, sizeof(pc->nonce)); in pdf_init()
232 aes_encryption(pc->nonce, pc->cache, pc->prf_key); in pdf_init()
240 * of the AES output. If last time around we returned the ndx-1st in pdf_gen_xor()
261 if ( (((UINT32 *)t.tmp_nonce_lo)[0] != ((UINT32 *)pc->nonce)[1]) || in pdf_gen_xor()
262 (((const UINT32 *)nonce)[0] != ((UINT32 *)pc->nonce)[0]) ) in pdf_gen_xor()
264 ((UINT32 *)pc->nonce)[0] = ((const UINT32 *)nonce)[0]; in pdf_gen_xor()
265 ((UINT32 *)pc->nonce)[1] = ((UINT32 *)t.tmp_nonce_lo)[0]; in pdf_gen_xor()
266 aes_encryption(pc->nonce, pc->cache, pc->prf_key); in pdf_gen_xor()
270 *((UINT32 *)buf) ^= ((UINT32 *)pc->cache)[ndx]; in pdf_gen_xor()
272 *((UINT64 *)buf) ^= ((UINT64 *)pc->cache)[ndx]; in pdf_gen_xor()
274 ((UINT64 *)buf)[0] ^= ((UINT64 *)pc->cache)[0]; in pdf_gen_xor()
275 ((UINT32 *)buf)[2] ^= ((UINT32 *)pc->cache)[2]; in pdf_gen_xor()
277 ((UINT64 *)buf)[0] ^= ((UINT64 *)pc->cache)[0]; in pdf_gen_xor()
278 ((UINT64 *)buf)[1] ^= ((UINT64 *)pc->cache)[1]; in pdf_gen_xor()
282 /* ---------------------------------------------------------------------- */
283 /* ---------------------------------------------------------------------- */
284 /* ----- Begin NH Hash Section ------------------------------------------ */
285 /* ---------------------------------------------------------------------- */
286 /* ---------------------------------------------------------------------- */
288 /* The NH-based hash functions used in UMAC are described in the UMAC paper
289 * and specification, both of which can be found at the UMAC website.
294 * multiple-buffer interface, the client calls the routine nh_update() as
298 * must be called. The single-buffer routine, nh(), is equivalent to
300 * optimized and should be preferred whenever the multiple-buffer interface
322 UINT8 nh_key [L1_KEY_LEN + L1_KEY_SHIFT * (STREAMS - 1)]; /* NH Key */
326 UINT64 state[STREAMS]; /* on-line state */
361 } while (--c); in nh_aux()
369 * reading and writing 16 bytes of hash-state per call. in nh_aux()
407 } while (--c); in nh_aux()
416 * reading and writing 24 bytes of hash-state per call. in nh_aux()
461 } while (--c); in nh_aux()
471 * reading and writing 24 bytes of hash-state per call. in nh_aux()
524 } while (--c); in nh_aux()
531 /* ---------------------------------------------------------------------- */
533 /* ---------------------------------------------------------------------- */
536 /* ---------------------------------------------------------------------- */
547 key = hc->nh_key + hc->bytes_hashed; in nh_transform()
548 nh_aux(key, buf, hc->state, nbytes); in nh_transform()
551 /* ---------------------------------------------------------------------- */
555 /* We endian convert the keys on little-endian computers to */ in endian_convert()
556 /* compensate for the lack of big-endian memory reads during hashing. */ in endian_convert()
564 } while (--iters); in endian_convert()
573 } while (--iters); in endian_convert()
581 /* ---------------------------------------------------------------------- */
584 /* Reset nh_ctx to ready for hashing of new data */ in nh_reset()
586 hc->bytes_hashed = 0; in nh_reset()
587 hc->next_data_empty = 0; in nh_reset()
588 hc->state[0] = 0; in nh_reset()
590 hc->state[1] = 0; in nh_reset()
593 hc->state[2] = 0; in nh_reset()
596 hc->state[3] = 0; in nh_reset()
601 /* ---------------------------------------------------------------------- */
604 /* Generate nh_key, endian convert and reset to be ready for hashing. */ in nh_init()
606 kdf(hc->nh_key, prf_key, 1, sizeof(hc->nh_key)); in nh_init()
607 endian_convert_if_le(hc->nh_key, 4, sizeof(hc->nh_key)); in nh_init()
611 /* ---------------------------------------------------------------------- */
619 j = hc->next_data_empty; in nh_update()
622 i = HASH_BUF_BYTES - j; in nh_update()
623 memcpy(hc->data+j, buf, i); in nh_update()
624 nh_transform(hc,hc->data,HASH_BUF_BYTES); in nh_update()
625 nbytes -= i; in nh_update()
627 hc->bytes_hashed += HASH_BUF_BYTES; in nh_update()
630 i = nbytes & ~(HASH_BUF_BYTES - 1); in nh_update()
632 nbytes -= i; in nh_update()
634 hc->bytes_hashed += i; in nh_update()
638 memcpy(hc->data + j, buf, nbytes); in nh_update()
639 hc->next_data_empty = j + nbytes; in nh_update()
642 /* ---------------------------------------------------------------------- */
650 nbytes--; in zero_pad()
655 nbytes -= sizeof(UWORD); in zero_pad()
661 nbytes--; in zero_pad()
666 /* ---------------------------------------------------------------------- */
671 * bytes are in the buffer hc->data, incorporate them into the in nh_final()
679 if (hc->next_data_empty != 0) { in nh_final()
680 nh_len = ((hc->next_data_empty + (L1_PAD_BOUNDARY - 1)) & in nh_final()
681 ~(L1_PAD_BOUNDARY - 1)); in nh_final()
682 zero_pad(hc->data + hc->next_data_empty, in nh_final()
683 nh_len - hc->next_data_empty); in nh_final()
684 nh_transform(hc, hc->data, nh_len); in nh_final()
685 hc->bytes_hashed += hc->next_data_empty; in nh_final()
686 } else if (hc->bytes_hashed == 0) { in nh_final()
688 zero_pad(hc->data, L1_PAD_BOUNDARY); in nh_final()
689 nh_transform(hc, hc->data, nh_len); in nh_final()
692 nbits = (hc->bytes_hashed << 3); in nh_final()
693 ((UINT64 *)result)[0] = ((UINT64 *)hc->state)[0] + nbits; in nh_final()
695 ((UINT64 *)result)[1] = ((UINT64 *)hc->state)[1] + nbits; in nh_final()
698 ((UINT64 *)result)[2] = ((UINT64 *)hc->state)[2] + nbits; in nh_final()
701 ((UINT64 *)result)[3] = ((UINT64 *)hc->state)[3] + nbits; in nh_final()
706 /* ---------------------------------------------------------------------- */
710 /* All-in-one nh_update() and nh_final() equivalent. in nh()
731 nh_aux(hc->nh_key, buf, result, padded_len); in nh()
734 /* ---------------------------------------------------------------------- */
735 /* ---------------------------------------------------------------------- */
736 /* ----- Begin UHASH Section -------------------------------------------- */
737 /* ---------------------------------------------------------------------- */
738 /* ---------------------------------------------------------------------- */
740 /* UHASH is a multi-layered algorithm. Data presented to UHASH is first
741 * hashed by NH. The NH output is then hashed by a polynomial-hash layer
742 * unless the initial data to be hashed is short. After the polynomial-
743 * layer, an inner-product hash is used to produce the final UHASH output.
745 * UHASH provides two interfaces, one all-at-once and another where data
751 * the uhash_reset() routine must be called. The all-at-once UHASH routine,
760 /* ---------------------------------------------------------------------- */
761 /* ----- Constants and uhash_ctx ---------------------------------------- */
762 /* ---------------------------------------------------------------------- */
764 /* ---------------------------------------------------------------------- */
765 /* ----- Poly hash and Inner-Product hash Constants --------------------- */
766 /* ---------------------------------------------------------------------- */
769 #define p36 ((UINT64)0x0000000FFFFFFFFBull) /* 2^36 - 5 */
770 #define p64 ((UINT64)0xFFFFFFFFFFFFFFC5ull) /* 2^64 - 59 */
774 /* ---------------------------------------------------------------------- */
780 UINT64 ip_keys[STREAMS*4]; /* Inner-product keys */
781 UINT32 ip_trans[STREAMS]; /* Inner-product translation */
787 /* ---------------------------------------------------------------------- */
794 * be within Z_p32 and Z_p64, but the Inner-Product hash implementation
827 /* Although UMAC is specified to use a ramped polynomial hash scheme, this
831 * bytes input to UMAC per tag, ie. 16MB).
840 hc->poly_accum[i] = poly64(hc->poly_accum[i], in poly_hash()
841 hc->poly_key_8[i], p64 - 1); in poly_hash()
842 hc->poly_accum[i] = poly64(hc->poly_accum[i], in poly_hash()
843 hc->poly_key_8[i], (data[i] - 59)); in poly_hash()
845 hc->poly_accum[i] = poly64(hc->poly_accum[i], in poly_hash()
846 hc->poly_key_8[i], data[i]); in poly_hash()
852 /* ---------------------------------------------------------------------- */
855 /* The final step in UHASH is an inner-product hash. The poly hash
856 * produces a result not necessarily WORD_LEN bytes long. The inner-
857 * product hash breaks the polyhash output into 16-bit chunks and
878 ret -= p36; in ip_reduce_p36()
894 t = ip_aux(0,ahc->ip_keys, nhp[0]); in ip_short()
895 STORE_UINT32_BIG((UINT32 *)res+0, ip_reduce_p36(t) ^ ahc->ip_trans[0]); in ip_short()
897 t = ip_aux(0,ahc->ip_keys+4, nhp[1]); in ip_short()
898 STORE_UINT32_BIG((UINT32 *)res+1, ip_reduce_p36(t) ^ ahc->ip_trans[1]); in ip_short()
901 t = ip_aux(0,ahc->ip_keys+8, nhp[2]); in ip_short()
902 STORE_UINT32_BIG((UINT32 *)res+2, ip_reduce_p36(t) ^ ahc->ip_trans[2]); in ip_short()
905 t = ip_aux(0,ahc->ip_keys+12, nhp[3]); in ip_short()
906 STORE_UINT32_BIG((UINT32 *)res+3, ip_reduce_p36(t) ^ ahc->ip_trans[3]); in ip_short()
921 if (ahc->poly_accum[i] >= p64) in ip_long()
922 ahc->poly_accum[i] -= p64; in ip_long()
923 t = ip_aux(0,ahc->ip_keys+(i*4), ahc->poly_accum[i]); in ip_long()
925 ip_reduce_p36(t) ^ ahc->ip_trans[i]); in ip_long()
930 /* ---------------------------------------------------------------------- */
932 /* ---------------------------------------------------------------------- */
934 /* Reset uhash context for next hash session */
937 nh_reset(&pc->hash); in uhash_reset()
938 pc->msg_len = 0; in uhash_reset()
939 pc->poly_accum[0] = 1; in uhash_reset()
941 pc->poly_accum[1] = 1; in uhash_reset()
944 pc->poly_accum[2] = 1; in uhash_reset()
947 pc->poly_accum[3] = 1; in uhash_reset()
952 /* ---------------------------------------------------------------------- */
955 * initialize the NH context and generate keys needed for poly and inner-
968 nh_init(&ahc->hash, prf_key); in uhash_init()
975 * little-endian computer. in uhash_init()
977 memcpy(ahc->poly_key_8+i, buf+24*i, 8); in uhash_init()
978 endian_convert_if_le(ahc->poly_key_8+i, 8, 8); in uhash_init()
979 /* Mask the 64-bit keys to their special domain */ in uhash_init()
980 ahc->poly_key_8[i] &= ((UINT64)0x01ffffffu << 32) + 0x01ffffffu; in uhash_init()
981 ahc->poly_accum[i] = 1; /* Our polyhash prepends a non-zero word */ in uhash_init()
984 /* Setup L3-1 hash variables */ in uhash_init()
987 memcpy(ahc->ip_keys+4*i, buf+(8*i+4)*sizeof(UINT64), in uhash_init()
989 endian_convert_if_le(ahc->ip_keys, sizeof(UINT64), in uhash_init()
990 sizeof(ahc->ip_keys)); in uhash_init()
992 ahc->ip_keys[i] %= p36; /* Bring into Z_p36 */ in uhash_init()
994 /* Setup L3-2 hash variables */ in uhash_init()
996 kdf(ahc->ip_trans, prf_key, 4, STREAMS * sizeof(UINT32)); in uhash_init()
997 endian_convert_if_le(ahc->ip_trans, sizeof(UINT32), in uhash_init()
1002 /* ---------------------------------------------------------------------- */
1007 /* Allocate memory and force to a 16-byte boundary. */
1015 bytes_to_add = ALLOC_BOUNDARY -
1016 ((ptrdiff_t)ctx & (ALLOC_BOUNDARY -1));
1018 *((u_char *)ctx - 1) = bytes_to_add;
1027 /* ---------------------------------------------------------------------- */
1037 bytes_to_sub = *((u_char *)ctx - 1);
1038 ctx = (uhash_ctx_t)((u_char *)ctx - bytes_to_sub);
1045 /* ---------------------------------------------------------------------- */
1056 if (ctx->msg_len + len <= L1_KEY_LEN) { in uhash_update()
1057 nh_update(&ctx->hash, (const UINT8 *)input, len); in uhash_update()
1058 ctx->msg_len += len; in uhash_update()
1061 bytes_hashed = ctx->msg_len % L1_KEY_LEN; in uhash_update()
1062 if (ctx->msg_len == L1_KEY_LEN) in uhash_update()
1068 /* then we want to pass at most (L1_KEY_LEN - bytes_hashed) */ in uhash_update()
1071 bytes_remaining = (L1_KEY_LEN - bytes_hashed); in uhash_update()
1072 nh_update(&ctx->hash, (const UINT8 *)input, bytes_remaining); in uhash_update()
1073 nh_final(&ctx->hash, nh_result); in uhash_update()
1074 ctx->msg_len += bytes_remaining; in uhash_update()
1076 len -= bytes_remaining; in uhash_update()
1082 nh(&ctx->hash, (const UINT8 *)input, L1_KEY_LEN, in uhash_update()
1084 ctx->msg_len += L1_KEY_LEN; in uhash_update()
1085 len -= L1_KEY_LEN; in uhash_update()
1093 nh_update(&ctx->hash, (const UINT8 *)input, len); in uhash_update()
1094 ctx->msg_len += len; in uhash_update()
1101 /* ---------------------------------------------------------------------- */
1109 if (ctx->msg_len > L1_KEY_LEN) { in uhash_final()
1110 if (ctx->msg_len % L1_KEY_LEN) { in uhash_final()
1111 nh_final(&ctx->hash, nh_result); in uhash_final()
1116 nh_final(&ctx->hash, nh_result); in uhash_final()
1123 /* ---------------------------------------------------------------------- */
1141 nh_len = ((len + (L1_PAD_BOUNDARY - 1)) & ~(L1_PAD_BOUNDARY - 1));
1142 extra_zeroes_needed = nh_len - len;
1144 nh(&ahc->hash, (UINT8 *)msg, nh_len, len, nh_result);
1151 nh(&ahc->hash, (UINT8 *)msg, L1_KEY_LEN, L1_KEY_LEN, nh_result);
1153 len -= L1_KEY_LEN;
1157 nh_len = ((len + (L1_PAD_BOUNDARY - 1)) & ~(L1_PAD_BOUNDARY - 1));
1158 extra_zeroes_needed = nh_len - len;
1160 nh(&ahc->hash, (UINT8 *)msg, nh_len, len, nh_result);
1172 /* ---------------------------------------------------------------------- */
1173 /* ---------------------------------------------------------------------- */
1174 /* ----- Begin UMAC Section --------------------------------------------- */
1175 /* ---------------------------------------------------------------------- */
1176 /* ---------------------------------------------------------------------- */
1178 /* The UMAC interface has two interfaces, an all-at-once interface where
1179 * the entire message to be authenticated is passed to UMAC in one buffer,
1181 * time. The all-at-once is more optimized than the sequential version and
1190 /* ---------------------------------------------------------------------- */
1194 /* Reset the hash function to begin a new authentication. */
1196 uhash_reset(&ctx->hash);
1201 /* ---------------------------------------------------------------------- */
1208 ctx = (struct umac_ctx *)ctx->free_ptr; in umac_delete()
1214 /* ---------------------------------------------------------------------- */
1218 * generate subkeys from key. Align to 16-byte boundary. in umac_new()
1228 bytes_to_add = ALLOC_BOUNDARY - in umac_new()
1229 ((ptrdiff_t)ctx & (ALLOC_BOUNDARY - 1)); in umac_new()
1232 ctx->free_ptr = octx; in umac_new()
1234 pdf_init(&ctx->pdf, prf_key); in umac_new()
1235 uhash_init(&ctx->hash, prf_key); in umac_new()
1242 /* ---------------------------------------------------------------------- */
1247 uhash_final(&ctx->hash, (u_char *)tag); in umac_final()
1248 pdf_gen_xor(&ctx->pdf, (const UINT8 *)nonce, (UINT8 *)tag); in umac_final()
1253 /* ---------------------------------------------------------------------- */
1257 /* hash each one, calling the PDF on the hashed output whenever the hash- */ in umac_update()
1260 uhash_update(&ctx->hash, input, len); in umac_update()
1264 /* ---------------------------------------------------------------------- */
1267 int umac(struct umac_ctx *ctx, u_char *input,
1270 /* All-in-one version simply calls umac_update() and umac_final(). */
1272 uhash(&ctx->hash, input, len, (u_char *)tag);
1273 pdf_gen_xor(&ctx->pdf, (UINT8 *)nonce, (UINT8 *)tag);
1279 /* ---------------------------------------------------------------------- */
1280 /* ---------------------------------------------------------------------- */
1281 /* ----- End UMAC Section ----------------------------------------------- */
1282 /* ---------------------------------------------------------------------- */
1283 /* ---------------------------------------------------------------------- */