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