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