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 if (x >= sizeof(PAD)) {
165 err = CRYPT_INVALID_ARG;
166 goto error;
167 }
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