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