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