doc: Fix typo.
[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 == 0)
264     return 0;
265
266   if (*outlen <= POLY1305_TAGLEN)
267     buf_cpy (outbuf, mac_ctx->tag, *outlen);
268   else
269     {
270       buf_cpy (outbuf, mac_ctx->tag, POLY1305_TAGLEN);
271       *outlen = POLY1305_TAGLEN;
272     }
273
274   return 0;
275 }
276
277
278 static gcry_err_code_t
279 poly1305mac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen)
280 {
281   struct poly1305mac_context_s *mac_ctx = h->u.poly1305mac.ctx;
282   gcry_err_code_t err;
283   size_t outlen = 0;
284
285   /* Check and finalize tag. */
286   err = poly1305mac_read(h, NULL, &outlen);
287   if (err)
288     return err;
289
290   if (buflen > POLY1305_TAGLEN)
291     return GPG_ERR_INV_LENGTH;
292
293   return buf_eq_const (buf, mac_ctx->tag, buflen) ? 0 : GPG_ERR_CHECKSUM;
294 }
295
296
297 static unsigned int
298 poly1305mac_get_maclen (int algo)
299 {
300   (void)algo;
301
302   return POLY1305_TAGLEN;
303 }
304
305
306 static unsigned int
307 poly1305mac_get_keylen (int algo)
308 {
309   (void)algo;
310
311   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