xref: /openbsd/sys/crypto/gmac.c (revision d223d7cb)
1 /*	$OpenBSD: gmac.c,v 1.10 2017/05/02 11:44:32 mikeb Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 Mike Belopuhov
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * This code implements the Message Authentication part of the
21  * Galois/Counter Mode (as being described in the RFC 4543) using
22  * the AES cipher.  FIPS SP 800-38D describes the algorithm details.
23  */
24 
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 
28 #include <crypto/aes.h>
29 #include <crypto/gmac.h>
30 
31 void	ghash_gfmul(uint32_t *, uint32_t *, uint32_t *);
32 void	ghash_update_mi(GHASH_CTX *, uint8_t *, size_t);
33 
34 /* Allow overriding with optimized MD function */
35 void	(*ghash_update)(GHASH_CTX *, uint8_t *, size_t) = ghash_update_mi;
36 
37 /* Computes a block multiplication in the GF(2^128) */
38 void
ghash_gfmul(uint32_t * X,uint32_t * Y,uint32_t * product)39 ghash_gfmul(uint32_t *X, uint32_t *Y, uint32_t *product)
40 {
41 	uint32_t	v[4];
42 	uint32_t	z[4] = { 0, 0, 0, 0};
43 	uint8_t		*x = (uint8_t *)X;
44 	uint32_t	mask;
45 	int		i;
46 
47 	v[0] = betoh32(Y[0]);
48 	v[1] = betoh32(Y[1]);
49 	v[2] = betoh32(Y[2]);
50 	v[3] = betoh32(Y[3]);
51 
52 	for (i = 0; i < GMAC_BLOCK_LEN * 8; i++) {
53 		/* update Z */
54 		mask = !!(x[i >> 3] & (1 << (~i & 7)));
55 		mask = ~(mask - 1);
56 		z[0] ^= v[0] & mask;
57 		z[1] ^= v[1] & mask;
58 		z[2] ^= v[2] & mask;
59 		z[3] ^= v[3] & mask;
60 
61 		/* update V */
62 		mask = ~((v[3] & 1) - 1);
63 		v[3] = (v[2] << 31) | (v[3] >> 1);
64 		v[2] = (v[1] << 31) | (v[2] >> 1);
65 		v[1] = (v[0] << 31) | (v[1] >> 1);
66 		v[0] = (v[0] >> 1) ^ (0xe1000000 & mask);
67 	}
68 
69 	product[0] = htobe32(z[0]);
70 	product[1] = htobe32(z[1]);
71 	product[2] = htobe32(z[2]);
72 	product[3] = htobe32(z[3]);
73 }
74 
75 void
ghash_update_mi(GHASH_CTX * ctx,uint8_t * X,size_t len)76 ghash_update_mi(GHASH_CTX *ctx, uint8_t *X, size_t len)
77 {
78 	uint32_t	*x = (uint32_t *)X;
79 	uint32_t	*s = (uint32_t *)ctx->S;
80 	uint32_t	*y = (uint32_t *)ctx->Z;
81 	int		i;
82 
83 	for (i = 0; i < len / GMAC_BLOCK_LEN; i++) {
84 		s[0] = y[0] ^ x[0];
85 		s[1] = y[1] ^ x[1];
86 		s[2] = y[2] ^ x[2];
87 		s[3] = y[3] ^ x[3];
88 
89 		ghash_gfmul((uint32_t *)ctx->S, (uint32_t *)ctx->H,
90 		    (uint32_t *)ctx->S);
91 
92 		y = s;
93 		x += 4;
94 	}
95 
96 	bcopy(ctx->S, ctx->Z, GMAC_BLOCK_LEN);
97 }
98 
99 #define AESCTR_NONCESIZE	4
100 
101 void
AES_GMAC_Init(void * xctx)102 AES_GMAC_Init(void *xctx)
103 {
104 	AES_GMAC_CTX	*ctx = xctx;
105 
106 	bzero(ctx->ghash.H, GMAC_BLOCK_LEN);
107 	bzero(ctx->ghash.S, GMAC_BLOCK_LEN);
108 	bzero(ctx->ghash.Z, GMAC_BLOCK_LEN);
109 	bzero(ctx->J, GMAC_BLOCK_LEN);
110 }
111 
112 void
AES_GMAC_Setkey(void * xctx,const uint8_t * key,uint16_t klen)113 AES_GMAC_Setkey(void *xctx, const uint8_t *key, uint16_t klen)
114 {
115 	AES_GMAC_CTX	*ctx = xctx;
116 
117 	AES_Setkey(&ctx->K, key, klen - AESCTR_NONCESIZE);
118 	/* copy out salt to the counter block */
119 	bcopy(key + klen - AESCTR_NONCESIZE, ctx->J, AESCTR_NONCESIZE);
120 	/* prepare a hash subkey */
121 	AES_Encrypt(&ctx->K, ctx->ghash.H, ctx->ghash.H);
122 }
123 
124 void
AES_GMAC_Reinit(void * xctx,const uint8_t * iv,uint16_t ivlen)125 AES_GMAC_Reinit(void *xctx, const uint8_t *iv, uint16_t ivlen)
126 {
127 	AES_GMAC_CTX	*ctx = xctx;
128 
129 	/* copy out IV to the counter block */
130 	bcopy(iv, ctx->J + AESCTR_NONCESIZE, ivlen);
131 }
132 
133 int
AES_GMAC_Update(void * xctx,const uint8_t * data,uint16_t len)134 AES_GMAC_Update(void *xctx, const uint8_t *data, uint16_t len)
135 {
136 	AES_GMAC_CTX	*ctx = xctx;
137 	uint32_t	blk[4] = { 0, 0, 0, 0 };
138 	int		plen;
139 
140 	if (len > 0) {
141 		plen = len % GMAC_BLOCK_LEN;
142 		if (len >= GMAC_BLOCK_LEN)
143 			(*ghash_update)(&ctx->ghash, (uint8_t *)data,
144 			    len - plen);
145 		if (plen) {
146 			memcpy((uint8_t *)blk, (uint8_t *)data + (len - plen),
147 			    plen);
148 			(*ghash_update)(&ctx->ghash, (uint8_t *)blk,
149 			    GMAC_BLOCK_LEN);
150 		}
151 	}
152 	return (0);
153 }
154 
155 void
AES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN],void * xctx)156 AES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN], void *xctx)
157 {
158 	AES_GMAC_CTX	*ctx = xctx;
159 	uint8_t		keystream[GMAC_BLOCK_LEN];
160 	int		i;
161 
162 	/* do one round of GCTR */
163 	ctx->J[GMAC_BLOCK_LEN - 1] = 1;
164 	AES_Encrypt(&ctx->K, ctx->J, keystream);
165 	for (i = 0; i < GMAC_DIGEST_LEN; i++)
166 		digest[i] = ctx->ghash.S[i] ^ keystream[i];
167 	explicit_bzero(keystream, sizeof(keystream));
168 }
169