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