1/*
2 * ascCrypt.c - simple ASC (ComCryption) encrypt/decrypt utility
3 */
4
5#include "cspwrap.h"
6#include "common.h"
7#include <security_cdsa_utils/cuFileIo.h>
8#include <string.h>
9#include <stdlib.h>
10#include <stdio.h>
11#include <time.h>
12#include <Security/cssm.h>
13#include <Security/cssmapple.h>
14#include <CoreFoundation/CoreFoundation.h>
15
16static void usage(char **argv)
17{
18	printf("usage:\n");
19	printf("  %s op password inFile outFile [k=keysize] [o=optimize]\n", argv[0]);
20	printf("  op:\n");
21	printf("     e  encrypt\n");
22	printf("     d  decrypt\n");
23	printf("  optimize:\n");
24	printf("     d  default\n");
25	printf("     s  size\n");
26	printf("     e  Security\n");
27	printf("     t  time\n");
28	printf("     z  time+size\n");
29	printf("     a  ASCII\n");
30	exit(1);
31}
32
33int main(int argc, char **argv)
34{
35	int				rtn;
36	uint32			keySizeInBytes = CSP_ASC_KEY_SIZE_DEFAULT / 8;
37	uint32			optimize = CSSM_ASC_OPTIMIZE_DEFAULT;
38	char			*password;			// ASCII password from cmd line
39	char			*inFileName;		// from cmd line
40	unsigned char 	*inFile;			// raw infile data
41	unsigned		inFileSize;			// in bytes
42	char			*outFileName;		// from cmd line
43	CSSM_CSP_HANDLE	cspHand;
44	CSSM_RETURN		crtn;
45	int				doEncrypt = 0;
46	CSSM_DATA		passwordData;
47	CSSM_DATA		saltData = {8, (uint8 *)"someSalt"};
48	CSSM_DATA		inData;				// data to encrypt/decrypt, from inFile
49	CSSM_DATA		outData = {0, NULL};// result data, written to outFile
50	CSSM_KEY_PTR	symKey;
51	int				arg;
52	char			*argp;
53	CFAbsoluteTime 	start, end;
54	CSSM_CC_HANDLE	ccHand;				// crypto context
55	CSSM_DATA		remData = {0, NULL};
56	CSSM_SIZE		bytesProcessed;
57	CSSM_DATA		iv = {0, NULL};
58
59	if(argc < 5) {
60		usage(argv);
61	}
62
63	/* gather up cmd line args */
64	switch(argv[1][0]) {
65		case 'e':
66			doEncrypt = 1;
67			break;
68		case 'd':
69			doEncrypt = 0;
70			break;
71		default:
72			usage(argv);
73	}
74	password = argv[2];
75	passwordData.Data = (uint8 *)password;
76	passwordData.Length = strlen(password);
77	inFileName = argv[3];
78	outFileName = argv[4];
79
80	/* optional args */
81	for(arg=5; arg<argc; arg++) {
82		argp = argv[arg];
83		switch(argp[0]) {
84			case 'k':
85				keySizeInBytes = atoi(&argp[2]);
86				if(keySizeInBytes == 0) {
87					printf("keySize of 0 illegal\n");
88					exit(1);
89				}
90				break;
91			case 'o':
92				switch(argp[2]) {
93					case 'd':
94						optimize = CSSM_ASC_OPTIMIZE_DEFAULT;
95						break;
96					case 's':
97						optimize = CSSM_ASC_OPTIMIZE_SIZE;
98						break;
99					case 'e':
100						optimize = CSSM_ASC_OPTIMIZE_SECURITY;
101						break;
102					case 't':
103						optimize = CSSM_ASC_OPTIMIZE_TIME;
104						break;
105					case 'z':
106						optimize = CSSM_ASC_OPTIMIZE_TIME_SIZE;
107						break;
108					case 'a':
109						optimize = CSSM_ASC_OPTIMIZE_ASCII;
110						break;
111					default:
112						usage(argv);
113				}
114				break;
115			default:
116				usage(argv);
117		}
118	}
119
120	/* read inFile from disk */
121	rtn = readFile(inFileName, &inFile, &inFileSize);
122	if(rtn) {
123		printf("Error reading %s: %s\n", inFileName, strerror(rtn));
124		exit(1);
125	}
126	inData.Data = inFile;
127	inData.Length = inFileSize;
128
129	/* attach to CSP */
130	cspHand = cspStartup();
131	if(cspHand == 0) {
132		exit(1);
133	}
134
135	/*
136	 * Derive an actual encryption/decryption key from the password ASCII text.
137	 * We could use the ASCII text directly as key material but using the DeriveKey
138	 * function is much more secure (besides being an industry-standard way to
139	 * convert an ASCII password into binary key material).
140	 */
141	symKey = cspDeriveKey(cspHand,
142		CSSM_ALGID_PKCS5_PBKDF2,
143		CSSM_ALGID_ASC,
144		"someLabel",		// keyLabel, not important
145		9,					// keyLabelLen
146		doEncrypt ? CSSM_KEYUSE_ENCRYPT : CSSM_KEYUSE_DECRYPT,
147		keySizeInBytes * 8,	// keySizeInBits,
148		CSSM_FALSE,			// raw key
149		&passwordData,
150		&saltData,
151		1000,				// iterCount, 1000 is the minimum
152		&iv);
153	if(symKey == NULL) {
154		exit(1);
155	}
156
157	/*
158	 * Cook up a symmetric encrypt/decrypt context using the key we just derived
159	 */
160	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
161		CSSM_ALGID_ASC,			// encryption algorithm
162		CSSM_ALGMODE_NONE,		// mode
163		NULL,					// access cred
164		symKey,
165		NULL,					// InitVector
166		CSSM_PADDING_NONE,		// Padding
167		NULL,					// Params
168		&ccHand);
169	if(crtn) {
170		printError("CSSM_CSP_CreateSymmetricContext", crtn);
171		exit(1);
172	}
173
174	/* add in optimal optimization attribute */
175	if(optimize != CSSM_ASC_OPTIMIZE_DEFAULT) {
176		crtn = AddContextAttribute(ccHand,
177			CSSM_ATTRIBUTE_ASC_OPTIMIZATION,
178			sizeof(uint32),
179			CAT_Uint32,
180			NULL,
181			optimize);
182		if(crtn) {
183			exit(1);
184		}
185	}
186
187	/*
188	 * Do the encrypt/decrypt.
189	 */
190	start = CFAbsoluteTimeGetCurrent();
191	if(doEncrypt) {
192		crtn = CSSM_EncryptDataInit(ccHand);
193		if(crtn) {
194			printError("CSSM_EncryptDataInit", crtn);
195			exit(1);
196		}
197
198		/* this step can be performed an arbitrary number of times, with
199		 * the appropriate housekeeping of inData and outData */
200		crtn = CSSM_EncryptDataUpdate(ccHand,
201			&inData,
202			1,
203			&outData,
204			1,
205			&bytesProcessed);
206		if(crtn) {
207			printError("CSSM_EncryptDataUpdate", crtn);
208			exit(1);
209		}
210		outData.Length = bytesProcessed;
211
212		/* one call more to clean up */
213		crtn = CSSM_EncryptDataFinal(ccHand, &remData);
214		if(crtn) {
215			printError("CSSM_EncryptDataFinal", crtn);
216			exit(1);
217		}
218		if(remData.Length != 0) {
219			/* append remaining data to outData */
220			uint32 newLen = outData.Length + remData.Length;
221			outData.Data = (uint8 *)appRealloc(outData.Data,
222				newLen,
223				NULL);
224			memmove(outData.Data + outData.Length, remData.Data, remData.Length);
225			outData.Length = newLen;
226			appFree(remData.Data, NULL);
227		}
228	}
229	else {
230		crtn = CSSM_DecryptDataInit(ccHand);
231		if(crtn) {
232			printError("CSSM_DecryptDataInit", crtn);
233			exit(1);
234		}
235
236		/* this step can be performed an arbitrary number of times, with
237		 * the appropriate housekeeping of inData and outData */
238		crtn = CSSM_DecryptDataUpdate(ccHand,
239			&inData,
240			1,
241			&outData,
242			1,
243			&bytesProcessed);
244		if(crtn) {
245			printError("CSSM_DecryptDataUpdate", crtn);
246			exit(1);
247		}
248		outData.Length = bytesProcessed;
249
250		/* one call more to clean up */
251		crtn = CSSM_DecryptDataFinal(ccHand, &remData);
252		if(crtn) {
253			printError("CSSM_DecryptDataFinal", crtn);
254			exit(1);
255		}
256		if(remData.Length != 0) {
257			/* append remaining data to outData */
258			uint32 newLen = outData.Length + remData.Length;
259			outData.Data = (uint8 *)appRealloc(outData.Data,
260				newLen,
261				NULL);
262			memmove(outData.Data + outData.Length, remData.Data, remData.Length);
263			outData.Length = newLen;
264			appFree(remData.Data, NULL);
265		}
266	}
267
268	end = CFAbsoluteTimeGetCurrent();
269	if(crtn == CSSM_OK) {
270		double inSizeD = (double)inFileSize;
271		double outSizeD = (double)outData.Length;
272		CFAbsoluteTime delta = end - start;
273
274		rtn = writeFile(outFileName, outData.Data, outData.Length);
275		if(rtn) {
276			printf("Error writing %s: %s\n", outFileName, strerror(rtn));
277			exit(1);
278		}
279		printf("    inFile length %d bytes, outFile length %lu bytes, "
280			"%d ms\n",
281			inFileSize, outData.Length, (unsigned)(delta * 1000.0));
282		printf("    compression = %.2f     %.2f KBytes/s\n",
283			doEncrypt ? outSizeD / inSizeD : inSizeD / outSizeD,
284			inSizeD / delta / 1024.0);
285	}
286
287	/* free key, outData, etc. */
288	CSSM_ModuleDetach(cspHand);
289	return rtn;
290}
291
292