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