• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 */
ccm_memory(int cipher,const unsigned char * key,unsigned long keylen,symmetric_key * uskey,const unsigned char * nonce,unsigned long noncelen,const unsigned char * header,unsigned long headerlen,unsigned char * pt,unsigned long ptlen,unsigned char * ct,unsigned char * tag,unsigned long * taglen,int direction)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