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*/
38int 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
339error:
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