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