Home | History | Annotate | Download | only in ccm
      1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
      2  *
      3  * LibTomCrypt is a library that provides various cryptographic
      4  * algorithms in a highly modular and flexible manner.
      5  *
      6  * The library is free for all purposes without any express
      7  * guarantee it works.
      8  *
      9  * Tom St Denis, tomstdenis (at) gmail.com, http://libtomcrypt.com
     10  */
     11 #include "tomcrypt.h"
     12 
     13 /**
     14   @file ccm_memory.c
     15   CCM support, process a block of memory, Tom St Denis
     16 */
     17 
     18 #ifdef CCM_MODE
     19 
     20 /**
     21    CCM encrypt/decrypt and produce an authentication tag
     22    @param cipher     The index of the cipher desired
     23    @param key        The secret key to use
     24    @param keylen     The length of the secret key (octets)
     25    @param uskey      A previously scheduled key [optional can be NULL]
     26    @param nonce      The session nonce [use once]
     27    @param noncelen   The length of the nonce
     28    @param header     The header for the session
     29    @param headerlen  The length of the header (octets)
     30    @param pt         [out] The plaintext
     31    @param ptlen      The length of the plaintext (octets)
     32    @param ct         [out] The ciphertext
     33    @param tag        [out] The destination tag
     34    @param taglen     [in/out] The max size and resulting size of the authentication tag
     35    @param direction  Encrypt or Decrypt direction (0 or 1)
     36    @return CRYPT_OK if successful
     37 */
     38 int ccm_memory(int cipher,
     39     const unsigned char *key,    unsigned long keylen,
     40     symmetric_key       *uskey,
     41     const unsigned char *nonce,  unsigned long noncelen,
     42     const unsigned char *header, unsigned long headerlen,
     43           unsigned char *pt,     unsigned long ptlen,
     44           unsigned char *ct,
     45           unsigned char *tag,    unsigned long *taglen,
     46                     int  direction)
     47 {
     48    unsigned char  PAD[16], ctr[16], CTRPAD[16], b;
     49    symmetric_key *skey;
     50    int            err;
     51    unsigned long  len, L, x, y, z, CTRlen;
     52 
     53    if (uskey == NULL) {
     54       LTC_ARGCHK(key    != NULL);
     55    }
     56    LTC_ARGCHK(nonce  != NULL);
     57    if (headerlen > 0) {
     58       LTC_ARGCHK(header != NULL);
     59    }
     60    LTC_ARGCHK(pt     != NULL);
     61    LTC_ARGCHK(ct     != NULL);
     62    LTC_ARGCHK(tag    != NULL);
     63    LTC_ARGCHK(taglen != NULL);
     64 
     65 #ifdef LTC_FAST
     66    if (16 % sizeof(LTC_FAST_TYPE)) {
     67       return CRYPT_INVALID_ARG;
     68    }
     69 #endif
     70 
     71    /* check cipher input */
     72    if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
     73       return err;
     74    }
     75    if (cipher_descriptor[cipher].block_length != 16) {
     76       return CRYPT_INVALID_CIPHER;
     77    }
     78 
     79    /* make sure the taglen is even and <= 16 */
     80    *taglen &= ~1;
     81    if (*taglen > 16) {
     82       *taglen = 16;
     83    }
     84 
     85    /* can't use < 4 */
     86    if (*taglen < 4) {
     87       return CRYPT_INVALID_ARG;
     88    }
     89 
     90    /* is there an accelerator? */
     91    if (cipher_descriptor[cipher].accel_ccm_memory != NULL) {
     92        return cipher_descriptor[cipher].accel_ccm_memory(
     93            key,    keylen,
     94            uskey,
     95            nonce,  noncelen,
     96            header, headerlen,
     97            pt,     ptlen,
     98            ct,
     99            tag,    taglen,
    100            direction);
    101    }
    102 
    103    /* let's get the L value */
    104    len = ptlen;
    105    L   = 0;
    106    while (len) {
    107       ++L;
    108       len >>= 8;
    109    }
    110    if (L <= 1) {
    111       L = 2;
    112    }
    113 
    114    /* increase L to match the nonce len */
    115    noncelen = (noncelen > 13) ? 13 : noncelen;
    116    if ((15 - noncelen) > L) {
    117       L = 15 - noncelen;
    118    }
    119 
    120    /* decrease noncelen to match L */
    121    if ((noncelen + L) > 15) {
    122       noncelen = 15 - L;
    123    }
    124 
    125    /* allocate mem for the symmetric key */
    126    if (uskey == NULL) {
    127       skey = XMALLOC(sizeof(*skey));
    128       if (skey == NULL) {
    129          return CRYPT_MEM;
    130       }
    131 
    132       /* initialize the cipher */
    133       if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, skey)) != CRYPT_OK) {
    134          XFREE(skey);
    135          return err;
    136       }
    137    } else {
    138       skey = uskey;
    139    }
    140 
    141    /* form B_0 == flags | Nonce N | l(m) */
    142    x = 0;
    143    PAD[x++] = (unsigned char)(((headerlen > 0) ? (1<<6) : 0) |
    144             (((*taglen - 2)>>1)<<3)        |
    145             (L-1));
    146 
    147    /* nonce */
    148    for (y = 0; y < (16 - (L + 1)); y++) {
    149        PAD[x++] = nonce[y];
    150    }
    151 
    152    /* store len */
    153    len = ptlen;
    154 
    155    /* shift len so the upper bytes of len are the contents of the length */
    156    for (y = L; y < 4; y++) {
    157        len <<= 8;
    158    }
    159 
    160    /* store l(m) (only store 32-bits) */
    161    for (y = 0; L > 4 && (L-y)>4; y++) {
    162        PAD[x++] = 0;
    163    }
    164    for (; y < L; y++) {
    165        PAD[x++] = (unsigned char)((len >> 24) & 255);
    166        len <<= 8;
    167    }
    168 
    169    /* encrypt PAD */
    170    if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
    171        goto error;
    172    }
    173 
    174    /* handle header */
    175    if (headerlen > 0) {
    176       x = 0;
    177 
    178       /* store length */
    179       if (headerlen < ((1UL<<16) - (1UL<<8))) {
    180          PAD[x++] ^= (headerlen>>8) & 255;
    181          PAD[x++] ^= headerlen & 255;
    182       } else {
    183          PAD[x++] ^= 0xFF;
    184          PAD[x++] ^= 0xFE;
    185          PAD[x++] ^= (headerlen>>24) & 255;
    186          PAD[x++] ^= (headerlen>>16) & 255;
    187          PAD[x++] ^= (headerlen>>8) & 255;
    188          PAD[x++] ^= headerlen & 255;
    189       }
    190 
    191       /* now add the data */
    192       for (y = 0; y < headerlen; y++) {
    193           if (x == 16) {
    194              /* full block so let's encrypt it */
    195              if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
    196                 goto error;
    197              }
    198              x = 0;
    199           }
    200           PAD[x++] ^= header[y];
    201       }
    202 
    203       /* remainder? */
    204       if (x != 0) {
    205          if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
    206             goto error;
    207          }
    208       }
    209    }
    210 
    211    /* setup the ctr counter */
    212    x = 0;
    213 
    214    /* flags */
    215    ctr[x++] = (unsigned char)L-1;
    216 
    217    /* nonce */
    218    for (y = 0; y < (16 - (L+1)); ++y) {
    219       ctr[x++] = nonce[y];
    220    }
    221    /* offset */
    222    while (x < 16) {
    223       ctr[x++] = 0;
    224    }
    225 
    226    x      = 0;
    227    CTRlen = 16;
    228 
    229    /* now handle the PT */
    230    if (ptlen > 0) {
    231       y = 0;
    232 #ifdef LTC_FAST
    233       if (ptlen & ~15)  {
    234           if (direction == CCM_ENCRYPT) {
    235              for (; y < (ptlen & ~15); y += 16) {
    236                 /* increment the ctr? */
    237                 for (z = 15; z > 15-L; z--) {
    238                     ctr[z] = (ctr[z] + 1) & 255;
    239                     if (ctr[z]) break;
    240                 }
    241                 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
    242                    goto error;
    243                 }
    244 
    245                 /* xor the PT against the pad first */
    246                 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
    247                     *((LTC_FAST_TYPE*)(&PAD[z]))  ^= *((LTC_FAST_TYPE*)(&pt[y+z]));
    248                     *((LTC_FAST_TYPE*)(&ct[y+z])) = *((LTC_FAST_TYPE*)(&pt[y+z])) ^ *((LTC_FAST_TYPE*)(&CTRPAD[z]));
    249                 }
    250                 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
    251                    goto error;
    252                 }
    253              }
    254          } else {
    255              for (; y < (ptlen & ~15); y += 16) {
    256                 /* increment the ctr? */
    257                 for (z = 15; z > 15-L; z--) {
    258                     ctr[z] = (ctr[z] + 1) & 255;
    259                     if (ctr[z]) break;
    260                 }
    261                 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
    262                    goto error;
    263                 }
    264 
    265                 /* xor the PT against the pad last */
    266                 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
    267                     *((LTC_FAST_TYPE*)(&pt[y+z])) = *((LTC_FAST_TYPE*)(&ct[y+z])) ^ *((LTC_FAST_TYPE*)(&CTRPAD[z]));
    268                     *((LTC_FAST_TYPE*)(&PAD[z]))  ^= *((LTC_FAST_TYPE*)(&pt[y+z]));
    269                 }
    270                 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
    271                    goto error;
    272                 }
    273              }
    274          }
    275      }
    276 #endif
    277 
    278       for (; y < ptlen; y++) {
    279           /* increment the ctr? */
    280           if (CTRlen == 16) {
    281              for (z = 15; z > 15-L; z--) {
    282                  ctr[z] = (ctr[z] + 1) & 255;
    283                  if (ctr[z]) break;
    284              }
    285              if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
    286                 goto error;
    287              }
    288              CTRlen = 0;
    289           }
    290 
    291           /* if we encrypt we add the bytes to the MAC first */
    292           if (direction == CCM_ENCRYPT) {
    293              b     = pt[y];
    294              ct[y] = b ^ CTRPAD[CTRlen++];
    295           } else {
    296              b     = ct[y] ^ CTRPAD[CTRlen++];
    297              pt[y] = b;
    298           }
    299 
    300           if (x == 16) {
    301              if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
    302                 goto error;
    303              }
    304              x = 0;
    305           }
    306           PAD[x++] ^= b;
    307       }
    308 
    309       if (x != 0) {
    310          if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
    311             goto error;
    312          }
    313       }
    314    }
    315 
    316    /* setup CTR for the TAG (zero the count) */
    317    for (y = 15; y > 15 - L; y--) {
    318       ctr[y] = 0x00;
    319    }
    320    if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
    321       goto error;
    322    }
    323 
    324    if (skey != uskey) {
    325       cipher_descriptor[cipher].done(skey);
    326    }
    327 
    328    /* store the TAG */
    329    for (x = 0; x < 16 && x < *taglen; x++) {
    330        tag[x] = PAD[x] ^ CTRPAD[x];
    331    }
    332    *taglen = x;
    333 
    334 #ifdef LTC_CLEAN_STACK
    335    zeromem(skey,   sizeof(*skey));
    336    zeromem(PAD,    sizeof(PAD));
    337    zeromem(CTRPAD, sizeof(CTRPAD));
    338 #endif
    339 error:
    340    if (skey != uskey) {
    341       XFREE(skey);
    342    }
    343 
    344    return err;
    345 }
    346 
    347 #endif
    348 
    349 /* $Source: /cvs/libtom/libtomcrypt/src/encauth/ccm/ccm_memory.c,v $ */
    350 /* $Revision: 1.18 $ */
    351 /* $Date: 2006/12/04 21:34:03 $ */
    352