comparison libtomcrypt/src/encauth/ccm/ccm_memory.c @ 285:1b9e69c058d2

propagate from branch 'au.asn.ucc.matt.ltc.dropbear' (head 20dccfc09627970a312d77fb41dc2970b62689c3) to branch 'au.asn.ucc.matt.dropbear' (head fdf4a7a3b97ae5046139915de7e40399cceb2c01)
author Matt Johnston <matt@ucc.asn.au>
date Wed, 08 Mar 2006 13:23:58 +0000
parents
children 0cbe8f6dbf9e
comparison
equal deleted inserted replaced
281:997e6f7dc01e 285:1b9e69c058d2
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, [email protected], http://libtomcrypt.org
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 nonce The session nonce [use once]
26 @param noncelen The length of the nonce
27 @param header The header for the session
28 @param headerlen The length of the header (octets)
29 @param pt [out] The plaintext
30 @param ptlen The length of the plaintext (octets)
31 @param ct [out] The ciphertext
32 @param tag [out] The destination tag
33 @param taglen [in/out] The max size and resulting size of the authentication tag
34 @param direction Encrypt or Decrypt direction (0 or 1)
35 @return CRYPT_OK if successful
36 */
37 int ccm_memory(int cipher,
38 const unsigned char *key, unsigned long keylen,
39 const unsigned char *nonce, unsigned long noncelen,
40 const unsigned char *header, unsigned long headerlen,
41 unsigned char *pt, unsigned long ptlen,
42 unsigned char *ct,
43 unsigned char *tag, unsigned long *taglen,
44 int direction)
45 {
46 unsigned char PAD[16], ctr[16], CTRPAD[16], b;
47 symmetric_key *skey;
48 int err;
49 unsigned long len, L, x, y, z, CTRlen;
50
51 LTC_ARGCHK(key != NULL);
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 #ifdef LTC_FAST
62 if (16 % sizeof(LTC_FAST_TYPE)) {
63 return CRYPT_INVALID_ARG;
64 }
65 #endif
66
67 /* check cipher input */
68 if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
69 return err;
70 }
71 if (cipher_descriptor[cipher].block_length != 16) {
72 return CRYPT_INVALID_CIPHER;
73 }
74
75 /* make sure the taglen is even and <= 16 */
76 *taglen &= ~1;
77 if (*taglen > 16) {
78 *taglen = 16;
79 }
80
81 /* can't use < 4 */
82 if (*taglen < 4) {
83 return CRYPT_INVALID_ARG;
84 }
85
86 /* is there an accelerator? */
87 if (cipher_descriptor[cipher].accel_ccm_memory != NULL) {
88 cipher_descriptor[cipher].accel_ccm_memory(
89 key, keylen,
90 nonce, noncelen,
91 header, headerlen,
92 pt, ptlen,
93 ct,
94 tag, taglen,
95 direction);
96 return CRYPT_OK;
97 }
98
99 /* let's get the L value */
100 len = ptlen;
101 L = 0;
102 while (len) {
103 ++L;
104 len >>= 8;
105 }
106 if (L <= 1) {
107 L = 2;
108 }
109
110 /* increase L to match the nonce len */
111 noncelen = (noncelen > 13) ? 13 : noncelen;
112 if ((15 - noncelen) > L) {
113 L = 15 - noncelen;
114 }
115
116 /* allocate mem for the symmetric key */
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
128 /* form B_0 == flags | Nonce N | l(m) */
129 x = 0;
130 PAD[x++] = ((headerlen > 0) ? (1<<6) : 0) |
131 (((*taglen - 2)>>1)<<3) |
132 (L-1);
133
134 /* nonce */
135 for (y = 0; y < (16 - (L + 1)); y++) {
136 PAD[x++] = nonce[y];
137 }
138
139 /* store len */
140 len = ptlen;
141
142 /* shift len so the upper bytes of len are the contents of the length */
143 for (y = L; y < 4; y++) {
144 len <<= 8;
145 }
146
147 /* store l(m) (only store 32-bits) */
148 for (y = 0; L > 4 && (L-y)>4; y++) {
149 PAD[x++] = 0;
150 }
151 for (; y < L; y++) {
152 PAD[x++] = (len >> 24) & 255;
153 len <<= 8;
154 }
155
156 /* encrypt PAD */
157 cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
158
159 /* handle header */
160 if (headerlen > 0) {
161 x = 0;
162
163 /* store length */
164 if (headerlen < ((1UL<<16) - (1UL<<8))) {
165 PAD[x++] ^= (headerlen>>8) & 255;
166 PAD[x++] ^= headerlen & 255;
167 } else {
168 PAD[x++] ^= 0xFF;
169 PAD[x++] ^= 0xFE;
170 PAD[x++] ^= (headerlen>>24) & 255;
171 PAD[x++] ^= (headerlen>>16) & 255;
172 PAD[x++] ^= (headerlen>>8) & 255;
173 PAD[x++] ^= headerlen & 255;
174 }
175
176 /* now add the data */
177 for (y = 0; y < headerlen; y++) {
178 if (x == 16) {
179 /* full block so let's encrypt it */
180 cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
181 x = 0;
182 }
183 PAD[x++] ^= header[y];
184 }
185
186 /* remainder? */
187 if (x != 0) {
188 cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
189 }
190 }
191
192 /* setup the ctr counter */
193 x = 0;
194
195 /* flags */
196 ctr[x++] = L-1;
197
198 /* nonce */
199 for (y = 0; y < (16 - (L+1)); ++y) {
200 ctr[x++] = nonce[y];
201 }
202 /* offset */
203 while (x < 16) {
204 ctr[x++] = 0;
205 }
206
207 x = 0;
208 CTRlen = 16;
209
210 /* now handle the PT */
211 if (ptlen > 0) {
212 y = 0;
213 #ifdef LTC_FAST
214 if (ptlen & ~15) {
215 if (direction == CCM_ENCRYPT) {
216 for (; y < (ptlen & ~15); y += 16) {
217 /* increment the ctr? */
218 for (z = 15; z > 15-L; z--) {
219 ctr[z] = (ctr[z] + 1) & 255;
220 if (ctr[z]) break;
221 }
222 cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey);
223
224 /* xor the PT against the pad first */
225 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
226 *((LTC_FAST_TYPE*)(&PAD[z])) ^= *((LTC_FAST_TYPE*)(&pt[y+z]));
227 *((LTC_FAST_TYPE*)(&ct[y+z])) = *((LTC_FAST_TYPE*)(&pt[y+z])) ^ *((LTC_FAST_TYPE*)(&CTRPAD[z]));
228 }
229 cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
230 }
231 } else {
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 cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey);
239
240 /* xor the PT against the pad last */
241 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
242 *((LTC_FAST_TYPE*)(&pt[y+z])) = *((LTC_FAST_TYPE*)(&ct[y+z])) ^ *((LTC_FAST_TYPE*)(&CTRPAD[z]));
243 *((LTC_FAST_TYPE*)(&PAD[z])) ^= *((LTC_FAST_TYPE*)(&pt[y+z]));
244 }
245 cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
246 }
247 }
248 }
249 #endif
250
251 for (; y < ptlen; y++) {
252 /* increment the ctr? */
253 if (CTRlen == 16) {
254 for (z = 15; z > 15-L; z--) {
255 ctr[z] = (ctr[z] + 1) & 255;
256 if (ctr[z]) break;
257 }
258 cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey);
259 CTRlen = 0;
260 }
261
262 /* if we encrypt we add the bytes to the MAC first */
263 if (direction == CCM_ENCRYPT) {
264 b = pt[y];
265 ct[y] = b ^ CTRPAD[CTRlen++];
266 } else {
267 b = ct[y] ^ CTRPAD[CTRlen++];
268 pt[y] = b;
269 }
270
271 if (x == 16) {
272 cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
273 x = 0;
274 }
275 PAD[x++] ^= b;
276 }
277
278 if (x != 0) {
279 cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
280 }
281 }
282
283 /* setup CTR for the TAG */
284 ctr[14] = ctr[15] = 0x00;
285 cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey);
286 cipher_descriptor[cipher].done(skey);
287
288 /* store the TAG */
289 for (x = 0; x < 16 && x < *taglen; x++) {
290 tag[x] = PAD[x] ^ CTRPAD[x];
291 }
292 *taglen = x;
293
294 #ifdef LTC_CLEAN_STACK
295 zeromem(skey, sizeof(*skey));
296 zeromem(PAD, sizeof(PAD));
297 zeromem(CTRPAD, sizeof(CTRPAD));
298 #endif
299
300 XFREE(skey);
301
302 return CRYPT_OK;
303 }
304
305 #endif
306
307 /* $Source: /cvs/libtom/libtomcrypt/src/encauth/ccm/ccm_memory.c,v $ */
308 /* $Revision: 1.9 $ */
309 /* $Date: 2005/05/05 14:35:58 $ */