ecc: Handle ephemeral key as opaque octets.
[libgcrypt.git] / cipher / cipher-ccm.c
1 /* cipher-ccm.c - CTR mode with CBC-MAC mode implementation
2  * Copyright (C) 2013 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 "cipher.h"
28 #include "bufhelp.h"
29 #include "./cipher-internal.h"
30
31
32 #define set_burn(burn, nburn) do { \
33   unsigned int __nburn = (nburn); \
34   (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0)
35
36
37 static unsigned int
38 do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen,
39             int do_padding)
40 {
41   const unsigned int blocksize = 16;
42   gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
43   unsigned char tmp[blocksize];
44   unsigned int burn = 0;
45   unsigned int unused = c->u_mode.ccm.mac_unused;
46   size_t nblocks;
47   size_t n;
48
49   if (inlen == 0 && (unused == 0 || !do_padding))
50     return 0;
51
52   do
53     {
54       if (inlen + unused < blocksize || unused > 0)
55         {
56           n = (inlen > blocksize - unused) ? blocksize - unused : inlen;
57
58           buf_cpy (&c->u_mode.ccm.macbuf[unused], inbuf, n);
59           unused += n;
60           inlen -= n;
61           inbuf += n;
62         }
63       if (!inlen)
64         {
65           if (!do_padding)
66             break;
67
68           n = blocksize - unused;
69           if (n > 0)
70             {
71               memset (&c->u_mode.ccm.macbuf[unused], 0, n);
72               unused = blocksize;
73             }
74         }
75
76       if (unused > 0)
77         {
78           /* Process one block from macbuf.  */
79           cipher_block_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf,
80                            blocksize);
81           set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ));
82
83           unused = 0;
84         }
85
86       if (c->bulk.cbc_enc)
87         {
88           nblocks = inlen / blocksize;
89           c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, tmp, inbuf, nblocks, 1);
90           inbuf += nblocks * blocksize;
91           inlen -= nblocks * blocksize;
92
93           wipememory (tmp, sizeof(tmp));
94         }
95       else
96         {
97           while (inlen >= blocksize)
98             {
99               cipher_block_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
100
101               set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ));
102
103               inlen -= blocksize;
104               inbuf += blocksize;
105             }
106         }
107     }
108   while (inlen > 0);
109
110   c->u_mode.ccm.mac_unused = unused;
111
112   if (burn)
113     burn += 4 * sizeof(void *);
114
115   return burn;
116 }
117
118
119 gcry_err_code_t
120 _gcry_cipher_ccm_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce,
121                             size_t noncelen)
122 {
123   unsigned int marks_key;
124   size_t L = 15 - noncelen;
125   size_t L_;
126
127   L_ = L - 1;
128
129   if (!nonce)
130     return GPG_ERR_INV_ARG;
131   /* Length field must be 2, 3, ..., or 8. */
132   if (L < 2 || L > 8)
133     return GPG_ERR_INV_LENGTH;
134
135   /* Reset state */
136   marks_key = c->marks.key;
137   memset (&c->u_mode, 0, sizeof(c->u_mode));
138   memset (&c->marks, 0, sizeof(c->marks));
139   memset (&c->u_iv, 0, sizeof(c->u_iv));
140   memset (&c->u_ctr, 0, sizeof(c->u_ctr));
141   memset (c->lastiv, 0, sizeof(c->lastiv));
142   c->unused = 0;
143   c->marks.key = marks_key;
144
145   /* Setup CTR */
146   c->u_ctr.ctr[0] = L_;
147   memcpy (&c->u_ctr.ctr[1], nonce, noncelen);
148   memset (&c->u_ctr.ctr[1 + noncelen], 0, L);
149
150   /* Setup IV */
151   c->u_iv.iv[0] = L_;
152   memcpy (&c->u_iv.iv[1], nonce, noncelen);
153   /* Add (8 * M_ + 64 * flags) to iv[0] and set iv[noncelen + 1 ... 15] later
154      in set_aad.  */
155   memset (&c->u_iv.iv[1 + noncelen], 0, L);
156
157   c->u_mode.ccm.nonce = 1;
158
159   return GPG_ERR_NO_ERROR;
160 }
161
162
163 gcry_err_code_t
164 _gcry_cipher_ccm_set_lengths (gcry_cipher_hd_t c, u64 encryptlen, u64 aadlen,
165                               u64 taglen)
166 {
167   unsigned int burn = 0;
168   unsigned char b0[16];
169   size_t noncelen = 15 - (c->u_iv.iv[0] + 1);
170   u64 M = taglen;
171   u64 M_;
172   int i;
173
174   M_ = (M - 2) / 2;
175
176   /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */
177   if ((M_ * 2 + 2) != M || M < 4 || M > 16)
178     return GPG_ERR_INV_LENGTH;
179   if (!c->u_mode.ccm.nonce || c->marks.tag)
180     return GPG_ERR_INV_STATE;
181   if (c->u_mode.ccm.lengths)
182     return GPG_ERR_INV_STATE;
183
184   c->u_mode.ccm.authlen = taglen;
185   c->u_mode.ccm.encryptlen = encryptlen;
186   c->u_mode.ccm.aadlen = aadlen;
187
188   /* Complete IV setup.  */
189   c->u_iv.iv[0] += (aadlen > 0) * 64 + M_ * 8;
190   for (i = 16 - 1; i >= 1 + noncelen; i--)
191     {
192       c->u_iv.iv[i] = encryptlen & 0xff;
193       encryptlen >>= 8;
194     }
195
196   memcpy (b0, c->u_iv.iv, 16);
197   memset (c->u_iv.iv, 0, 16);
198
199   set_burn (burn, do_cbc_mac (c, b0, 16, 0));
200
201   if (aadlen == 0)
202     {
203       /* Do nothing.  */
204     }
205   else if (aadlen > 0 && aadlen <= (unsigned int)0xfeff)
206     {
207       b0[0] = (aadlen >> 8) & 0xff;
208       b0[1] = aadlen & 0xff;
209       set_burn (burn, do_cbc_mac (c, b0, 2, 0));
210     }
211   else if (aadlen > 0xfeff && aadlen <= (unsigned int)0xffffffff)
212     {
213       b0[0] = 0xff;
214       b0[1] = 0xfe;
215       buf_put_be32(&b0[2], aadlen);
216       set_burn (burn, do_cbc_mac (c, b0, 6, 0));
217     }
218   else if (aadlen > (unsigned int)0xffffffff)
219     {
220       b0[0] = 0xff;
221       b0[1] = 0xff;
222       buf_put_be64(&b0[2], aadlen);
223       set_burn (burn, do_cbc_mac (c, b0, 10, 0));
224     }
225
226   /* Generate S_0 and increase counter.  */
227   set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0,
228                                      c->u_ctr.ctr ));
229   c->u_ctr.ctr[15]++;
230
231   if (burn)
232     _gcry_burn_stack (burn + sizeof(void *) * 5);
233
234   c->u_mode.ccm.lengths = 1;
235
236   return GPG_ERR_NO_ERROR;
237 }
238
239
240 gcry_err_code_t
241 _gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf,
242                                size_t abuflen)
243 {
244   unsigned int burn;
245
246   if (abuflen > 0 && !abuf)
247     return GPG_ERR_INV_ARG;
248   if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->marks.tag)
249     return GPG_ERR_INV_STATE;
250   if (abuflen > c->u_mode.ccm.aadlen)
251     return GPG_ERR_INV_LENGTH;
252
253   c->u_mode.ccm.aadlen -= abuflen;
254   burn = do_cbc_mac (c, abuf, abuflen, c->u_mode.ccm.aadlen == 0);
255
256   if (burn)
257     _gcry_burn_stack (burn + sizeof(void *) * 5);
258
259   return GPG_ERR_NO_ERROR;
260 }
261
262
263 gcry_err_code_t
264 _gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf,
265                       size_t outbuflen, int check)
266 {
267   unsigned int burn;
268
269   if (!outbuf || outbuflen == 0)
270     return GPG_ERR_INV_ARG;
271   /* Tag length must be same as initial authlen.  */
272   if (c->u_mode.ccm.authlen != outbuflen)
273     return GPG_ERR_INV_LENGTH;
274   if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->u_mode.ccm.aadlen > 0)
275     return GPG_ERR_INV_STATE;
276   /* Initial encrypt length must match with length of actual data processed.  */
277   if (c->u_mode.ccm.encryptlen > 0)
278     return GPG_ERR_UNFINISHED;
279
280   if (!c->marks.tag)
281     {
282       burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding.  */
283
284       /* Add S_0 */
285       cipher_block_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16);
286
287       wipememory (c->u_ctr.ctr, 16);
288       wipememory (c->u_mode.ccm.s0, 16);
289       wipememory (c->u_mode.ccm.macbuf, 16);
290
291       if (burn)
292         _gcry_burn_stack (burn + sizeof(void *) * 5);
293
294       c->marks.tag = 1;
295     }
296
297   if (!check)
298     {
299       memcpy (outbuf, c->u_iv.iv, outbuflen);
300       return GPG_ERR_NO_ERROR;
301     }
302   else
303     {
304       return buf_eq_const(outbuf, c->u_iv.iv, outbuflen) ?
305              GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
306     }
307 }
308
309
310 gcry_err_code_t
311 _gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
312                           size_t taglen)
313 {
314   return _gcry_cipher_ccm_tag (c, outtag, taglen, 0);
315 }
316
317
318 gcry_err_code_t
319 _gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
320                             size_t taglen)
321 {
322   return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1);
323 }
324
325
326 gcry_err_code_t
327 _gcry_cipher_ccm_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
328                           size_t outbuflen, const unsigned char *inbuf,
329                           size_t inbuflen)
330 {
331   gcry_err_code_t err = 0;
332   unsigned int burn = 0;
333   unsigned int nburn;
334
335   if (outbuflen < inbuflen)
336     return GPG_ERR_BUFFER_TOO_SHORT;
337   if (!c->u_mode.ccm.nonce || c->marks.tag || !c->u_mode.ccm.lengths ||
338       c->u_mode.ccm.aadlen > 0)
339     return GPG_ERR_INV_STATE;
340   if (inbuflen > c->u_mode.ccm.encryptlen)
341     return GPG_ERR_INV_LENGTH;
342
343   while (inbuflen)
344     {
345       size_t currlen = inbuflen;
346
347       /* Since checksumming is done before encryption, process input in 24KiB
348        * chunks to keep data loaded in L1 cache for encryption. */
349       if (currlen > 24 * 1024)
350         currlen = 24 * 1024;
351
352       c->u_mode.ccm.encryptlen -= currlen;
353       nburn = do_cbc_mac (c, inbuf, currlen, 0);
354       burn = nburn > burn ? nburn : burn;
355
356       err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, currlen);
357       if (err)
358         break;
359
360       outbuf += currlen;
361       inbuf += currlen;
362       outbuflen -= currlen;
363       inbuflen -= currlen;
364     }
365
366   if (burn)
367     _gcry_burn_stack (burn + sizeof(void *) * 5);
368   return err;
369 }
370
371
372 gcry_err_code_t
373 _gcry_cipher_ccm_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
374                           size_t outbuflen, const unsigned char *inbuf,
375                           size_t inbuflen)
376 {
377   gcry_err_code_t err = 0;
378   unsigned int burn = 0;
379   unsigned int nburn;
380
381   if (outbuflen < inbuflen)
382     return GPG_ERR_BUFFER_TOO_SHORT;
383   if (!c->u_mode.ccm.nonce || c->marks.tag || !c->u_mode.ccm.lengths ||
384       c->u_mode.ccm.aadlen > 0)
385     return GPG_ERR_INV_STATE;
386   if (inbuflen > c->u_mode.ccm.encryptlen)
387     return GPG_ERR_INV_LENGTH;
388
389   while (inbuflen)
390     {
391       size_t currlen = inbuflen;
392
393       /* Since checksumming is done after decryption, process input in 24KiB
394        * chunks to keep data loaded in L1 cache for checksumming. */
395       if (currlen > 24 * 1024)
396         currlen = 24 * 1024;
397
398       err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, currlen);
399       if (err)
400         break;
401
402       c->u_mode.ccm.encryptlen -= currlen;
403       nburn = do_cbc_mac (c, outbuf, currlen, 0);
404       burn = nburn > burn ? nburn : burn;
405
406       outbuf += currlen;
407       inbuf += currlen;
408       outbuflen -= currlen;
409       inbuflen -= currlen;
410     }
411
412   if (burn)
413     _gcry_burn_stack (burn + sizeof(void *) * 5);
414   return err;
415 }