1/*
2 * ccPerform.cpp - measure performance of CommonCrypto encryption
3 */
4
5#include <stdlib.h>
6#include <strings.h>
7#include <stdio.h>
8#include <unistd.h>
9#include <CoreFoundation/CoreFoundation.h>
10#include <CommonCrypto/CommonCryptor.h>
11#include "common.h"
12#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
13
14#define LOOPS_DEF		1000
15#define BUFSIZE_DEF		10240
16#define MAX_KEY_SIZE	kCCKeySizeMaxRC4		/* bytes */
17
18
19/*
20 * Enumerate algs our own way to allow iteration.
21 */
22typedef enum {
23	ALG_AES_128,
24	ALG_AES_192,
25	ALG_AES_256,
26	ALG_DES,
27	ALG_3DES,
28	ALG_CAST,
29	ALG_RC4
30} SymAlg;
31#define ALG_FIRST			ALG_AES_128
32#define ALG_LAST			ALG_RC4
33
34static void usage(char **argv)
35{
36	printf("usage: %s [options]\n", argv[0]);
37	printf("Options:\n");
38	printf("  -a alg     -- alg : d=DES; 3=3DES; a=AES128; n=AES192; A=AES256;\n");
39	printf("                      c=CAST; 4=RC4; default=all\n");
40	printf("  -l loops   -- loops; default %u\n", LOOPS_DEF);
41	printf("  -b bufsize -- buffer size; default %u\n", BUFSIZE_DEF);
42	printf("  -e         -- ECB mode; default is CBC\n");
43
44	exit(1);
45}
46
47static void printCCError(const char *str, OSStatus ortn)
48{
49	printf("***%s returned %ld\n", str, (long)ortn);
50}
51
52int main(int argc, char **argv)
53{
54	unsigned loops = LOOPS_DEF;
55	unsigned bufSize = BUFSIZE_DEF;
56	unsigned algFirst = ALG_FIRST;
57	unsigned algLast = ALG_LAST;
58	bool ecbMode = false;
59	extern char *optarg;
60	int arg;
61	while ((arg = getopt(argc, argv, "a:l:b:eh")) != -1) {
62		switch (arg) {
63			case 'a':
64				switch(optarg[0]) {
65					case 'a':
66						algFirst = algLast = ALG_AES_128;
67						break;
68					case 'n':
69						algFirst = algLast = ALG_AES_192;
70						break;
71					case 'A':
72						algFirst = algLast = ALG_AES_256;
73						break;
74					case 'd':
75						algFirst = algLast = ALG_DES;
76						break;
77					case '3':
78						algFirst = algLast = ALG_3DES;
79						break;
80					case 'c':
81						algFirst = algLast = ALG_CAST;
82					case '4':
83						algFirst = algLast = ALG_RC4;
84				}
85				break;
86			case 'l':
87				loops = atoi(optarg);
88				break;
89			case 'b':
90				bufSize = atoi(optarg);
91				break;
92			case 'e':
93				ecbMode = true;
94				break;
95			case 'h':
96				usage(argv);
97		}
98	}
99	if(optind != argc) {
100		usage(argv);
101	}
102
103	/*
104	 * encrypt and decrypt on workBuf
105	 * save original ptext in saveBuf, compare at end as sanity check
106	 *   for ECB only
107	 */
108	unsigned char *workBuf = (unsigned char *)malloc(bufSize);
109	unsigned char *saveBuf = (unsigned char *)malloc(bufSize);
110	if((workBuf == NULL) || (saveBuf == NULL)) {
111		printf("***malloc failure\n");
112		exit(1);
113	}
114	appGetRandomBytes(workBuf, bufSize);
115	memmove(saveBuf, workBuf, bufSize);
116
117	uint8_t keyBytes[MAX_KEY_SIZE];
118	size_t keyLength;
119
120	appGetRandomBytes(keyBytes, MAX_KEY_SIZE);
121
122	CCCryptorRef cryptor;
123	CCAlgorithm alg;
124	CCOptions options = 0;
125	OSStatus ortn;
126
127	if(ecbMode) {
128		options |= kCCOptionECBMode;
129	}
130
131	unsigned currAlg;
132	for(currAlg=algFirst; currAlg<=algLast; currAlg++) {
133		const char *algStr = NULL;
134
135		switch(currAlg) {
136			case ALG_DES:
137				keyLength = kCCKeySizeDES;
138				alg = kCCAlgorithmDES;
139				algStr = "DES ";
140				break;
141			case ALG_3DES:
142				keyLength = kCCKeySize3DES;
143				alg = kCCAlgorithm3DES;
144				algStr = "3DES";
145				break;
146			case ALG_AES_128:
147				keyLength = kCCKeySizeAES128;
148				alg = kCCAlgorithmAES128;
149				algStr = "AES128";
150				break;
151			case ALG_AES_192:
152				keyLength = kCCKeySizeAES192;
153				alg = kCCAlgorithmAES128;
154				algStr = "AES192";
155				break;
156			case ALG_AES_256:
157				keyLength = kCCKeySizeAES256;
158				alg = kCCAlgorithmAES128;
159				algStr = "AES256";
160				break;
161			case ALG_CAST:
162				keyLength = kCCKeySizeMaxCAST;
163				alg = kCCAlgorithmCAST;
164				algStr = "CAST";
165				break;
166			case ALG_RC4:
167				keyLength = kCCKeySizeMaxRC4;
168				alg = kCCAlgorithmRC4;
169				algStr = "RC4";
170				break;
171		}
172
173		printf("Algorithm: %s  keySize: %u  mode: %s  loops: %u  bufSize: %u\n",
174			algStr, (unsigned)keyLength, ecbMode ? "ECB" : "CBC",
175			(unsigned)loops, (unsigned)bufSize);
176
177		CFAbsoluteTime start, end;
178		unsigned loop;
179		size_t thisMoved;
180
181		/* encrypt: GO */
182		start = CFAbsoluteTimeGetCurrent();
183
184		ortn = CCCryptorCreate(kCCEncrypt, alg, options,
185			keyBytes, keyLength, NULL, &cryptor);
186		if(ortn) {
187			printCCError("CCCryptorCreate", ortn);
188			exit(1);
189		}
190
191		for(loop=0; loop<loops; loop++) {
192			ortn = CCCryptorUpdate(cryptor, workBuf, bufSize,
193				workBuf, bufSize, &thisMoved);
194			if(ortn) {
195				printCCError("CCCryptorUpdate", ortn);
196				exit(1);
197			}
198		}
199		/* no padding, CCCryptFinal not needed */
200		end = CFAbsoluteTimeGetCurrent();
201
202		printf("   encrypt %u * %u bytes took %gs: %g KBytes/s\n",
203			(unsigned)loops, (unsigned)bufSize,
204			end - start,
205			(loops * bufSize) / (end - start) / 1024.0);
206
207		/* dncrypt: GO */
208		start = CFAbsoluteTimeGetCurrent();
209
210		ortn = CCCryptorCreate(kCCDecrypt, alg, options,
211			keyBytes, keyLength, NULL, &cryptor);
212		if(ortn) {
213			printCCError("CCCryptorCreate", ortn);
214			exit(1);
215		}
216
217		for(loop=0; loop<loops; loop++) {
218			ortn = CCCryptorUpdate(cryptor, workBuf, bufSize,
219				workBuf, bufSize, &thisMoved);
220			if(ortn) {
221				printCCError("CCCryptorUpdate", ortn);
222				exit(1);
223			}
224		}
225		/* no padding, CCCryptFinal not needed */
226		end = CFAbsoluteTimeGetCurrent();
227
228		printf("   decrypt %u * %u bytes took %gs: %g KBytes/s\n",
229			(unsigned)loops, (unsigned)bufSize,
230			end - start,
231			(loops * bufSize) / (end - start) / 1024.0);
232
233		if(ecbMode) {
234			if(memcmp(workBuf, saveBuf, bufSize)) {
235				printf("***plaintext miscompare!\n");
236			}
237		}
238	}
239	return 0;
240}
241