LCOV - code coverage report
Current view: top level - cipher - cipher-ccm.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 146 170 85.9 %
Date: 2017-03-02 16:44:37 Functions: 9 9 100.0 %

          Line data    Source code
       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      270226 : do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen,
      39             :             int do_padding)
      40      270226 : {
      41      270226 :   const unsigned int blocksize = 16;
      42      270226 :   gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
      43      270226 :   unsigned char tmp[blocksize];
      44      270226 :   unsigned int burn = 0;
      45      270226 :   unsigned int unused = c->u_mode.ccm.mac_unused;
      46             :   size_t nblocks;
      47             : 
      48      270226 :   if (inlen == 0 && (unused == 0 || !do_padding))
      49       54298 :     return 0;
      50             : 
      51             :   do
      52             :     {
      53      243948 :       if (inlen + unused < blocksize || unused > 0)
      54             :         {
      55      649486 :           for (; inlen && unused < blocksize; inlen--)
      56      533960 :             c->u_mode.ccm.macbuf[unused++] = *inbuf++;
      57             :         }
      58      243948 :       if (!inlen)
      59             :         {
      60       88146 :           if (!do_padding)
      61       54056 :             break;
      62             : 
      63      542316 :           while (unused < blocksize)
      64      474136 :             c->u_mode.ccm.macbuf[unused++] = 0;
      65             :         }
      66             : 
      67      189892 :       if (unused > 0)
      68             :         {
      69             :           /* Process one block from macbuf.  */
      70       61470 :           buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize);
      71       61470 :           set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ));
      72             : 
      73       61470 :           unused = 0;
      74             :         }
      75             : 
      76      189892 :       if (c->bulk.cbc_enc)
      77             :         {
      78       88872 :           nblocks = inlen / blocksize;
      79       88872 :           c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, tmp, inbuf, nblocks, 1);
      80       88872 :           inbuf += nblocks * blocksize;
      81       88872 :           inlen -= nblocks * blocksize;
      82             : 
      83       88872 :           wipememory (tmp, sizeof(tmp));
      84             :         }
      85             :       else
      86             :         {
      87     3928690 :           while (inlen >= blocksize)
      88             :             {
      89     3726650 :               buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
      90             : 
      91     3726650 :               set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ));
      92             : 
      93     3726650 :               inlen -= blocksize;
      94     3726650 :               inbuf += blocksize;
      95             :             }
      96             :         }
      97             :     }
      98      189892 :   while (inlen > 0);
      99             : 
     100      215928 :   c->u_mode.ccm.mac_unused = unused;
     101             : 
     102      215928 :   if (burn)
     103       97486 :     burn += 4 * sizeof(void *);
     104             : 
     105      215928 :   return burn;
     106             : }
     107             : 
     108             : 
     109             : gcry_err_code_t
     110       73038 : _gcry_cipher_ccm_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce,
     111             :                             size_t noncelen)
     112             : {
     113             :   unsigned int marks_key;
     114       73038 :   size_t L = 15 - noncelen;
     115             :   size_t L_;
     116             : 
     117       73038 :   L_ = L - 1;
     118             : 
     119       73038 :   if (!nonce)
     120           0 :     return GPG_ERR_INV_ARG;
     121             :   /* Length field must be 2, 3, ..., or 8. */
     122       73038 :   if (L < 2 || L > 8)
     123           0 :     return GPG_ERR_INV_LENGTH;
     124             : 
     125             :   /* Reset state */
     126       73038 :   marks_key = c->marks.key;
     127       73038 :   memset (&c->u_mode, 0, sizeof(c->u_mode));
     128       73038 :   memset (&c->marks, 0, sizeof(c->marks));
     129       73038 :   memset (&c->u_iv, 0, sizeof(c->u_iv));
     130       73038 :   memset (&c->u_ctr, 0, sizeof(c->u_ctr));
     131       73038 :   memset (c->lastiv, 0, sizeof(c->lastiv));
     132       73038 :   c->unused = 0;
     133       73038 :   c->marks.key = marks_key;
     134             : 
     135             :   /* Setup CTR */
     136       73038 :   c->u_ctr.ctr[0] = L_;
     137       73038 :   memcpy (&c->u_ctr.ctr[1], nonce, noncelen);
     138       73038 :   memset (&c->u_ctr.ctr[1 + noncelen], 0, L);
     139             : 
     140             :   /* Setup IV */
     141       73038 :   c->u_iv.iv[0] = L_;
     142       73038 :   memcpy (&c->u_iv.iv[1], nonce, noncelen);
     143             :   /* Add (8 * M_ + 64 * flags) to iv[0] and set iv[noncelen + 1 ... 15] later
     144             :      in set_aad.  */
     145       73038 :   memset (&c->u_iv.iv[1 + noncelen], 0, L);
     146             : 
     147       73038 :   c->u_mode.ccm.nonce = 1;
     148             : 
     149       73038 :   return GPG_ERR_NO_ERROR;
     150             : }
     151             : 
     152             : 
     153             : gcry_err_code_t
     154       73038 : _gcry_cipher_ccm_set_lengths (gcry_cipher_hd_t c, u64 encryptlen, u64 aadlen,
     155             :                               u64 taglen)
     156             : {
     157       73038 :   unsigned int burn = 0;
     158             :   unsigned char b0[16];
     159       73038 :   size_t noncelen = 15 - (c->u_iv.iv[0] + 1);
     160       73038 :   u64 M = taglen;
     161             :   u64 M_;
     162             :   int i;
     163             : 
     164       73038 :   M_ = (M - 2) / 2;
     165             : 
     166             :   /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */
     167       73038 :   if ((M_ * 2 + 2) != M || M < 4 || M > 16)
     168           0 :     return GPG_ERR_INV_LENGTH;
     169       73038 :   if (!c->u_mode.ccm.nonce || c->marks.tag)
     170           0 :     return GPG_ERR_INV_STATE;
     171       73038 :   if (c->u_mode.ccm.lengths)
     172           0 :     return GPG_ERR_INV_STATE;
     173             : 
     174       73038 :   c->u_mode.ccm.authlen = taglen;
     175       73038 :   c->u_mode.ccm.encryptlen = encryptlen;
     176       73038 :   c->u_mode.ccm.aadlen = aadlen;
     177             : 
     178             :   /* Complete IV setup.  */
     179       73038 :   c->u_iv.iv[0] += (aadlen > 0) * 64 + M_ * 8;
     180      371720 :   for (i = 16 - 1; i >= 1 + noncelen; i--)
     181             :     {
     182      298682 :       c->u_iv.iv[i] = encryptlen & 0xff;
     183      298682 :       encryptlen >>= 8;
     184             :     }
     185             : 
     186       73038 :   memcpy (b0, c->u_iv.iv, 16);
     187       73038 :   memset (c->u_iv.iv, 0, 16);
     188             : 
     189       73038 :   set_burn (burn, do_cbc_mac (c, b0, 16, 0));
     190             : 
     191       73038 :   if (aadlen == 0)
     192             :     {
     193             :       /* Do nothing.  */
     194             :     }
     195       17046 :   else if (aadlen > 0 && aadlen <= (unsigned int)0xfeff)
     196             :     {
     197       17044 :       b0[0] = (aadlen >> 8) & 0xff;
     198       17044 :       b0[1] = aadlen & 0xff;
     199       17044 :       set_burn (burn, do_cbc_mac (c, b0, 2, 0));
     200             :     }
     201           2 :   else if (aadlen > 0xfeff && aadlen <= (unsigned int)0xffffffff)
     202             :     {
     203           2 :       b0[0] = 0xff;
     204           2 :       b0[1] = 0xfe;
     205           2 :       buf_put_be32(&b0[2], aadlen);
     206           2 :       set_burn (burn, do_cbc_mac (c, b0, 6, 0));
     207             :     }
     208           0 :   else if (aadlen > (unsigned int)0xffffffff)
     209             :     {
     210           0 :       b0[0] = 0xff;
     211           0 :       b0[1] = 0xff;
     212           0 :       buf_put_be64(&b0[2], aadlen);
     213           0 :       set_burn (burn, do_cbc_mac (c, b0, 10, 0));
     214             :     }
     215             : 
     216             :   /* Generate S_0 and increase counter.  */
     217       73038 :   set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0,
     218             :                                      c->u_ctr.ctr ));
     219       73038 :   c->u_ctr.ctr[15]++;
     220             : 
     221       73038 :   if (burn)
     222       41257 :     _gcry_burn_stack (burn + sizeof(void *) * 5);
     223             : 
     224       73038 :   c->u_mode.ccm.lengths = 1;
     225             : 
     226       73038 :   return GPG_ERR_NO_ERROR;
     227             : }
     228             : 
     229             : 
     230             : gcry_err_code_t
     231       18644 : _gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf,
     232             :                                size_t abuflen)
     233             : {
     234             :   unsigned int burn;
     235             : 
     236       18644 :   if (abuflen > 0 && !abuf)
     237           0 :     return GPG_ERR_INV_ARG;
     238       18644 :   if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->marks.tag)
     239           0 :     return GPG_ERR_INV_STATE;
     240       18644 :   if (abuflen > c->u_mode.ccm.aadlen)
     241           0 :     return GPG_ERR_INV_LENGTH;
     242             : 
     243       18644 :   c->u_mode.ccm.aadlen -= abuflen;
     244       18644 :   burn = do_cbc_mac (c, abuf, abuflen, c->u_mode.ccm.aadlen == 0);
     245             : 
     246       18644 :   if (burn)
     247        6982 :     _gcry_burn_stack (burn + sizeof(void *) * 5);
     248             : 
     249       18644 :   return GPG_ERR_NO_ERROR;
     250             : }
     251             : 
     252             : 
     253             : gcry_err_code_t
     254       69966 : _gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf,
     255             :                       size_t outbuflen, int check)
     256             : {
     257             :   unsigned int burn;
     258             : 
     259       69966 :   if (!outbuf || outbuflen == 0)
     260           0 :     return GPG_ERR_INV_ARG;
     261             :   /* Tag length must be same as initial authlen.  */
     262       69966 :   if (c->u_mode.ccm.authlen != outbuflen)
     263           0 :     return GPG_ERR_INV_LENGTH;
     264       69966 :   if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->u_mode.ccm.aadlen > 0)
     265           0 :     return GPG_ERR_INV_STATE;
     266             :   /* Initial encrypt length must match with length of actual data processed.  */
     267       69966 :   if (c->u_mode.ccm.encryptlen > 0)
     268           0 :     return GPG_ERR_UNFINISHED;
     269             : 
     270       69966 :   if (!c->marks.tag)
     271             :     {
     272       69966 :       burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding.  */
     273             : 
     274             :       /* Add S_0 */
     275       69966 :       buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16);
     276             : 
     277       69966 :       wipememory (c->u_ctr.ctr, 16);
     278       69966 :       wipememory (c->u_mode.ccm.s0, 16);
     279       69966 :       wipememory (c->u_mode.ccm.macbuf, 16);
     280             : 
     281       69966 :       if (burn)
     282        6854 :         _gcry_burn_stack (burn + sizeof(void *) * 5);
     283             : 
     284       69966 :       c->marks.tag = 1;
     285             :     }
     286             : 
     287       69966 :   if (!check)
     288             :     {
     289       45948 :       memcpy (outbuf, c->u_iv.iv, outbuflen);
     290       45948 :       return GPG_ERR_NO_ERROR;
     291             :     }
     292             :   else
     293             :     {
     294       24018 :       return buf_eq_const(outbuf, c->u_iv.iv, outbuflen) ?
     295       24018 :              GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
     296             :     }
     297             : }
     298             : 
     299             : 
     300             : gcry_err_code_t
     301       45948 : _gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
     302             :                           size_t taglen)
     303             : {
     304       45948 :   return _gcry_cipher_ccm_tag (c, outtag, taglen, 0);
     305             : }
     306             : 
     307             : 
     308             : gcry_err_code_t
     309       24018 : _gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
     310             :                             size_t taglen)
     311             : {
     312       24018 :   return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1);
     313             : }
     314             : 
     315             : 
     316             : gcry_err_code_t
     317       56858 : _gcry_cipher_ccm_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
     318             :                           size_t outbuflen, const unsigned char *inbuf,
     319             :                           size_t inbuflen)
     320             : {
     321             :   unsigned int burn;
     322             : 
     323       56858 :   if (outbuflen < inbuflen)
     324           0 :     return GPG_ERR_BUFFER_TOO_SHORT;
     325      113716 :   if (!c->u_mode.ccm.nonce || c->marks.tag || !c->u_mode.ccm.lengths ||
     326       56858 :       c->u_mode.ccm.aadlen > 0)
     327           0 :     return GPG_ERR_INV_STATE;
     328       56858 :   if (inbuflen > c->u_mode.ccm.encryptlen)
     329           0 :     return GPG_ERR_INV_LENGTH;
     330             : 
     331       56858 :   c->u_mode.ccm.encryptlen -= inbuflen;
     332       56858 :   burn = do_cbc_mac (c, inbuf, inbuflen, 0);
     333       56858 :   if (burn)
     334       22710 :     _gcry_burn_stack (burn + sizeof(void *) * 5);
     335             : 
     336       56858 :   return _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
     337             : }
     338             : 
     339             : 
     340             : gcry_err_code_t
     341       34674 : _gcry_cipher_ccm_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf,
     342             :                           size_t outbuflen, const unsigned char *inbuf,
     343             :                           size_t inbuflen)
     344             : {
     345             :   gcry_err_code_t err;
     346             :   unsigned int burn;
     347             : 
     348       34674 :   if (outbuflen < inbuflen)
     349           0 :     return GPG_ERR_BUFFER_TOO_SHORT;
     350       69348 :   if (!c->u_mode.ccm.nonce || c->marks.tag || !c->u_mode.ccm.lengths ||
     351       34674 :       c->u_mode.ccm.aadlen > 0)
     352           0 :     return GPG_ERR_INV_STATE;
     353       34674 :   if (inbuflen > c->u_mode.ccm.encryptlen)
     354           0 :     return GPG_ERR_INV_LENGTH;
     355             : 
     356       34674 :   err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
     357       34674 :   if (err)
     358           0 :     return err;
     359             : 
     360       34674 :   c->u_mode.ccm.encryptlen -= inbuflen;
     361       34674 :   burn = do_cbc_mac (c, outbuf, inbuflen, 0);
     362       34674 :   if (burn)
     363       20404 :     _gcry_burn_stack (burn + sizeof(void *) * 5);
     364             : 
     365       34674 :   return err;
     366             : }

Generated by: LCOV version 1.13