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