]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | File: cryptTool.c | |
3 | ||
4 | Description: simple encrypt/decrypt utility to demonstrate CDSA API | |
5 | used for symmetric encryption | |
6 | ||
7 | Author: dmitch | |
8 | ||
9 | Copyright: Copyright (c) 2001,2003,2005-2006 Apple Computer, Inc. All Rights Reserved. | |
10 | ||
11 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple | |
12 | Computer, Inc. ("Apple") in consideration of your agreement to | |
13 | the following terms, and your use, installation, modification | |
14 | or redistribution of this Apple software constitutes acceptance | |
15 | of these terms. If you do not agree with these terms, please | |
16 | do not use, install, modify or redistribute this Apple software. | |
17 | ||
18 | In consideration of your agreement to abide by the following | |
19 | terms, and subject to these terms, Apple grants you a personal, | |
20 | non-exclusive license, under Apple's copyrights in this | |
21 | original Apple software (the "Apple Software"), to use, | |
22 | reproduce, modify and redistribute the Apple Software, with | |
23 | or without modifications, in source and/or binary forms; | |
24 | provided that if you redistribute the Apple Software in | |
25 | its entirety and without modifications, you must retain | |
26 | this notice and the following text and disclaimers in all | |
27 | such redistributions of the Apple Software. Neither the | |
28 | name, trademarks, service marks or logos of Apple Computer, | |
29 | Inc. may be used to endorse or promote products derived from the | |
30 | Apple Software without specific prior written permission from | |
31 | Apple. Except as expressly stated in this notice, no other | |
32 | rights or licenses, express or implied, are granted by Apple | |
33 | herein, including but not limited to any patent rights that | |
34 | may be infringed by your derivative works or by other works | |
35 | in which the Apple Software may be incorporated. | |
36 | ||
37 | The Apple Software is provided by Apple on an "AS IS" basis. | |
38 | APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING | |
39 | WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, | |
40 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, | |
41 | REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE | |
42 | OR IN COMBINATION WITH YOUR PRODUCTS. | |
43 | ||
44 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, | |
45 | INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
46 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
47 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
48 | ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION | |
49 | AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED | |
50 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING | |
51 | NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE | |
52 | HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
53 | */ | |
54 | ||
55 | #include "common.h" | |
56 | #include <security_cdsa_utils/cuFileIo.h> | |
57 | #include <stdio.h> | |
58 | #include <string.h> | |
59 | #include <stdlib.h> | |
60 | ||
61 | static void usage(char **argv) | |
62 | { | |
63 | printf("usage:\n"); | |
64 | printf(" %s op password keySize inFile outFile [a=algorithm]\n", argv[0]); | |
65 | printf(" op:\n"); | |
66 | printf(" e encrypt\n"); | |
67 | printf(" d decrypt\n"); | |
68 | printf(" algorithm:\n"); | |
69 | printf(" 4 RC4 (default if no algorithm specified)\n"); | |
70 | printf(" c ASC/ComCryption\n"); | |
71 | printf(" d DES\n"); | |
72 | printf(" a AES\n"); | |
73 | exit(1); | |
74 | } | |
75 | ||
76 | /* | |
77 | * Derive symmetric key. | |
78 | */ | |
79 | static CSSM_RETURN ctDeriveKey(CSSM_CSP_HANDLE cspHand, | |
80 | uint32 keyAlg, // CSSM_ALGID_RC5, etc. | |
81 | const char *keyLabel, | |
82 | unsigned keyLabelLen, | |
83 | uint32 keyUsage, // CSSM_KEYUSE_ENCRYPT, etc. | |
84 | uint32 keySizeInBits, | |
85 | CSSM_DATA_PTR password, // in PKCS-5 lingo | |
86 | CSSM_DATA_PTR salt, // ditto | |
87 | uint32 iterationCnt, // ditto | |
88 | CSSM_KEY_PTR key) | |
89 | { | |
90 | CSSM_RETURN crtn; | |
91 | CSSM_CC_HANDLE ccHand; | |
92 | uint32 keyAttr; | |
93 | CSSM_DATA dummyLabel; | |
94 | CSSM_PKCS5_PBKDF2_PARAMS pbeParams; | |
95 | CSSM_DATA pbeData; | |
96 | CSSM_ACCESS_CREDENTIALS creds; | |
97 | ||
98 | memset(key, 0, sizeof(CSSM_KEY)); | |
99 | memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); | |
100 | crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand, | |
101 | CSSM_ALGID_PKCS5_PBKDF2, | |
102 | keyAlg, | |
103 | keySizeInBits, | |
104 | &creds, | |
105 | NULL, // BaseKey | |
106 | iterationCnt, | |
107 | salt, | |
108 | NULL, // seed | |
109 | &ccHand); | |
110 | if(crtn) { | |
111 | printError("CSSM_CSP_CreateDeriveKeyContext", crtn); | |
112 | return crtn; | |
113 | } | |
114 | keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF | | |
115 | CSSM_KEYATTR_SENSITIVE; | |
116 | dummyLabel.Length = keyLabelLen; | |
117 | dummyLabel.Data = (uint8 *)keyLabel; | |
118 | ||
119 | /* passing in password is pretty strange....*/ | |
120 | pbeParams.Passphrase = *password; | |
121 | pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1; | |
122 | pbeData.Data = (uint8 *)&pbeParams; | |
123 | pbeData.Length = sizeof(pbeParams); | |
124 | crtn = CSSM_DeriveKey(ccHand, | |
125 | &pbeData, | |
126 | keyUsage, | |
127 | keyAttr, | |
128 | &dummyLabel, | |
129 | NULL, // cred and acl | |
130 | key); | |
131 | if(crtn) { | |
132 | printError("CSSM_DeriveKey", crtn); | |
133 | return crtn; | |
134 | } | |
135 | crtn = CSSM_DeleteContext(ccHand); | |
136 | if(crtn) { | |
137 | printError("CSSM_DeleteContext", crtn); | |
138 | } | |
139 | return crtn; | |
140 | } | |
141 | ||
142 | ||
143 | int main(int argc, char **argv) | |
144 | { | |
145 | int rtn; | |
146 | uint32 keySizeInBytes; // from cmd line | |
147 | char *password; // ASCII password from cmd line | |
148 | char *inFileName; // from cmd line | |
149 | unsigned char *inFile; // raw infile data | |
150 | unsigned inFileSize; // in bytes | |
151 | char *outFileName; // from cmd line | |
152 | CSSM_CSP_HANDLE cspHand; | |
153 | CSSM_RETURN crtn; | |
154 | int doEncrypt = 0; | |
155 | CSSM_DATA passwordData; | |
156 | CSSM_DATA saltData = {8, (uint8 *)"someSalt"}; | |
157 | CSSM_DATA inData; // data to encrypt/decrypt, from inFile | |
158 | CSSM_DATA outData = {0, NULL};// result data, written to outFile | |
159 | CSSM_CC_HANDLE ccHand; // crypto context | |
160 | CSSM_DATA remData = {0, NULL}; | |
161 | CSSM_SIZE bytesProcessed; | |
162 | CSSM_KEY symKey; | |
163 | char algSpec = '4'; | |
164 | CSSM_ALGORITHMS keyAlg = 0; | |
165 | CSSM_ALGORITHMS encrAlg = 0; | |
166 | CSSM_ENCRYPT_MODE encrMode = 0; | |
167 | CSSM_PADDING padding = 0; | |
168 | /* max of 16 bytes of init vector for the algs we use */ | |
169 | CSSM_DATA initVect = {16, (uint8 *)"someStrangeInitVector"}; | |
170 | CSSM_DATA_PTR initVectPtr = NULL; | |
171 | ||
172 | if(argc < 6) { | |
173 | usage(argv); | |
174 | } | |
175 | ||
176 | /* gather up cmd line args */ | |
177 | switch(argv[1][0]) { | |
178 | case 'e': | |
179 | doEncrypt = 1; | |
180 | break; | |
181 | case 'd': | |
182 | doEncrypt = 0; | |
183 | break; | |
184 | default: | |
185 | usage(argv); | |
186 | } | |
187 | password = argv[2]; | |
188 | passwordData.Data = (uint8 *)password; | |
189 | passwordData.Length = strlen(password); | |
190 | keySizeInBytes = atoi(argv[3]); | |
191 | if(keySizeInBytes == 0) { | |
192 | printf("keySize of 0 illegal\n"); | |
193 | exit(1); | |
194 | } | |
195 | inFileName = argv[4]; | |
196 | outFileName = argv[5]; | |
197 | ||
198 | /* optional algorithm specifier */ | |
199 | if(argc == 7) { | |
200 | if(argv[6][0] != 'a') { | |
201 | usage(argv); | |
202 | } | |
203 | algSpec = argv[6][2]; | |
204 | } | |
205 | ||
206 | /* algorithm-specific parameters */ | |
207 | switch(algSpec) { | |
208 | case '4': | |
209 | /* RC4 stream cipher - no padding, no IV, variable key size */ | |
210 | keyAlg = CSSM_ALGID_RC4; | |
211 | encrAlg = CSSM_ALGID_RC4; | |
212 | encrMode = CSSM_ALGMODE_NONE; | |
213 | padding = CSSM_PADDING_NONE; | |
214 | break; | |
215 | case 'c': | |
216 | /* ComCryption stream cipher - no padding, no IV, variable key size */ | |
217 | keyAlg = CSSM_ALGID_ASC; | |
218 | encrAlg = CSSM_ALGID_ASC; | |
219 | encrMode = CSSM_ALGMODE_NONE; | |
220 | padding = CSSM_PADDING_NONE; | |
221 | break; | |
222 | case 'd': | |
223 | /* DES block cipher, block size = 8 bytes, fixed key size */ | |
224 | if(keySizeInBytes != 8) { | |
225 | printf("***DES must have key size of 8 bytes\n"); | |
226 | exit(1); | |
227 | } | |
228 | keyAlg = CSSM_ALGID_DES; | |
229 | encrAlg = CSSM_ALGID_DES; | |
230 | encrMode = CSSM_ALGMODE_CBCPadIV8; | |
231 | padding = CSSM_PADDING_PKCS7; | |
232 | initVect.Length = 8; | |
233 | initVectPtr = &initVect; | |
234 | break; | |
235 | case 'a': | |
236 | /* AES block cipher, block size = 16 bytes, fixed key size */ | |
237 | if(keySizeInBytes != 16) { | |
238 | printf("***AES must have key size of 8 bytes\n"); | |
239 | exit(1); | |
240 | } | |
241 | keyAlg = CSSM_ALGID_AES; | |
242 | encrAlg = CSSM_ALGID_AES; | |
243 | encrMode = CSSM_ALGMODE_CBCPadIV8; | |
244 | padding = CSSM_PADDING_PKCS7; | |
245 | initVect.Length = 16; | |
246 | initVectPtr = &initVect; | |
247 | break; | |
248 | default: | |
249 | usage(argv); | |
250 | } | |
251 | ||
252 | /* read inFile from disk */ | |
253 | rtn = readFile(inFileName, &inFile, &inFileSize); | |
254 | if(rtn) { | |
255 | printf("Error reading %s: %s\n", inFileName, strerror(rtn)); | |
256 | exit(1); | |
257 | } | |
258 | inData.Data = inFile; | |
259 | inData.Length = inFileSize; | |
260 | ||
261 | /* attach to CSP */ | |
262 | cspHand = cspStartup(); | |
263 | if(cspHand == 0) { | |
264 | exit(1); | |
265 | } | |
266 | ||
267 | /* | |
268 | * Derive an actual encryption/decryption key from the password ASCII text. | |
269 | * We could use the ASCII text directly as key material but using the DeriveKey | |
270 | * function is much more secure (besides being an industry-standard way to | |
271 | * convert an ASCII password into binary key material). | |
272 | */ | |
273 | crtn = ctDeriveKey(cspHand, | |
274 | keyAlg, | |
275 | "someLabel", // keyLabel, not important | |
276 | 9, // keyLabelLen | |
277 | doEncrypt ? CSSM_KEYUSE_ENCRYPT : CSSM_KEYUSE_DECRYPT, | |
278 | keySizeInBytes * 8, // keySizeInBits, | |
279 | &passwordData, | |
280 | &saltData, | |
281 | 1000, // iterCount, 1000 is the minimum | |
282 | &symKey); | |
283 | if(crtn) { | |
284 | exit(1); | |
285 | } | |
286 | ||
287 | /* | |
288 | * Cook up a symmetric encrypt/decrypt context using the key we just derived | |
289 | */ | |
290 | crtn = CSSM_CSP_CreateSymmetricContext(cspHand, | |
291 | encrAlg, // encryption algorithm | |
292 | encrMode, // mode | |
293 | NULL, // access cred | |
294 | &symKey, | |
295 | initVectPtr, // InitVector | |
296 | padding, // Padding | |
297 | NULL, // Params | |
298 | &ccHand); | |
299 | if(crtn) { | |
300 | printError("CSSM_CSP_CreateSymmetricContext", crtn); | |
301 | exit(1); | |
302 | } | |
303 | ||
304 | /* | |
305 | * Do the encrypt/decrypt. | |
306 | * We do this with the init/update/final sequence only to demonstrate its | |
307 | * usage. | |
308 | */ | |
309 | if(doEncrypt) { | |
310 | crtn = CSSM_EncryptDataInit(ccHand); | |
311 | if(crtn) { | |
312 | printError("CSSM_EncryptDataInit", crtn); | |
313 | exit(1); | |
314 | } | |
315 | ||
316 | /* this step can be performed an arbitrary number of times, with | |
317 | * the appropriate housekeeping of inData and outData */ | |
318 | crtn = CSSM_EncryptDataUpdate(ccHand, | |
319 | &inData, | |
320 | 1, | |
321 | &outData, | |
322 | 1, | |
323 | &bytesProcessed); | |
324 | if(crtn) { | |
325 | printError("CSSM_EncryptDataUpdate", crtn); | |
326 | exit(1); | |
327 | } | |
328 | outData.Length = bytesProcessed; | |
329 | ||
330 | /* one call more to clean up */ | |
331 | crtn = CSSM_EncryptDataFinal(ccHand, &remData); | |
332 | if(crtn) { | |
333 | printError("CSSM_EncryptDataFinal", crtn); | |
334 | exit(1); | |
335 | } | |
336 | if(remData.Length != 0) { | |
337 | /* append remaining data to outData */ | |
338 | uint32 newLen = outData.Length + remData.Length; | |
339 | outData.Data = (uint8 *)appRealloc(outData.Data, | |
340 | newLen, | |
341 | NULL); | |
342 | memmove(outData.Data + outData.Length, remData.Data, remData.Length); | |
343 | outData.Length = newLen; | |
344 | appFree(remData.Data, NULL); | |
345 | } | |
346 | } | |
347 | else { | |
348 | crtn = CSSM_DecryptDataInit(ccHand); | |
349 | if(crtn) { | |
350 | printError("CSSM_DecryptDataInit", crtn); | |
351 | exit(1); | |
352 | } | |
353 | ||
354 | /* this step can be performed an arbitrary number of times, with | |
355 | * the appropriate housekeeping of inData and outData */ | |
356 | crtn = CSSM_DecryptDataUpdate(ccHand, | |
357 | &inData, | |
358 | 1, | |
359 | &outData, | |
360 | 1, | |
361 | &bytesProcessed); | |
362 | if(crtn) { | |
363 | printError("CSSM_DecryptDataUpdate", crtn); | |
364 | exit(1); | |
365 | } | |
366 | outData.Length = bytesProcessed; | |
367 | ||
368 | /* one call more to clean up */ | |
369 | crtn = CSSM_DecryptDataFinal(ccHand, &remData); | |
370 | if(crtn) { | |
371 | printError("CSSM_DecryptDataFinal", crtn); | |
372 | exit(1); | |
373 | } | |
374 | if(remData.Length != 0) { | |
375 | /* append remaining data to outData */ | |
376 | uint32 newLen = outData.Length + remData.Length; | |
377 | outData.Data = (uint8 *)appRealloc(outData.Data, | |
378 | newLen, | |
379 | NULL); | |
380 | memmove(outData.Data + outData.Length, remData.Data, remData.Length); | |
381 | outData.Length = newLen; | |
382 | appFree(remData.Data, NULL); | |
383 | } | |
384 | } | |
385 | if(crtn == CSSM_OK) { | |
386 | rtn = writeFile(outFileName, outData.Data, outData.Length); | |
387 | if(rtn) { | |
388 | printf("Error writing %s: %s\n", outFileName, strerror(rtn)); | |
389 | exit(1); | |
390 | } | |
391 | else { | |
392 | printf("SUCCESS: inFile length %u bytes, outFile length %u bytes\n", | |
393 | inFileSize, (unsigned)outData.Length); | |
394 | } | |
395 | } | |
396 | /* free resources */ | |
397 | crtn = CSSM_DeleteContext(ccHand); | |
398 | if(crtn) { | |
399 | printError("CSSM_DeleteContext", crtn); | |
400 | } | |
401 | crtn = CSSM_FreeKey(cspHand, | |
402 | NULL, // access cred | |
403 | &symKey, | |
404 | CSSM_FALSE); // don't delete since it wasn't permanent | |
405 | if(crtn) { | |
406 | printError("CSSM_FreeKey", crtn); | |
407 | } | |
408 | free(inFile); // mallocd by readFile() | |
409 | ||
410 | /* this was mallocd by CSP */ | |
411 | appFree(outData.Data, NULL); | |
412 | CSSM_ModuleDetach(cspHand); | |
413 | return rtn; | |
414 | } | |
415 |