LCOV - code coverage report
Current view: top level - cipher - cipher-ccm.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 170 0.0 %
Date: 2016-12-15 12:59:22 Functions: 0 9 0.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           0 : do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen,
      39             :             int do_padding)
      40           0 : {
      41           0 :   const unsigned int blocksize = 16;
      42           0 :   gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
      43           0 :   unsigned char tmp[blocksize];
      44           0 :   unsigned int burn = 0;
      45           0 :   unsigned int unused = c->u_mode.ccm.mac_unused;
      46             :   size_t nblocks;
      47             : 
      48           0 :   if (inlen == 0 && (unused == 0 || !do_padding))
      49           0 :     return 0;
      50             : 
      51             :   do
      52             :     {
      53           0 :       if (inlen + unused < blocksize || unused > 0)
      54             :         {
      55           0 :           for (; inlen && unused < blocksize; inlen--)
      56           0 :             c->u_mode.ccm.macbuf[unused++] = *inbuf++;
      57             :         }
      58           0 :       if (!inlen)
      59             :         {
      60           0 :           if (!do_padding)
      61           0 :             break;
      62             : 
      63           0 :           while (unused < blocksize)
      64           0 :             c->u_mode.ccm.macbuf[unused++] = 0;
      65             :         }
      66             : 
      67           0 :       if (unused > 0)
      68             :         {
      69             :           /* Process one block from macbuf.  */
      70           0 :           buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize);
      71           0 :           set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ));
      72             : 
      73           0 :           unused = 0;
      74             :         }
      75             : 
      76           0 :       if (c->bulk.cbc_enc)
      77             :         {
      78           0 :           nblocks = inlen / blocksize;
      79           0 :           c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, tmp, inbuf, nblocks, 1);
      80           0 :           inbuf += nblocks * blocksize;
      81           0 :           inlen -= nblocks * blocksize;
      82             : 
      83           0 :           wipememory (tmp, sizeof(tmp));
      84             :         }
      85             :       else
      86             :         {
      87           0 :           while (inlen >= blocksize)
      88             :             {
      89           0 :               buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize);
      90             : 
      91           0 :               set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ));
      92             : 
      93           0 :               inlen -= blocksize;
      94           0 :               inbuf += blocksize;
      95             :             }
      96             :         }
      97             :     }
      98           0 :   while (inlen > 0);
      99             : 
     100           0 :   c->u_mode.ccm.mac_unused = unused;
     101             : 
     102           0 :   if (burn)
     103           0 :     burn += 4 * sizeof(void *);
     104             : 
     105           0 :   return burn;
     106             : }
     107             : 
     108             : 
     109             : gcry_err_code_t
     110           0 : _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           0 :   size_t L = 15 - noncelen;
     115             :   size_t L_;
     116             : 
     117           0 :   L_ = L - 1;
     118             : 
     119           0 :   if (!nonce)
     120           0 :     return GPG_ERR_INV_ARG;
     121             :   /* Length field must be 2, 3, ..., or 8. */
     122           0 :   if (L < 2 || L > 8)
     123           0 :     return GPG_ERR_INV_LENGTH;
     124             : 
     125             :   /* Reset state */
     126           0 :   marks_key = c->marks.key;
     127           0 :   memset (&c->u_mode, 0, sizeof(c->u_mode));
     128           0 :   memset (&c->marks, 0, sizeof(c->marks));
     129           0 :   memset (&c->u_iv, 0, sizeof(c->u_iv));
     130           0 :   memset (&c->u_ctr, 0, sizeof(c->u_ctr));
     131           0 :   memset (c->lastiv, 0, sizeof(c->lastiv));
     132           0 :   c->unused = 0;
     133           0 :   c->marks.key = marks_key;
     134             : 
     135             :   /* Setup CTR */
     136           0 :   c->u_ctr.ctr[0] = L_;
     137           0 :   memcpy (&c->u_ctr.ctr[1], nonce, noncelen);
     138           0 :   memset (&c->u_ctr.ctr[1 + noncelen], 0, L);
     139             : 
     140             :   /* Setup IV */
     141           0 :   c->u_iv.iv[0] = L_;
     142           0 :   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           0 :   memset (&c->u_iv.iv[1 + noncelen], 0, L);
     146             : 
     147           0 :   c->u_mode.ccm.nonce = 1;
     148             : 
     149           0 :   return GPG_ERR_NO_ERROR;
     150             : }
     151             : 
     152             : 
     153             : gcry_err_code_t
     154           0 : _gcry_cipher_ccm_set_lengths (gcry_cipher_hd_t c, u64 encryptlen, u64 aadlen,
     155             :                               u64 taglen)
     156             : {
     157           0 :   unsigned int burn = 0;
     158             :   unsigned char b0[16];
     159           0 :   size_t noncelen = 15 - (c->u_iv.iv[0] + 1);
     160           0 :   u64 M = taglen;
     161             :   u64 M_;
     162             :   int i;
     163             : 
     164           0 :   M_ = (M - 2) / 2;
     165             : 
     166             :   /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */
     167           0 :   if ((M_ * 2 + 2) != M || M < 4 || M > 16)
     168           0 :     return GPG_ERR_INV_LENGTH;
     169           0 :   if (!c->u_mode.ccm.nonce || c->marks.tag)
     170           0 :     return GPG_ERR_INV_STATE;
     171           0 :   if (c->u_mode.ccm.lengths)
     172           0 :     return GPG_ERR_INV_STATE;
     173             : 
     174           0 :   c->u_mode.ccm.authlen = taglen;
     175           0 :   c->u_mode.ccm.encryptlen = encryptlen;
     176           0 :   c->u_mode.ccm.aadlen = aadlen;
     177             : 
     178             :   /* Complete IV setup.  */
     179           0 :   c->u_iv.iv[0] += (aadlen > 0) * 64 + M_ * 8;
     180           0 :   for (i = 16 - 1; i >= 1 + noncelen; i--)
     181             :     {
     182           0 :       c->u_iv.iv[i] = encryptlen & 0xff;
     183           0 :       encryptlen >>= 8;
     184             :     }
     185             : 
     186           0 :   memcpy (b0, c->u_iv.iv, 16);
     187           0 :   memset (c->u_iv.iv, 0, 16);
     188             : 
     189           0 :   set_burn (burn, do_cbc_mac (c, b0, 16, 0));
     190             : 
     191           0 :   if (aadlen == 0)
     192             :     {
     193             :       /* Do nothing.  */
     194             :     }
     195           0 :   else if (aadlen > 0 && aadlen <= (unsigned int)0xfeff)
     196             :     {
     197           0 :       b0[0] = (aadlen >> 8) & 0xff;
     198           0 :       b0[1] = aadlen & 0xff;
     199           0 :       set_burn (burn, do_cbc_mac (c, b0, 2, 0));
     200             :     }
     201           0 :   else if (aadlen > 0xfeff && aadlen <= (unsigned int)0xffffffff)
     202             :     {
     203           0 :       b0[0] = 0xff;
     204           0 :       b0[1] = 0xfe;
     205           0 :       buf_put_be32(&b0[2], aadlen);
     206           0 :       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           0 :   set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0,
     218             :                                      c->u_ctr.ctr ));
     219           0 :   c->u_ctr.ctr[15]++;
     220             : 
     221           0 :   if (burn)
     222           0 :     _gcry_burn_stack (burn + sizeof(void *) * 5);
     223             : 
     224           0 :   c->u_mode.ccm.lengths = 1;
     225             : 
     226           0 :   return GPG_ERR_NO_ERROR;
     227             : }
     228             : 
     229             : 
     230             : gcry_err_code_t
     231           0 : _gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf,
     232             :                                size_t abuflen)
     233             : {
     234             :   unsigned int burn;
     235             : 
     236           0 :   if (abuflen > 0 && !abuf)
     237           0 :     return GPG_ERR_INV_ARG;
     238           0 :   if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->marks.tag)
     239           0 :     return GPG_ERR_INV_STATE;
     240           0 :   if (abuflen > c->u_mode.ccm.aadlen)
     241           0 :     return GPG_ERR_INV_LENGTH;
     242             : 
     243           0 :   c->u_mode.ccm.aadlen -= abuflen;
     244           0 :   burn = do_cbc_mac (c, abuf, abuflen, c->u_mode.ccm.aadlen == 0);
     245             : 
     246           0 :   if (burn)
     247           0 :     _gcry_burn_stack (burn + sizeof(void *) * 5);
     248             : 
     249           0 :   return GPG_ERR_NO_ERROR;
     250             : }
     251             : 
     252             : 
     253             : gcry_err_code_t
     254           0 : _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           0 :   if (!outbuf || outbuflen == 0)
     260           0 :     return GPG_ERR_INV_ARG;
     261             :   /* Tag length must be same as initial authlen.  */
     262           0 :   if (c->u_mode.ccm.authlen != outbuflen)
     263           0 :     return GPG_ERR_INV_LENGTH;
     264           0 :   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           0 :   if (c->u_mode.ccm.encryptlen > 0)
     268           0 :     return GPG_ERR_UNFINISHED;
     269             : 
     270           0 :   if (!c->marks.tag)
     271             :     {
     272           0 :       burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding.  */
     273             : 
     274             :       /* Add S_0 */
     275           0 :       buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16);
     276             : 
     277           0 :       wipememory (c->u_ctr.ctr, 16);
     278           0 :       wipememory (c->u_mode.ccm.s0, 16);
     279           0 :       wipememory (c->u_mode.ccm.macbuf, 16);
     280             : 
     281           0 :       if (burn)
     282           0 :         _gcry_burn_stack (burn + sizeof(void *) * 5);
     283             : 
     284           0 :       c->marks.tag = 1;
     285             :     }
     286             : 
     287           0 :   if (!check)
     288             :     {
     289           0 :       memcpy (outbuf, c->u_iv.iv, outbuflen);
     290           0 :       return GPG_ERR_NO_ERROR;
     291             :     }
     292             :   else
     293             :     {
     294           0 :       return buf_eq_const(outbuf, c->u_iv.iv, outbuflen) ?
     295           0 :              GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM;
     296             :     }
     297             : }
     298             : 
     299             : 
     300             : gcry_err_code_t
     301           0 : _gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag,
     302             :                           size_t taglen)
     303             : {
     304           0 :   return _gcry_cipher_ccm_tag (c, outtag, taglen, 0);
     305             : }
     306             : 
     307             : 
     308             : gcry_err_code_t
     309           0 : _gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag,
     310             :                             size_t taglen)
     311             : {
     312           0 :   return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1);
     313             : }
     314             : 
     315             : 
     316             : gcry_err_code_t
     317           0 : _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           0 :   if (outbuflen < inbuflen)
     324           0 :     return GPG_ERR_BUFFER_TOO_SHORT;
     325           0 :   if (!c->u_mode.ccm.nonce || c->marks.tag || !c->u_mode.ccm.lengths ||
     326           0 :       c->u_mode.ccm.aadlen > 0)
     327           0 :     return GPG_ERR_INV_STATE;
     328           0 :   if (inbuflen > c->u_mode.ccm.encryptlen)
     329           0 :     return GPG_ERR_INV_LENGTH;
     330             : 
     331           0 :   c->u_mode.ccm.encryptlen -= inbuflen;
     332           0 :   burn = do_cbc_mac (c, inbuf, inbuflen, 0);
     333           0 :   if (burn)
     334           0 :     _gcry_burn_stack (burn + sizeof(void *) * 5);
     335             : 
     336           0 :   return _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
     337             : }
     338             : 
     339             : 
     340             : gcry_err_code_t
     341           0 : _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           0 :   if (outbuflen < inbuflen)
     349           0 :     return GPG_ERR_BUFFER_TOO_SHORT;
     350           0 :   if (!c->u_mode.ccm.nonce || c->marks.tag || !c->u_mode.ccm.lengths ||
     351           0 :       c->u_mode.ccm.aadlen > 0)
     352           0 :     return GPG_ERR_INV_STATE;
     353           0 :   if (inbuflen > c->u_mode.ccm.encryptlen)
     354           0 :     return GPG_ERR_INV_LENGTH;
     355             : 
     356           0 :   err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen);
     357           0 :   if (err)
     358           0 :     return err;
     359             : 
     360           0 :   c->u_mode.ccm.encryptlen -= inbuflen;
     361           0 :   burn = do_cbc_mac (c, outbuf, inbuflen, 0);
     362           0 :   if (burn)
     363           0 :     _gcry_burn_stack (burn + sizeof(void *) * 5);
     364             : 
     365           0 :   return err;
     366             : }

Generated by: LCOV version 1.12