]> pd.if.org Git - zpackage/blob - libtomcrypt/src/encauth/ccm/ccm_memory.c
commit files needed for zpm-fetchurl
[zpackage] / libtomcrypt / src / encauth / ccm / ccm_memory.c
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 #include "tomcrypt.h"
10
11 /**
12   @file ccm_memory.c
13   CCM support, process a block of memory, Tom St Denis
14 */
15
16 #ifdef LTC_CCM_MODE
17
18 /**
19    CCM encrypt/decrypt and produce an authentication tag
20
21      *1 'pt', 'ct' and 'tag' can both be 'in' or 'out', depending on 'direction'
22
23    @param cipher     The index of the cipher desired
24    @param key        The secret key to use
25    @param keylen     The length of the secret key (octets)
26    @param uskey      A previously scheduled key [optional can be NULL]
27    @param nonce      The session nonce [use once]
28    @param noncelen   The length of the nonce
29    @param header     The header for the session
30    @param headerlen  The length of the header (octets)
31    @param pt         [*1] The plaintext
32    @param ptlen      The length of the plaintext (octets)
33    @param ct         [*1] The ciphertext
34    @param tag        [*1] The destination tag
35    @param taglen     The max size and resulting size of the authentication tag
36    @param direction  Encrypt or Decrypt direction (0 or 1)
37    @return CRYPT_OK if successful
38 */
39 int ccm_memory(int cipher,
40     const unsigned char *key,    unsigned long keylen,
41     symmetric_key       *uskey,
42     const unsigned char *nonce,  unsigned long noncelen,
43     const unsigned char *header, unsigned long headerlen,
44           unsigned char *pt,     unsigned long ptlen,
45           unsigned char *ct,
46           unsigned char *tag,    unsigned long *taglen,
47                     int  direction)
48 {
49    unsigned char  PAD[16], ctr[16], CTRPAD[16], ptTag[16], b, *pt_real;
50    unsigned char *pt_work = NULL;
51    symmetric_key *skey;
52    int            err;
53    unsigned long  len, L, x, y, z, CTRlen;
54 #ifdef LTC_FAST
55    LTC_FAST_TYPE fastMask = ~(LTC_FAST_TYPE)0; /* initialize fastMask at all zeroes */
56 #endif
57    unsigned char mask = 0xff; /* initialize mask at all zeroes */
58
59    if (uskey == NULL) {
60       LTC_ARGCHK(key    != NULL);
61    }
62    LTC_ARGCHK(nonce  != NULL);
63    if (headerlen > 0) {
64       LTC_ARGCHK(header != NULL);
65    }
66    LTC_ARGCHK(pt     != NULL);
67    LTC_ARGCHK(ct     != NULL);
68    LTC_ARGCHK(tag    != NULL);
69    LTC_ARGCHK(taglen != NULL);
70
71    pt_real = pt;
72
73 #ifdef LTC_FAST
74    if (16 % sizeof(LTC_FAST_TYPE)) {
75       return CRYPT_INVALID_ARG;
76    }
77 #endif
78
79    /* check cipher input */
80    if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
81       return err;
82    }
83    if (cipher_descriptor[cipher].block_length != 16) {
84       return CRYPT_INVALID_CIPHER;
85    }
86
87    /* make sure the taglen is even and <= 16 */
88    *taglen &= ~1;
89    if (*taglen > 16) {
90       *taglen = 16;
91    }
92
93    /* can't use < 4 */
94    if (*taglen < 4) {
95       return CRYPT_INVALID_ARG;
96    }
97
98    /* is there an accelerator? */
99    if (cipher_descriptor[cipher].accel_ccm_memory != NULL) {
100        return cipher_descriptor[cipher].accel_ccm_memory(
101            key,    keylen,
102            uskey,
103            nonce,  noncelen,
104            header, headerlen,
105            pt,     ptlen,
106            ct,
107            tag,    taglen,
108            direction);
109    }
110
111    /* let's get the L value */
112    len = ptlen;
113    L   = 0;
114    while (len) {
115       ++L;
116       len >>= 8;
117    }
118    if (L <= 1) {
119       L = 2;
120    }
121
122    /* increase L to match the nonce len */
123    noncelen = (noncelen > 13) ? 13 : noncelen;
124    if ((15 - noncelen) > L) {
125       L = 15 - noncelen;
126    }
127
128    /* allocate mem for the symmetric key */
129    if (uskey == NULL) {
130       skey = XMALLOC(sizeof(*skey));
131       if (skey == NULL) {
132          return CRYPT_MEM;
133       }
134
135       /* initialize the cipher */
136       if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, skey)) != CRYPT_OK) {
137          XFREE(skey);
138          return err;
139       }
140    } else {
141       skey = uskey;
142    }
143
144    /* initialize buffer for pt */
145    if (direction == CCM_DECRYPT && ptlen > 0) {
146       pt_work = XMALLOC(ptlen);
147       if (pt_work == NULL) {
148          goto error;
149       }
150       pt = pt_work;
151    }
152
153    /* form B_0 == flags | Nonce N | l(m) */
154    x = 0;
155    PAD[x++] = (unsigned char)(((headerlen > 0) ? (1<<6) : 0) |
156             (((*taglen - 2)>>1)<<3)        |
157             (L-1));
158
159    /* nonce */
160    for (y = 0; y < (16 - (L + 1)); y++) {
161        PAD[x++] = nonce[y];
162    }
163
164    /* store len */
165    len = ptlen;
166
167    /* shift len so the upper bytes of len are the contents of the length */
168    for (y = L; y < 4; y++) {
169        len <<= 8;
170    }
171
172    /* store l(m) (only store 32-bits) */
173    for (y = 0; L > 4 && (L-y)>4; y++) {
174        PAD[x++] = 0;
175    }
176    for (; y < L; y++) {
177        PAD[x++] = (unsigned char)((len >> 24) & 255);
178        len <<= 8;
179    }
180
181    /* encrypt PAD */
182    if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
183        goto error;
184    }
185
186    /* handle header */
187    if (headerlen > 0) {
188       x = 0;
189
190       /* store length */
191       if (headerlen < ((1UL<<16) - (1UL<<8))) {
192          PAD[x++] ^= (headerlen>>8) & 255;
193          PAD[x++] ^= headerlen & 255;
194       } else {
195          PAD[x++] ^= 0xFF;
196          PAD[x++] ^= 0xFE;
197          PAD[x++] ^= (headerlen>>24) & 255;
198          PAD[x++] ^= (headerlen>>16) & 255;
199          PAD[x++] ^= (headerlen>>8) & 255;
200          PAD[x++] ^= headerlen & 255;
201       }
202
203       /* now add the data */
204       for (y = 0; y < headerlen; y++) {
205           if (x == 16) {
206              /* full block so let's encrypt it */
207              if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
208                 goto error;
209              }
210              x = 0;
211           }
212           PAD[x++] ^= header[y];
213       }
214
215       /* remainder */
216       if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
217          goto error;
218       }
219    }
220
221    /* setup the ctr counter */
222    x = 0;
223
224    /* flags */
225    ctr[x++] = (unsigned char)L-1;
226
227    /* nonce */
228    for (y = 0; y < (16 - (L+1)); ++y) {
229       ctr[x++] = nonce[y];
230    }
231    /* offset */
232    while (x < 16) {
233       ctr[x++] = 0;
234    }
235
236    x      = 0;
237    CTRlen = 16;
238
239    /* now handle the PT */
240    if (ptlen > 0) {
241       y = 0;
242 #ifdef LTC_FAST
243       if (ptlen & ~15)  {
244           if (direction == CCM_ENCRYPT) {
245              for (; y < (ptlen & ~15); y += 16) {
246                 /* increment the ctr? */
247                 for (z = 15; z > 15-L; z--) {
248                     ctr[z] = (ctr[z] + 1) & 255;
249                     if (ctr[z]) break;
250                 }
251                 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
252                    goto error;
253                 }
254
255                 /* xor the PT against the pad first */
256                 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
257                     *(LTC_FAST_TYPE_PTR_CAST(&PAD[z]))  ^= *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z]));
258                     *(LTC_FAST_TYPE_PTR_CAST(&ct[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) ^ *(LTC_FAST_TYPE_PTR_CAST(&CTRPAD[z]));
259                 }
260                 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
261                    goto error;
262                 }
263              }
264           } else { /* direction == CCM_DECRYPT */
265              for (; y < (ptlen & ~15); y += 16) {
266                 /* increment the ctr? */
267                 for (z = 15; z > 15-L; z--) {
268                     ctr[z] = (ctr[z] + 1) & 255;
269                     if (ctr[z]) break;
270                 }
271                 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
272                    goto error;
273                 }
274
275                 /* xor the PT against the pad last */
276                 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
277                     *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&ct[y+z])) ^ *(LTC_FAST_TYPE_PTR_CAST(&CTRPAD[z]));
278                     *(LTC_FAST_TYPE_PTR_CAST(&PAD[z]))  ^= *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z]));
279                 }
280                 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
281                    goto error;
282                 }
283              }
284           }
285       }
286 #endif
287
288       for (; y < ptlen; y++) {
289           /* increment the ctr? */
290           if (CTRlen == 16) {
291              for (z = 15; z > 15-L; z--) {
292                  ctr[z] = (ctr[z] + 1) & 255;
293                  if (ctr[z]) break;
294              }
295              if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
296                 goto error;
297              }
298              CTRlen = 0;
299           }
300
301           /* if we encrypt we add the bytes to the MAC first */
302           if (direction == CCM_ENCRYPT) {
303              b     = pt[y];
304              ct[y] = b ^ CTRPAD[CTRlen++];
305           } else {
306              b     = ct[y] ^ CTRPAD[CTRlen++];
307              pt[y] = b;
308           }
309
310           if (x == 16) {
311              if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
312                 goto error;
313              }
314              x = 0;
315           }
316           PAD[x++] ^= b;
317       }
318
319       if (x != 0) {
320          if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
321             goto error;
322          }
323       }
324    }
325
326    /* setup CTR for the TAG (zero the count) */
327    for (y = 15; y > 15 - L; y--) {
328       ctr[y] = 0x00;
329    }
330    if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
331       goto error;
332    }
333
334    if (skey != uskey) {
335       cipher_descriptor[cipher].done(skey);
336 #ifdef LTC_CLEAN_STACK
337       zeromem(skey,   sizeof(*skey));
338 #endif
339    }
340
341    if (direction == CCM_ENCRYPT) {
342       /* store the TAG */
343       for (x = 0; x < 16 && x < *taglen; x++) {
344           tag[x] = PAD[x] ^ CTRPAD[x];
345       }
346       *taglen = x;
347    } else { /* direction == CCM_DECRYPT */
348       /* decrypt the tag */
349       for (x = 0; x < 16 && x < *taglen; x++) {
350          ptTag[x] = tag[x] ^ CTRPAD[x];
351       }
352       *taglen = x;
353
354       /* check validity of the decrypted tag against the computed PAD (in constant time) */
355       /* HACK: the boolean value of XMEM_NEQ becomes either 0 (CRYPT_OK) or 1 (CRYPT_ERR).
356        *       there should be a better way of setting the correct error code in constant
357        *       time.
358        */
359       err = XMEM_NEQ(ptTag, PAD, *taglen);
360
361       /* Zero the plaintext if the tag was invalid (in constant time) */
362       if (ptlen > 0) {
363          y = 0;
364          mask *= 1 - err; /* mask = ( err ? 0 : 0xff ) */
365 #ifdef LTC_FAST
366          fastMask *= 1 - err;
367          if (ptlen & ~15) {
368             for (; y < (ptlen & ~15); y += 16) {
369               for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
370                 *(LTC_FAST_TYPE_PTR_CAST(&pt_real[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) & fastMask;
371               }
372             }
373          }
374 #endif
375          for (; y < ptlen; y++) {
376             pt_real[y] = pt[y] & mask;
377          }
378       }
379    }
380
381 #ifdef LTC_CLEAN_STACK
382 #ifdef LTC_FAST
383    fastMask = 0;
384 #endif
385    mask = 0;
386    zeromem(PAD,    sizeof(PAD));
387    zeromem(CTRPAD, sizeof(CTRPAD));
388    if (pt_work != NULL) {
389      zeromem(pt_work, ptlen);
390    }
391 #endif
392 error:
393    if (pt_work) {
394       XFREE(pt_work);
395    }
396    if (skey != uskey) {
397       XFREE(skey);
398    }
399
400    return err;
401 }
402
403 #endif
404
405 /* ref:         $Format:%D$ */
406 /* git commit:  $Format:%H$ */
407 /* commit time: $Format:%ai$ */