1/*
2 * CSP symmetric encryption performance measurement tool
3 * Based on Michael Brouwer's cryptoPerformance.cpp; this one does not
4 * use CssmClient.
5 *
6 */
7#include <CoreFoundation/CoreFoundation.h>
8#include <security_cdsa_utilities/cssmdata.h>
9#include <security_cdsa_utilities/cssmerrors.h>
10#include <string.h>
11#include "cspwrap.h"
12#include "common.h"
13#include <iomanip>
14#include <iostream>
15#include <memory>
16
17using namespace std;
18
19/*
20 * Default values
21 */
22#define ALG_DEFAULT				CSSM_ALGID_AES
23#define ALG_STR_DEFAULT			"AES"
24#define CHAIN_DEFAULT			CSSM_TRUE
25#define ALG_MODE_DEFAULT		CSSM_ALGMODE_CBC_IV8
26#define ALG_MODE_STR_DEFAULT	"CBC"
27#define KEY_SIZE_DEFAULT		128
28#define BLOCK_SIZE_DEFAULT		16
29
30static void usage(char **argv)
31{
32	printf("usage: %s iterations bufsize [options]\n", argv[0]);
33	printf("   Options:\n");
34	printf("   a=algorithm (s=ASC; d=DES; 3=3DES; 2=RC2; 4=RC4; 5=RC5;\n");
35	printf("     a=AES; b=Blowfish; c=CAST; n=NULL; default=AES)\n");
36	printf("   k=keySizeInBits\n");
37	printf("   e (ECB mode; default is CBC)\n");
38	printf("   c (re-create context in each loop)\n");
39	printf("   v(erbose)\n");
40	printf("   h(elp)\n");
41	exit(1);
42}
43
44static int doEncrypt(
45	CSSM_CSP_HANDLE cspHand,
46	CSSM_KEY_PTR symKey,
47	CSSM_BOOL resetContext,
48	unsigned iterations,
49	uint8 blockSizeBytes,
50	CSSM_ALGORITHMS encrAlg,
51	CSSM_ENCRYPT_MODE encrMode,
52	const CSSM_DATA *ptext,		// pre-allocd
53	CSSM_DATA *ctext)
54{
55	CSSM_CC_HANDLE ccHand = 0;
56	char *someIv = "some Initialization vector";
57	CSSM_DATA iv = {blockSizeBytes, (uint8 *)someIv};
58	CSSM_DATA remData = {0, NULL};
59	CSSM_SIZE moved;
60	CSSM_RETURN crtn;
61
62	for(unsigned dex=0; dex<iterations; dex++) {
63		if(ccHand == 0) {
64			/* always the first time, and each loop if resetContext */
65			crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
66				encrAlg,
67				encrMode,
68				NULL,			// access cred
69				symKey,
70				&iv,			// InitVector
71				CSSM_PADDING_NONE,
72				NULL,			// Params
73				&ccHand);
74			if(crtn) {
75				cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn);
76				return -1;
77			}
78		}
79		crtn = CSSM_EncryptData(ccHand, ptext, 1,
80			ctext, 1, &moved, &remData);
81		if(crtn) {
82			cssmPerror("CSSM_EncryptData", crtn);
83			return -1;
84		}
85		if(resetContext) {
86			CSSM_DeleteContext(ccHand);
87			ccHand = 0;
88		}
89	}
90	if(ccHand != 0) {
91		CSSM_DeleteContext(ccHand);
92	}
93	return 0;
94}
95
96static int doDecrypt(
97	CSSM_CSP_HANDLE cspHand,
98	CSSM_KEY_PTR symKey,
99	CSSM_BOOL resetContext,
100	unsigned iterations,
101	uint8 blockSizeBytes,
102	CSSM_ALGORITHMS encrAlg,
103	CSSM_ENCRYPT_MODE encrMode,
104	const CSSM_DATA *ctext,		// pre-allocd
105	CSSM_DATA *rptext)
106{
107	CSSM_CC_HANDLE ccHand = 0;
108	char *someIv = "some Initialization vector";
109	CSSM_DATA iv = {blockSizeBytes, (uint8 *)someIv};
110	CSSM_DATA remData = {0, NULL};
111	CSSM_SIZE moved;
112	CSSM_RETURN crtn;
113
114	for(unsigned dex=0; dex<iterations; dex++) {
115		if(ccHand == 0) {
116			/* always the first time, and each loop if resetContext */
117			crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
118				encrAlg,
119				encrMode,
120				NULL,			// access cred
121				symKey,
122				&iv,			// InitVector
123				CSSM_PADDING_NONE,
124				NULL,			// Params
125				&ccHand);
126			if(crtn) {
127				cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn);
128				return -1;
129			}
130		}
131		crtn = CSSM_DecryptData(ccHand, ctext, 1,
132			rptext, 1, &moved, &remData);
133		if(crtn) {
134			cssmPerror("CSSM_DecryptData", crtn);
135			return -1;
136		}
137		if(resetContext) {
138			CSSM_DeleteContext(ccHand);
139			ccHand = 0;
140		}
141	}
142	CSSM_FreeKey(cspHand, NULL, symKey, CSSM_FALSE);
143	if(ccHand != 0) {
144		CSSM_DeleteContext(ccHand);
145	}
146	return 0;
147}
148
149int main(int argc, char **argv)
150{
151	int					arg;
152	char				*argp;
153	CSSM_ENCRYPT_MODE	mode = ALG_MODE_DEFAULT;
154	char				*modeStr = ALG_MODE_STR_DEFAULT;
155	uint32				blockSizeBytes = BLOCK_SIZE_DEFAULT;
156
157	/*
158	 * User-spec'd params
159	 */
160	CSSM_BOOL			chainEnable = CHAIN_DEFAULT;
161	uint32				keySizeInBits = KEY_SIZE_DEFAULT;
162	char				*algStr = ALG_STR_DEFAULT;
163	uint32				keyAlg = ALG_DEFAULT;		// CSSM_ALGID_xxx of the key
164	uint32				encrAlg = ALG_DEFAULT;		// CSSM_ALGID_xxx for encrypt
165	int 				iterations;
166	int 				bufSize;
167	CSSM_BOOL			resetContext = CSSM_FALSE;
168	CSSM_BOOL			verbose = false;
169
170	if(argc < 3) {
171		usage(argv);
172	}
173	iterations = atoi(argv[1]);
174	bufSize = atoi(argv[2]);
175	for(arg=3; arg<argc; arg++) {
176		argp = argv[arg];
177		switch(argp[0]) {
178			case 'a':
179				if(argp[1] != '=') {
180					usage(argv);
181				}
182				/* only set mode and modeStr if not default (CBC) */
183				switch(argp[2]) {
184					case 's':
185						encrAlg = keyAlg = CSSM_ALGID_ASC;
186						algStr = "ASC";
187						mode = CSSM_ALGMODE_NONE;
188						modeStr = "NONE";
189						blockSizeBytes = 0;
190						break;
191					case 'd':
192						encrAlg = keyAlg = CSSM_ALGID_DES;
193						algStr = "DES";
194						keySizeInBits = 64;
195						blockSizeBytes = 8;
196						break;
197					case '3':
198						keyAlg  = CSSM_ALGID_3DES_3KEY;
199						encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
200						algStr = "3DES";
201						keySizeInBits = 64 * 3;
202						blockSizeBytes = 8;
203						break;
204					case '2':
205						encrAlg = keyAlg = CSSM_ALGID_RC2;
206						algStr = "RC2";
207						blockSizeBytes = 8;
208						break;
209					case '4':
210						encrAlg = keyAlg = CSSM_ALGID_RC4;
211						algStr = "RC4";
212						/* not a block cipher */
213						chainEnable = CSSM_FALSE;
214						mode = CSSM_ALGMODE_NONE;
215						modeStr = "NONE";
216						blockSizeBytes = 0;
217						break;
218					case '5':
219						encrAlg = keyAlg = CSSM_ALGID_RC5;
220						algStr = "RC5";
221						blockSizeBytes = 8;
222						break;
223					case 'a':
224						encrAlg = keyAlg = CSSM_ALGID_AES;
225						algStr = "AES";
226						blockSizeBytes = 16;
227						break;
228					case 'b':
229						encrAlg = keyAlg = CSSM_ALGID_BLOWFISH;
230						algStr = "Blowfish";
231						blockSizeBytes = 8;
232						break;
233					case 'c':
234						encrAlg = keyAlg = CSSM_ALGID_CAST;
235						algStr = "CAST";
236						blockSizeBytes = 8;
237						break;
238					case 'n':
239						encrAlg = keyAlg = CSSM_ALGID_NONE;
240						algStr = "NULL";
241						blockSizeBytes = 8;
242						break;
243					default:
244						usage(argv);
245				}
246				break;
247		    case 'k':
248		    	keySizeInBits = atoi(&argp[2]);
249				break;
250			case 'e':
251				chainEnable = CSSM_FALSE;
252				break;
253			case 'c':
254				resetContext = CSSM_TRUE;
255				break;
256			case 'v':
257				verbose = CSSM_TRUE;
258				break;
259		    case 'h':
260		    default:
261				usage(argv);
262		}
263	}
264	if(!chainEnable) {
265		switch(mode) {
266			case CSSM_ALGMODE_CBC_IV8:
267				mode = CSSM_ALGMODE_ECB;
268				modeStr = "ECB";
269				break;
270			case CSSM_ALGMODE_NONE:
271				/* stream cipher, we weren't running CBC anyway */
272			default:
273				break;
274		}
275	}
276
277	printf("Algorithm: %s   keySize: %u  mode: %s  iterations: %d  "
278		"bufSize %d\n",
279		algStr, (unsigned)keySizeInBits, modeStr, iterations, bufSize);
280
281	CSSM_CSP_HANDLE cspHand = cspStartup();
282	CSSM_DATA ptext;
283	CSSM_DATA ctext;
284	CSSM_DATA rptext;
285
286	appSetupCssmData(&ptext, bufSize);
287	appSetupCssmData(&ctext, bufSize);
288	appSetupCssmData(&rptext, bufSize);
289	simpleGenData(&ptext, ptext.Length, ptext.Length);
290
291	CSSM_KEY_PTR symKey = cspGenSymKey(cspHand, keyAlg,
292		"someLabel", 9,
293		CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
294		keySizeInBits,
295		CSSM_TRUE);
296	if(symKey == NULL) {
297		printf("***Error generating symmetric key\n");
298		exit(1);
299	}
300
301	CFAbsoluteTime start, end;
302	int rtn;
303
304	printf("  %d * cdsaEncrypt %d bytes", iterations, bufSize);
305	fflush(stdout);
306	start = CFAbsoluteTimeGetCurrent();
307	rtn = doEncrypt(cspHand, symKey, resetContext, iterations,
308		blockSizeBytes, encrAlg, mode, &ptext, &ctext);
309	end = CFAbsoluteTimeGetCurrent();
310	if(rtn) {
311		exit(1);
312	}
313	printf(" took: %gs %.1f Kbytes/s\n", end - start,
314		(iterations * bufSize) / (end - start) / 1024.0);
315
316	printf("  %d * cdsaDecrypt %d bytes", iterations, bufSize);
317	fflush(stdout);
318	start = CFAbsoluteTimeGetCurrent();
319	rtn = doDecrypt(cspHand, symKey, resetContext, iterations,
320		blockSizeBytes, encrAlg, mode, &ctext, &rptext);
321	end = CFAbsoluteTimeGetCurrent();
322	if(rtn) {
323		exit(1);
324	}
325	printf(" took: %gs %.1f Kbytes/s\n", end - start,
326		(iterations * bufSize) / (end - start) / 1024.0);
327
328	return 0;
329}
330