Line data Source code
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 100 : poly1305mac_open (gcry_mac_hd_t h)
46 : {
47 : struct poly1305mac_context_s *mac_ctx;
48 100 : int secure = (h->magic == CTX_MAGIC_SECURE);
49 100 : unsigned int flags = (secure ? GCRY_CIPHER_SECURE : 0);
50 : gcry_err_code_t err;
51 : int cipher_algo;
52 :
53 100 : if (secure)
54 0 : mac_ctx = xtrycalloc_secure (1, sizeof(*mac_ctx));
55 : else
56 100 : mac_ctx = xtrycalloc (1, sizeof(*mac_ctx));
57 :
58 100 : if (!mac_ctx)
59 0 : return gpg_err_code_from_syserror ();
60 :
61 100 : h->u.poly1305mac.ctx = mac_ctx;
62 :
63 100 : switch (h->spec->algo)
64 : {
65 : default:
66 : /* already checked. */
67 : case GCRY_MAC_POLY1305:
68 : /* plain Poly1305. */
69 72 : cipher_algo = -1;
70 72 : return 0;
71 : case GCRY_MAC_POLY1305_AES:
72 20 : cipher_algo = GCRY_CIPHER_AES;
73 20 : break;
74 : case GCRY_MAC_POLY1305_CAMELLIA:
75 2 : cipher_algo = GCRY_CIPHER_CAMELLIA128;
76 2 : break;
77 : case GCRY_MAC_POLY1305_TWOFISH:
78 2 : cipher_algo = GCRY_CIPHER_TWOFISH;
79 2 : break;
80 : case GCRY_MAC_POLY1305_SERPENT:
81 2 : cipher_algo = GCRY_CIPHER_SERPENT128;
82 2 : break;
83 : case GCRY_MAC_POLY1305_SEED:
84 2 : cipher_algo = GCRY_CIPHER_SEED;
85 2 : break;
86 : }
87 :
88 28 : err = _gcry_cipher_open_internal (&mac_ctx->hd, cipher_algo,
89 : GCRY_CIPHER_MODE_ECB, flags);
90 28 : if (err)
91 0 : goto err_free;
92 :
93 28 : return 0;
94 :
95 : err_free:
96 0 : xfree(h->u.poly1305mac.ctx);
97 0 : return err;
98 : }
99 :
100 :
101 : static void
102 100 : poly1305mac_close (gcry_mac_hd_t h)
103 : {
104 100 : struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
105 :
106 100 : if (h->spec->algo != GCRY_MAC_POLY1305)
107 28 : _gcry_cipher_close (mac_ctx->hd);
108 :
109 100 : xfree(mac_ctx);
110 100 : }
111 :
112 :
113 : static gcry_err_code_t
114 28 : poly1305mac_prepare_key (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
115 : {
116 28 : struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
117 28 : size_t block_keylen = keylen - 16;
118 :
119 : /* Need at least 16 + 1 byte key. */
120 28 : 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 28 : memcpy (mac_ctx->key, key + block_keylen, 16);
125 :
126 : /* Remaining part is used as key for the block cipher. */
127 28 : return _gcry_cipher_setkey (mac_ctx->hd, key, block_keylen);
128 : }
129 :
130 :
131 : static gcry_err_code_t
132 100 : poly1305mac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen)
133 : {
134 100 : struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
135 : gcry_err_code_t err;
136 :
137 100 : memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
138 100 : memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
139 100 : memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
140 :
141 100 : mac_ctx->marks.key_set = 0;
142 100 : mac_ctx->marks.nonce_set = 0;
143 100 : mac_ctx->marks.tag = 0;
144 :
145 100 : if (h->spec->algo != GCRY_MAC_POLY1305)
146 : {
147 28 : err = poly1305mac_prepare_key (h, key, keylen);
148 28 : if (err)
149 0 : return err;
150 :
151 : /* Poly1305-AES/etc also need nonce. */
152 28 : mac_ctx->marks.key_set = 1;
153 28 : mac_ctx->marks.nonce_set = 0;
154 : }
155 : else
156 : {
157 : /* For plain Poly1305, key is the nonce and setup is complete now. */
158 :
159 72 : if (keylen != POLY1305_KEYLEN)
160 0 : return GPG_ERR_INV_KEYLEN;
161 :
162 72 : memcpy (mac_ctx->key, key, keylen);
163 :
164 72 : err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
165 72 : if (err)
166 : {
167 0 : memset(&mac_ctx->key, 0, sizeof(mac_ctx->key));
168 0 : return err;
169 : }
170 :
171 72 : mac_ctx->marks.key_set = 1;
172 72 : mac_ctx->marks.nonce_set = 1;
173 : }
174 :
175 100 : return 0;
176 : }
177 :
178 :
179 : static gcry_err_code_t
180 28 : poly1305mac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen)
181 : {
182 28 : struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
183 : gcry_err_code_t err;
184 :
185 28 : if (h->spec->algo == GCRY_MAC_POLY1305)
186 0 : return GPG_ERR_INV_ARG;
187 :
188 28 : if (ivlen != 16)
189 0 : return GPG_ERR_INV_ARG;
190 :
191 28 : if (!mac_ctx->marks.key_set)
192 0 : return 0;
193 :
194 28 : memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
195 28 : memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
196 28 : mac_ctx->marks.nonce_set = 0;
197 28 : mac_ctx->marks.tag = 0;
198 :
199 : /* Prepare second part of the poly1305 key. */
200 :
201 28 : err = _gcry_cipher_encrypt (mac_ctx->hd, mac_ctx->key + 16, 16, iv, 16);
202 28 : if (err)
203 0 : return err;
204 :
205 28 : err = _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
206 28 : if (err)
207 0 : return err;
208 :
209 28 : mac_ctx->marks.nonce_set = 1;
210 28 : return 0;
211 : }
212 :
213 :
214 : static gcry_err_code_t
215 4964 : poly1305mac_reset (gcry_mac_hd_t h)
216 : {
217 4964 : struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
218 :
219 4964 : if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set)
220 0 : return GPG_ERR_INV_STATE;
221 :
222 4964 : memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
223 4964 : memset(&mac_ctx->tag, 0, sizeof(mac_ctx->tag));
224 :
225 4964 : mac_ctx->marks.key_set = 1;
226 4964 : mac_ctx->marks.nonce_set = 1;
227 4964 : mac_ctx->marks.tag = 0;
228 :
229 4964 : return _gcry_poly1305_init (&mac_ctx->ctx, mac_ctx->key, POLY1305_KEYLEN);
230 : }
231 :
232 :
233 : static gcry_err_code_t
234 683000 : poly1305mac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
235 : {
236 683000 : struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
237 :
238 683000 : if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set ||
239 : mac_ctx->marks.tag)
240 0 : return GPG_ERR_INV_STATE;
241 :
242 683000 : _gcry_poly1305_update (&mac_ctx->ctx, buf, buflen);
243 683000 : return 0;
244 : }
245 :
246 :
247 : static gcry_err_code_t
248 5146 : poly1305mac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t *outlen)
249 : {
250 5146 : struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
251 :
252 5146 : if (!mac_ctx->marks.key_set || !mac_ctx->marks.nonce_set)
253 0 : return GPG_ERR_INV_STATE;
254 :
255 5146 : if (!mac_ctx->marks.tag)
256 : {
257 5058 : _gcry_poly1305_finish(&mac_ctx->ctx, mac_ctx->tag);
258 :
259 5058 : memset(&mac_ctx->ctx, 0, sizeof(mac_ctx->ctx));
260 5058 : mac_ctx->marks.tag = 1;
261 : }
262 :
263 5146 : if (*outlen == 0)
264 88 : return 0;
265 :
266 5058 : if (*outlen <= POLY1305_TAGLEN)
267 5058 : buf_cpy (outbuf, mac_ctx->tag, *outlen);
268 : else
269 : {
270 0 : buf_cpy (outbuf, mac_ctx->tag, POLY1305_TAGLEN);
271 0 : *outlen = POLY1305_TAGLEN;
272 : }
273 :
274 5058 : return 0;
275 : }
276 :
277 :
278 : static gcry_err_code_t
279 88 : poly1305mac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
280 : {
281 88 : struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
282 : gcry_err_code_t err;
283 88 : size_t outlen = 0;
284 :
285 : /* Check and finalize tag. */
286 88 : err = poly1305mac_read(h, NULL, &outlen);
287 88 : if (err)
288 0 : return err;
289 :
290 88 : if (buflen > POLY1305_TAGLEN)
291 0 : return GPG_ERR_INV_LENGTH;
292 :
293 88 : return buf_eq_const (buf, mac_ctx->tag, buflen) ? 0 : GPG_ERR_CHECKSUM;
294 : }
295 :
296 :
297 : static unsigned int
298 94 : poly1305mac_get_maclen (int algo)
299 : {
300 : (void)algo;
301 :
302 94 : return POLY1305_TAGLEN;
303 : }
304 :
305 :
306 : static unsigned int
307 12 : poly1305mac_get_keylen (int algo)
308 : {
309 : (void)algo;
310 :
311 12 : return POLY1305_KEYLEN;
312 : }
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 : };
327 :
328 :
329 : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac = {
330 : GCRY_MAC_POLY1305, {0, 0}, "POLY1305",
331 : &poly1305mac_ops
332 : };
333 : #if USE_AES
334 : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_aes = {
335 : GCRY_MAC_POLY1305_AES, {0, 0}, "POLY1305_AES",
336 : &poly1305mac_ops
337 : };
338 : #endif
339 : #if USE_CAMELLIA
340 : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_camellia = {
341 : GCRY_MAC_POLY1305_CAMELLIA, {0, 0}, "POLY1305_CAMELLIA",
342 : &poly1305mac_ops
343 : };
344 : #endif
345 : #if USE_TWOFISH
346 : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_twofish = {
347 : GCRY_MAC_POLY1305_TWOFISH, {0, 0}, "POLY1305_TWOFISH",
348 : &poly1305mac_ops
349 : };
350 : #endif
351 : #if USE_SERPENT
352 : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_serpent = {
353 : GCRY_MAC_POLY1305_SERPENT, {0, 0}, "POLY1305_SERPENT",
354 : &poly1305mac_ops
355 : };
356 : #endif
357 : #if USE_SEED
358 : gcry_mac_spec_t _gcry_mac_type_spec_poly1305mac_seed = {
359 : GCRY_MAC_POLY1305_SEED, {0, 0}, "POLY1305_SEED",
360 : &poly1305mac_ops
361 : };
362 : #endif
|