xref: /openbsd-src/sys/crypto/gmac.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: gmac.c,v 1.3 2011/01/11 15:44:23 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 Mike Belopuhov <mike@vantronix.net>
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/rijndael.h>
29 #include <crypto/gmac.h>
30 
31 void	ghash_gfmul(uint32_t *, uint32_t *, uint32_t *);
32 void	ghash_update(GHASH_CTX *, uint8_t *, size_t);
33 
34 /* Computes a block multiplication in the GF(2^128) */
35 void
36 ghash_gfmul(uint32_t *X, uint32_t *Y, uint32_t *product)
37 {
38 	uint32_t	v[4];
39 	uint32_t	z[4] = { 0, 0, 0, 0};
40 	uint8_t		*x = (uint8_t *)X;
41 	uint32_t	mul;
42 	int		i;
43 
44 	v[0] = betoh32(Y[0]);
45 	v[1] = betoh32(Y[1]);
46 	v[2] = betoh32(Y[2]);
47 	v[3] = betoh32(Y[3]);
48 
49 	for (i = 0; i < GMAC_BLOCK_LEN * 8; i++) {
50 		/* update Z */
51 		if (x[i >> 3] & (1 << (~i & 7))) {
52 			z[0] ^= v[0];
53 			z[1] ^= v[1];
54 			z[2] ^= v[2];
55 			z[3] ^= v[3];
56 		} /* else: we preserve old values */
57 
58 		/* update V */
59 		mul = v[3] & 1;
60 		v[3] = (v[2] << 31) | (v[3] >> 1);
61 		v[2] = (v[1] << 31) | (v[2] >> 1);
62 		v[1] = (v[0] << 31) | (v[1] >> 1);
63 		v[0] = (v[0] >> 1) ^ (0xe1000000 * mul);
64 	}
65 
66 	product[0] = htobe32(z[0]);
67 	product[1] = htobe32(z[1]);
68 	product[2] = htobe32(z[2]);
69 	product[3] = htobe32(z[3]);
70 }
71 
72 void
73 ghash_update(GHASH_CTX *ctx, uint8_t *X, size_t len)
74 {
75 	uint32_t	*x = (uint32_t *)X;
76 	uint32_t	*s = (uint32_t *)ctx->S;
77 	uint32_t	*y = (uint32_t *)ctx->Z;
78 	int		i;
79 
80 	for (i = 0; i < len / GMAC_BLOCK_LEN; i++) {
81 		s[0] = y[0] ^ x[0];
82 		s[1] = y[1] ^ x[1];
83 		s[2] = y[2] ^ x[2];
84 		s[3] = y[3] ^ x[3];
85 
86 		ghash_gfmul((uint32_t *)ctx->S, (uint32_t *)ctx->H,
87 		    (uint32_t *)ctx->S);
88 
89 		y = s;
90 		x += 4;
91 	}
92 
93 	bcopy(ctx->S, ctx->Z, GMAC_BLOCK_LEN);
94 }
95 
96 #define AESCTR_NONCESIZE	4
97 
98 void
99 AES_GMAC_Init(AES_GMAC_CTX *ctx)
100 {
101 	bzero(ctx->ghash.H, GMAC_BLOCK_LEN);
102 	bzero(ctx->ghash.S, GMAC_BLOCK_LEN);
103 	bzero(ctx->ghash.Z, GMAC_BLOCK_LEN);
104 	bzero(ctx->J, GMAC_BLOCK_LEN);
105 }
106 
107 void
108 AES_GMAC_Setkey(AES_GMAC_CTX *ctx, const uint8_t *key, uint16_t klen)
109 {
110 	ctx->rounds = rijndaelKeySetupEnc(ctx->K, (u_char *)key,
111 	    (klen - AESCTR_NONCESIZE) * 8);
112 	/* copy out salt to the counter block */
113 	bcopy(key + klen - AESCTR_NONCESIZE, ctx->J, AESCTR_NONCESIZE);
114 	/* prepare a hash subkey */
115 	rijndaelEncrypt(ctx->K, ctx->rounds, ctx->ghash.H, ctx->ghash.H);
116 }
117 
118 void
119 AES_GMAC_Reinit(AES_GMAC_CTX *ctx, const uint8_t *iv, uint16_t ivlen)
120 {
121 	/* copy out IV to the counter block */
122 	bcopy(iv, ctx->J + AESCTR_NONCESIZE, ivlen);
123 }
124 
125 int
126 AES_GMAC_Update(AES_GMAC_CTX *ctx, const uint8_t *data, uint16_t len)
127 {
128 	uint32_t	blk[4] = { 0, 0, 0, 0 };
129 	int		plen;
130 
131 	if (len > 0) {
132 		plen = len % GMAC_BLOCK_LEN;
133 		if (len >= GMAC_BLOCK_LEN)
134 			ghash_update(&ctx->ghash, (uint8_t *)data, len - plen);
135 		if (plen) {
136 			bcopy((uint8_t *)data + (len - plen), (uint8_t *)blk,
137 			    plen);
138 			ghash_update(&ctx->ghash, (uint8_t *)blk,
139 			    GMAC_BLOCK_LEN);
140 		}
141 	}
142 	return (0);
143 }
144 
145 void
146 AES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN], AES_GMAC_CTX *ctx)
147 {
148 	uint8_t		keystream[GMAC_BLOCK_LEN];
149 	int		i;
150 
151 	/* do one round of GCTR */
152 	ctx->J[GMAC_BLOCK_LEN - 1] = 1;
153 	rijndaelEncrypt(ctx->K, ctx->rounds, ctx->J, keystream);
154 	for (i = 0; i < GMAC_DIGEST_LEN; i++)
155 		digest[i] = ctx->ghash.S[i] ^ keystream[i];
156 	explicit_bzero(keystream, sizeof(keystream));
157 }
158