/src/libgcrypt/cipher/mac-poly1305.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* mac-poly1305.c - Poly1305 based MACs |
2 | | * Copyright (C) 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi> |
3 | | * |
4 | | * This file is part of Libgcrypt. |
5 | | * |
6 | | * Libgcrypt is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser general Public License as |
8 | | * published by the Free Software Foundation; either version 2.1 of |
9 | | * the License, or (at your option) any later version. |
10 | | * |
11 | | * Libgcrypt is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this program; if not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include <config.h> |
21 | | #include <stdio.h> |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | #include <errno.h> |
25 | | |
26 | | #include "g10lib.h" |
27 | | #include "mac-internal.h" |
28 | | #include "poly1305-internal.h" |
29 | | |
30 | | |
31 | | struct poly1305mac_context_s { |
32 | | poly1305_context_t ctx; |
33 | | gcry_cipher_hd_t hd; |
34 | | struct { |
35 | | unsigned int key_set:1; |
36 | | unsigned int nonce_set:1; |
37 | | unsigned int tag:1; |
38 | | } marks; |
39 | | byte tag[POLY1305_TAGLEN]; |
40 | | byte key[POLY1305_KEYLEN]; |
41 | | }; |
42 | | |
43 | | |
44 | | static gcry_err_code_t |
45 | | poly1305mac_open (gcry_mac_hd_t h) |
46 | 0 | { |
47 | 0 | struct poly1305mac_context_s *mac_ctx; |
48 | 0 | int secure = (h->magic == CTX_MAC_MAGIC_SECURE); |
49 | 0 | unsigned int flags = (secure ? GCRY_CIPHER_SECURE : 0); |
50 | 0 | gcry_err_code_t err; |
51 | 0 | int cipher_algo; |
52 | |
|
53 | 0 | if (secure) |
54 | 0 | mac_ctx = xtrycalloc_secure (1, sizeof(*mac_ctx)); |
55 | 0 | else |
56 | 0 | mac_ctx = xtrycalloc (1, sizeof(*mac_ctx)); |
57 | |
|
58 | 0 | if (!mac_ctx) |
59 | 0 | return gpg_err_code_from_syserror (); |
60 | | |
61 | 0 | h->u.poly1305mac.ctx = mac_ctx; |
62 | |
|
63 | 0 | switch (h->spec->algo) |
64 | 0 | { |
65 | 0 | default: |
66 | | /* already checked. */ |
67 | 0 | case GCRY_MAC_POLY1305: |
68 | | /* plain Poly1305. */ |
69 | 0 | cipher_algo = -1; |
70 | 0 | return 0; |
71 | 0 | case GCRY_MAC_POLY1305_AES: |
72 | 0 | cipher_algo = GCRY_CIPHER_AES; |
73 | 0 | break; |
74 | 0 | case GCRY_MAC_POLY1305_CAMELLIA: |
75 | 0 | cipher_algo = GCRY_CIPHER_CAMELLIA128; |
76 | 0 | break; |
77 | 0 | case GCRY_MAC_POLY1305_TWOFISH: |
78 | 0 | cipher_algo = GCRY_CIPHER_TWOFISH; |
79 | 0 | break; |
80 | 0 | case GCRY_MAC_POLY1305_SERPENT: |
81 | 0 | cipher_algo = GCRY_CIPHER_SERPENT128; |
82 | 0 | break; |
83 | 0 | case GCRY_MAC_POLY1305_SEED: |
84 | 0 | cipher_algo = GCRY_CIPHER_SEED; |
85 | 0 | break; |
86 | 0 | } |
87 | | |
88 | 0 | err = _gcry_cipher_open_internal (&mac_ctx->hd, cipher_algo, |
89 | 0 | GCRY_CIPHER_MODE_ECB, flags); |
90 | 0 | if (err) |
91 | 0 | goto err_free; |
92 | | |
93 | 0 | return 0; |
94 | | |
95 | 0 | err_free: |
96 | 0 | xfree(h->u.poly1305mac.ctx); |
97 | 0 | return err; |
98 | 0 | } |
99 | | |
100 | | |
101 | | static void |
102 | | poly1305mac_close (gcry_mac_hd_t h) |
103 | 0 | { |
104 | 0 | struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; |
105 | |
|
106 | 0 | if (h->spec->algo != GCRY_MAC_POLY1305) |
107 | 0 | _gcry_cipher_close (mac_ctx->hd); |
108 | |
|
109 | 0 | xfree(mac_ctx); |
110 | 0 | } |
111 | | |
112 | | |
113 | | static gcry_err_code_t |
114 | | poly1305mac_prepare_key (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) |
115 | 0 | { |
116 | 0 | struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; |
117 | 0 | size_t block_keylen = keylen - 16; |
118 | | |
119 | | /* Need at least 16 + 1 byte key. */ |
120 | 0 | if (keylen <= 16) |
121 | 0 | return GPG_ERR_INV_KEYLEN; |
122 | | |
123 | | /* For Poly1305-AES, first part of key is passed to Poly1305 as is. */ |
124 | 0 | memcpy (mac_ctx->key, key + block_keylen, 16); |
125 | | |
126 | | /* Remaining part is used as key for the block cipher. */ |
127 | 0 | return _gcry_cipher_setkey (mac_ctx->hd, key, block_keylen); |
128 | 0 | } |
129 | | |
130 | | |
131 | | static gcry_err_code_t |
132 | | poly1305mac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) |
133 | 0 | { |
134 | 0 | struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; |
135 | 0 | gcry_err_code_t err; |
136 | |
|
137 | 0 | memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx)); |
138 | 0 | memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag)); |
139 | 0 | memset(&mac_ctx->key, 0, sizeof(mac_ctx->key)); |
140 | |
|
141 | 0 | mac_ctx->marks.key_set = 0; |
142 | 0 | mac_ctx->marks.nonce_set = 0; |
143 | 0 | mac_ctx->marks.tag = 0; |
144 | |
|
145 | 0 | if (h->spec->algo != GCRY_MAC_POLY1305) |
146 | 0 | { |
147 | 0 | err = poly1305mac_prepare_key (h, key, keylen); |
148 | 0 | if (err) |
149 | 0 | return err; |
150 | | |
151 | | /* Poly1305-AES/etc also need nonce. */ |
152 | 0 | mac_ctx->marks.key_set = 1; |
153 | 0 | mac_ctx->marks.nonce_set = 0; |
154 | 0 | } |
155 | 0 | else |
156 | 0 | { |
157 | | /* For plain Poly1305, key is the nonce and setup is complete now. */ |
158 | |
|
159 | 0 | if (keylen != POLY1305_KEYLEN) |
160 | 0 | return GPG_ERR_INV_KEYLEN; |
161 | | |
162 | 0 | memcpy (mac_ctx->key, key, keylen); |
163 | |
|
164 | 0 | err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN); |
165 | 0 | if (err) |
166 | 0 | { |
167 | 0 | memset(&mac_ctx->key, 0, sizeof(mac_ctx->key)); |
168 | 0 | return err; |
169 | 0 | } |
170 | | |
171 | 0 | mac_ctx->marks.key_set = 1; |
172 | 0 | mac_ctx->marks.nonce_set = 1; |
173 | 0 | } |
174 | | |
175 | 0 | return 0; |
176 | 0 | } |
177 | | |
178 | | |
179 | | static gcry_err_code_t |
180 | | poly1305mac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen) |
181 | 0 | { |
182 | 0 | struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; |
183 | 0 | gcry_err_code_t err; |
184 | |
|
185 | 0 | if (h->spec->algo == GCRY_MAC_POLY1305) |
186 | 0 | return GPG_ERR_INV_ARG; |
187 | | |
188 | 0 | if (ivlen != 16) |
189 | 0 | return GPG_ERR_INV_ARG; |
190 | | |
191 | 0 | if (!mac_ctx->marks.key_set) |
192 | 0 | return 0; |
193 | | |
194 | 0 | memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx)); |
195 | 0 | memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag)); |
196 | 0 | mac_ctx->marks.nonce_set = 0; |
197 | 0 | mac_ctx->marks.tag = 0; |
198 | | |
199 | | /* Prepare second part of the poly1305 key. */ |
200 | |
|
201 | 0 | err = _gcry_cipher_encrypt (mac_ctx->hd, mac_ctx->key + 16, 16, iv, 16); |
202 | 0 | if (err) |
203 | 0 | return err; |
204 | | |
205 | 0 | err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN); |
206 | 0 | if (err) |
207 | 0 | return err; |
208 | | |
209 | 0 | mac_ctx->marks.nonce_set = 1; |
210 | 0 | return 0; |
211 | 0 | } |
212 | | |
213 | | |
214 | | static gcry_err_code_t |
215 | | poly1305mac_reset (gcry_mac_hd_t h) |
216 | 0 | { |
217 | 0 | struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; |
218 | |
|
219 | 0 | if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set) |
220 | 0 | return GPG_ERR_INV_STATE; |
221 | | |
222 | 0 | memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx)); |
223 | 0 | memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag)); |
224 | |
|
225 | 0 | mac_ctx->marks.key_set = 1; |
226 | 0 | mac_ctx->marks.nonce_set = 1; |
227 | 0 | mac_ctx->marks.tag = 0; |
228 | |
|
229 | 0 | return _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN); |
230 | 0 | } |
231 | | |
232 | | |
233 | | static gcry_err_code_t |
234 | | poly1305mac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) |
235 | 0 | { |
236 | 0 | struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; |
237 | |
|
238 | 0 | if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set || |
239 | 0 | mac_ctx->marks.tag) |
240 | 0 | return GPG_ERR_INV_STATE; |
241 | | |
242 | 0 | _gcry_poly1305_update (&mac_ctx->ctx, buf, buflen); |
243 | 0 | return 0; |
244 | 0 | } |
245 | | |
246 | | |
247 | | static gcry_err_code_t |
248 | | poly1305mac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t *outlen) |
249 | 0 | { |
250 | 0 | struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; |
251 | |
|
252 | 0 | if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set) |
253 | 0 | return GPG_ERR_INV_STATE; |
254 | | |
255 | 0 | if (!mac_ctx->marks.tag) |
256 | 0 | { |
257 | 0 | _gcry_poly1305_finish(&mac_ctx->ctx, mac_ctx->tag); |
258 | |
|
259 | 0 | memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx)); |
260 | 0 | mac_ctx->marks.tag = 1; |
261 | 0 | } |
262 | |
|
263 | 0 | if (*outlen == 0) |
264 | 0 | return 0; |
265 | | |
266 | 0 | if (*outlen <= POLY1305_TAGLEN) |
267 | 0 | buf_cpy (outbuf, mac_ctx->tag, *outlen); |
268 | 0 | else |
269 | 0 | { |
270 | 0 | buf_cpy (outbuf, mac_ctx->tag, POLY1305_TAGLEN); |
271 | 0 | *outlen = POLY1305_TAGLEN; |
272 | 0 | } |
273 | |
|
274 | 0 | return 0; |
275 | 0 | } |
276 | | |
277 | | |
278 | | static gcry_err_code_t |
279 | | poly1305mac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) |
280 | 0 | { |
281 | 0 | struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx; |
282 | 0 | gcry_err_code_t err; |
283 | 0 | size_t outlen = 0; |
284 | | |
285 | | /* Check and finalize tag. */ |
286 | 0 | err = poly1305mac_read(h, NULL, &outlen); |
287 | 0 | if (err) |
288 | 0 | return err; |
289 | | |
290 | 0 | if (buflen > POLY1305_TAGLEN) |
291 | 0 | return GPG_ERR_INV_LENGTH; |
292 | | |
293 | 0 | return buf_eq_const (buf, mac_ctx->tag, buflen) ? 0 : GPG_ERR_CHECKSUM; |
294 | 0 | } |
295 | | |
296 | | |
297 | | static unsigned int |
298 | | poly1305mac_get_maclen (int algo) |
299 | 0 | { |
300 | 0 | (void)algo; |
301 | |
|
302 | 0 | return POLY1305_TAGLEN; |
303 | 0 | } |
304 | | |
305 | | |
306 | | static unsigned int |
307 | | poly1305mac_get_keylen (int algo) |
308 | 0 | { |
309 | 0 | (void)algo; |
310 | |
|
311 | 0 | return POLY1305_KEYLEN; |
312 | 0 | } |
313 | | |
314 | | |
315 | | static gcry_mac_spec_ops_t poly1305mac_ops = { |
316 | | poly1305mac_open, |
317 | | poly1305mac_close, |
318 | | poly1305mac_setkey, |
319 | | poly1305mac_setiv, |
320 | | poly1305mac_reset, |
321 | | poly1305mac_write, |
322 | | poly1305mac_read, |
323 | | poly1305mac_verify, |
324 | | poly1305mac_get_maclen, |
325 | | poly1305mac_get_keylen, |
326 | | NULL, |
327 | | NULL, |
328 | | }; |
329 | | |
330 | | |
331 | | const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac = { |
332 | | GCRY_MAC_POLY1305, {0, 0}, "POLY1305", |
333 | | &poly1305mac_ops |
334 | | }; |
335 | | #if USE_AES |
336 | | const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aes = { |
337 | | GCRY_MAC_POLY1305_AES, {0, 0}, "POLY1305_AES", |
338 | | &poly1305mac_ops |
339 | | }; |
340 | | #endif |
341 | | #if USE_CAMELLIA |
342 | | const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_camellia = { |
343 | | GCRY_MAC_POLY1305_CAMELLIA, {0, 0}, "POLY1305_CAMELLIA", |
344 | | &poly1305mac_ops |
345 | | }; |
346 | | #endif |
347 | | #if USE_TWOFISH |
348 | | const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_twofish = { |
349 | | GCRY_MAC_POLY1305_TWOFISH, {0, 0}, "POLY1305_TWOFISH", |
350 | | &poly1305mac_ops |
351 | | }; |
352 | | #endif |
353 | | #if USE_SERPENT |
354 | | const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_serpent = { |
355 | | GCRY_MAC_POLY1305_SERPENT, {0, 0}, "POLY1305_SERPENT", |
356 | | &poly1305mac_ops |
357 | | }; |
358 | | #endif |
359 | | #if USE_SEED |
360 | | const gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_seed = { |
361 | | GCRY_MAC_POLY1305_SEED, {0, 0}, "POLY1305_SEED", |
362 | | &poly1305mac_ops |
363 | | }; |
364 | | #endif |