1 /* Copyright (c) 1998,2003-2006,2008 Apple Inc.
3 * symTest.c - test CSP symmetric encrypt/decrypt.
7 * 4 May 2000 Doug Mitchell
9 * 20 May 1998 Doug Mitchell at Apple
10 * Ported to CDSA1.2, new Apple CSP
11 * 15 Aug 1997 Doug Mitchell at Apple
12 * Ported from CryptKit ObjC version
13 * 26 Aug 1996 Doug Mitchell at NeXT
20 #include <Security/cssm.h>
21 #include <Security/cssmapple.h>
24 #include "cspdlTesting.h"
30 #define MIN_PTEXT_SIZE 8
31 #define MAX_PTEXT_SIZE 0x10000
34 * Enumerate algs our own way to allow iteration.
46 ALG_NULL
/* normally not used */
48 #define ALG_FIRST ALG_ASC
49 #define ALG_LAST ALG_CAST
52 #define PWD_LENGTH_MAX 64
53 #define MAX_DATA_SIZE (100000 + 100) /* bytes */
54 #define LOOP_NOTIFY 20
58 #define logSize(s) printf s
63 static void usage(char **argv
)
65 printf("usage: %s [options]\n", argv
[0]);
66 printf(" Options:\n");
67 printf(" a=algorithm (s=ASC; d=DES; 3=3DES; 2=RC2; 4=RC4; 5=RC5; a=AES;\n");
68 printf(" b=Blowfish; c=CAST; n=Null; default=all)\n");
69 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF
);
70 printf(" n=minPtextSize (default=%d)\n", MIN_PTEXT_SIZE
);
71 printf(" x=maxPtextSize (default=%d)\n", MAX_PTEXT_SIZE
);
72 printf(" k=keySizeInBits\n");
73 printf(" r(eference keys only)\n");
74 printf(" e(xport)\n");
75 printf(" d (no DB open)\n");
76 printf(" p=pauseInterval (default=0, no pause)\n");
77 printf(" o (no padding, well-aligned plaintext)\n");
78 printf(" u (no multi-update ops)\n");
79 printf(" U (only multi-update ops)\n");
80 printf(" m (CSP mallocs out bufs)\n");
81 printf(" D (CSP/DL; default = bare CSP)\n");
82 printf(" K (key gen only)\n");
83 printf(" v(erbose)\n");
89 /* constant seed data */
90 static CSSM_DATA seedData
= {8, (uint8
*)"12345678"};
92 /* alternate between two derivation algs, with different digest sizes */
93 #define PBE_DERIVE_ALG_ODD CSSM_ALGID_PKCS5_PBKDF1_MD5
94 #define PBE_DERIVE_ALG_EVEN CSSM_ALGID_PKCS5_PBKDF1_SHA1
97 * When expectEqualText is true, encrypt/decrypt in place.
99 #define EQUAL_TEXT_IN_PLACE 1
101 static int doTest(CSSM_CSP_HANDLE cspHand
,
103 uint32 keyAlg
, // CSSM_ALGID_xxx of the key
104 uint32 encrAlg
, // encrypt/decrypt
107 uint32 effectiveKeySizeInBits
,
109 CSSM_DATA_PTR pwd
, // password- NULL means use a random key data
110 CSSM_BOOL stagedEncr
,
111 CSSM_BOOL stagedDecr
,
112 CSSM_BOOL mallocPtext
, // only meaningful if !stagedDecr
113 CSSM_BOOL mallocCtext
, // only meaningful if !stagedEncr
115 CSSM_BOOL keyGenOnly
,
116 CSSM_BOOL expectEqualText
) // ptext size must == ctext size
118 CSSM_KEY_PTR symKey
= NULL
;
119 CSSM_DATA ctext
= {0, NULL
};
120 CSSM_DATA rptext
= {0, NULL
};
123 uint32 keySizeInBits
;
124 CSSM_DATA initVector
;
127 /* generate keys with well aligned sizes; effectiveKeySize specified in encrypt
128 * only if not well aligned */
129 keySizeInBits
= (effectiveKeySizeInBits
+ 7) & ~7;
130 if(keySizeInBits
== effectiveKeySizeInBits
) {
131 effectiveKeySizeInBits
= 0;
134 if(encrAlg
== CSSM_ALGID_RC5
) {
135 /* roll the dice, pick one of three values for rounds */
136 unsigned die
= genRand(1,3);
152 symKey
= cspGenSymKey(cspHand
,
156 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
161 /* this code isn't tested */
163 initVector
.Data
= NULL
; // we're going to ignore this
164 initVector
.Length
= 0;
165 /* one of two random PBE algs */
166 if(ptext
->Data
[0] & 1) {
167 pbeAlg
= PBE_DERIVE_ALG_ODD
;
170 pbeAlg
= PBE_DERIVE_ALG_EVEN
;
172 symKey
= cspDeriveKey(cspHand
,
177 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
182 1, // iteration count
184 if(initVector
.Data
!= NULL
) {
185 CSSM_FREE(initVector
.Data
);
189 rtn
= testError(quiet
);
197 /* not all algs need this, pass it in anyway */
198 initVector
.Data
= (uint8
*)"someStrangeInitVect";
201 case CSSM_ALGID_NONE
:
202 initVector
.Length
= 16;
205 initVector
.Length
= 8;
209 crtn
= cspStagedEncrypt(cspHand
,
214 NULL
, // second key unused
215 effectiveKeySizeInBits
,
216 0, // cipherBlockSize
224 const CSSM_DATA
*ptextPtr
= ptext
;
225 if(expectEqualText
&& mallocCtext
&& CSPDL_NOPAD_ENFORCE_SIZE
) {
227 * !pad test: ensure this works when ctextlen == ptextlen by
228 * mallocing ourself right now (instead of cspEncrypt doing it
229 * after doing a CSSM_QuerySize())
231 ctext
.Data
= (uint8
*)appMalloc(ptext
->Length
, NULL
);
232 if(ctext
.Data
== NULL
) {
233 printf("memmory failure\n");
234 rtn
= testError(quiet
);
237 ctext
.Length
= ptext
->Length
;
238 #if EQUAL_TEXT_IN_PLACE
239 /* encrypt in place */
240 memmove(ctext
.Data
, ptext
->Data
, ptext
->Length
);
244 crtn
= cspEncrypt(cspHand
,
249 NULL
, // second key unused
250 effectiveKeySizeInBits
,
258 rtn
= testError(quiet
);
261 if(expectEqualText
&& (ptext
->Length
!= ctext
.Length
)) {
262 printf("***ctext/ptext length mismatch: ptextLen %lu ctextLen %lu\n",
263 ptext
->Length
, ctext
.Length
);
264 rtn
= testError(quiet
);
269 logSize(("###ctext len %lu\n", ctext
.Length
));
271 crtn
= cspStagedDecrypt(cspHand
,
276 NULL
, // second key unused
277 effectiveKeySizeInBits
,
278 0, // cipherBlockSize
286 const CSSM_DATA
*ctextPtr
= &ctext
;
287 if(expectEqualText
&& mallocPtext
&& CSPDL_NOPAD_ENFORCE_SIZE
) {
289 * !pad test: ensure this works when ctextlen == ptextlen by
290 * mallocing ourself right now (instead of cspDecrypt doing it
291 * after doing a CSSM_QuerySize())
293 rptext
.Data
= (uint8
*)appMalloc(ctext
.Length
, NULL
);
294 if(rptext
.Data
== NULL
) {
295 printf("memmory failure\n");
296 rtn
= testError(quiet
);
299 rptext
.Length
= ctext
.Length
;
300 #if EQUAL_TEXT_IN_PLACE
301 /* decrypt in place */
302 memmove(rptext
.Data
, ctext
.Data
, ctext
.Length
);
306 crtn
= cspDecrypt(cspHand
,
311 NULL
, // second key unused
312 effectiveKeySizeInBits
,
320 rtn
= testError(quiet
);
323 logSize(("###rptext len %lu\n", rptext
.Length
));
324 /* compare ptext, rptext */
325 if(ptext
->Length
!= rptext
.Length
) {
326 printf("Ptext length mismatch: expect %lu, got %lu\n", ptext
->Length
, rptext
.Length
);
327 rtn
= testError(quiet
);
332 if(memcmp(ptext
->Data
, rptext
.Data
, ptext
->Length
)) {
333 printf("***data miscompare\n");
334 rtn
= testError(quiet
);
337 /* free key if we have it*/
339 if(cspFreeKey(cspHand
, symKey
)) {
340 printf("Error freeing privKey\n");
345 /* free rptext, ctext */
346 appFreeCssmData(&rptext
, CSSM_FALSE
);
347 appFreeCssmData(&ctext
, CSSM_FALSE
);
351 int main(int argc
, char **argv
)
357 CSSM_CSP_HANDLE cspHand
;
358 CSSM_BOOL stagedEncr
;
359 CSSM_BOOL stagedDecr
;
360 CSSM_BOOL mallocCtext
;
361 CSSM_BOOL mallocPtext
;
364 uint32 keyAlg
; // CSSM_ALGID_xxx of the key
365 uint32 encrAlg
; // CSSM_ALGID_xxx of the encrypt/decrypt/sign
367 int currAlg
; // ALG_xxx
370 uint32 actKeySizeInBits
;
372 uint32 blockSize
; // for noPadding case
373 CSSM_BOOL expectEqualText
;
378 CSSM_BOOL keySizeSpec
= CSSM_FALSE
; // false: use rand key size
379 SymAlg minAlg
= ALG_FIRST
;
380 SymAlg maxAlg
= ALG_LAST
;
381 unsigned loops
= LOOPS_DEF
;
382 CSSM_BOOL verbose
= CSSM_FALSE
;
383 unsigned minPtextSize
= MIN_PTEXT_SIZE
;
384 unsigned maxPtextSize
= MAX_PTEXT_SIZE
;
385 CSSM_BOOL quiet
= CSSM_FALSE
;
386 unsigned pauseInterval
= 0;
389 CSSM_BOOL noDbOpen
= CSSM_FALSE
;
390 CSSM_BOOL bareCsp
= CSSM_TRUE
;
391 CSSM_BOOL keyGenOnly
= CSSM_FALSE
;
392 CSSM_BOOL noPadding
= CSSM_FALSE
;
393 CSSM_BOOL multiEnable
= CSSM_TRUE
;
394 CSSM_BOOL multiOnly
= CSSM_FALSE
;
395 CSSM_BOOL refKeysOnly
= CSSM_FALSE
;
396 CSSM_BOOL cspMallocs
= CSSM_FALSE
;
399 argc
= ccommand(&argv
);
401 for(arg
=1; arg
<argc
; arg
++) {
410 minAlg
= maxAlg
= ALG_ASC
;
413 minAlg
= maxAlg
= ALG_DES
;
416 minAlg
= maxAlg
= ALG_3DES
;
419 minAlg
= maxAlg
= ALG_RC2
;
422 minAlg
= maxAlg
= ALG_RC4
;
425 minAlg
= maxAlg
= ALG_RC5
;
428 minAlg
= maxAlg
= ALG_AES
;
431 minAlg
= maxAlg
= ALG_BFISH
;
434 minAlg
= maxAlg
= ALG_CAST
;
437 minAlg
= maxAlg
= ALG_NULL
;
444 loops
= atoi(&argp
[2]);
447 minPtextSize
= atoi(&argp
[2]);
450 maxPtextSize
= atoi(&argp
[2]);
453 refKeysOnly
= CSSM_TRUE
;
456 actKeySizeInBits
= atoi(&argp
[2]);
457 keySizeSpec
= CSSM_TRUE
;
463 bareCsp
= CSSM_FALSE
;
464 #if CSPDL_ALL_KEYS_ARE_REF
465 refKeysOnly
= CSSM_TRUE
;
472 pauseInterval
= atoi(&argp
[2]);;
475 noPadding
= CSSM_TRUE
;
478 noDbOpen
= CSSM_TRUE
;
481 keyGenOnly
= CSSM_TRUE
;
484 multiEnable
= CSSM_FALSE
;
487 multiOnly
= CSSM_TRUE
;
490 cspMallocs
= CSSM_TRUE
;
497 if(multiOnly
&& !multiEnable
) {
498 printf("***can't specify multi disable and multi only\n");
501 if(minPtextSize
> maxPtextSize
) {
502 printf("***minPtextSize must be <= maxPtextSize\n");
505 pwd
.Data
= (uint8
*)CSSM_MALLOC(PWD_LENGTH_MAX
);
506 ptext
.Data
= (uint8
*)CSSM_MALLOC(maxPtextSize
);
507 if(ptext
.Data
== NULL
) {
508 printf("Insufficient heap space\n");
511 /* ptext length set in test loop */
512 printf("Starting symTest; args: ");
513 for(i
=1; i
<argc
; i
++) {
514 printf("%s ", argv
[i
]);
517 cspHand
= cspDlDbStartup(bareCsp
, NULL
);
523 printf("Top of test; hit CR to proceed: ");
526 for(currAlg
=minAlg
; currAlg
<=maxAlg
; currAlg
++) {
527 /* some default values... */
528 mode
= CSSM_ALGMODE_NONE
;
529 padding
= CSSM_PADDING_NONE
;
530 blockSize
= 0; // i.e., don't align
531 expectEqualText
= CSSM_FALSE
;
534 encrAlg
= keyAlg
= CSSM_ALGID_ASC
;
538 encrAlg
= keyAlg
= CSSM_ALGID_DES
;
541 mode
= CSSM_ALGMODE_CBC_IV8
;
543 expectEqualText
= CSSM_TRUE
;
546 mode
= CSSM_ALGMODE_CBCPadIV8
;
547 padding
= CSSM_PADDING_PKCS1
;
551 /* currently the only one with different key and encr algs */
552 /* Though actually these two consts are equivalent...for now... */
553 keyAlg
= CSSM_ALGID_3DES_3KEY
;
554 encrAlg
= CSSM_ALGID_3DES_3KEY_EDE
;
557 mode
= CSSM_ALGMODE_CBC_IV8
;
559 expectEqualText
= CSSM_TRUE
;
562 mode
= CSSM_ALGMODE_CBCPadIV8
;
563 padding
= CSSM_PADDING_PKCS1
;
567 encrAlg
= keyAlg
= CSSM_ALGID_RC2
;
570 mode
= CSSM_ALGMODE_CBC_IV8
;
572 expectEqualText
= CSSM_TRUE
;
575 mode
= CSSM_ALGMODE_CBCPadIV8
;
576 padding
= CSSM_PADDING_PKCS1
; // what does padding do here?
580 encrAlg
= keyAlg
= CSSM_ALGID_RC4
;
582 mode
= CSSM_ALGMODE_NONE
;
583 expectEqualText
= CSSM_TRUE
; // always for RC4
586 encrAlg
= keyAlg
= CSSM_ALGID_RC5
;
589 mode
= CSSM_ALGMODE_CBC_IV8
;
591 expectEqualText
= CSSM_TRUE
;
594 mode
= CSSM_ALGMODE_CBCPadIV8
;
595 padding
= CSSM_PADDING_PKCS1
; // eh?
599 encrAlg
= keyAlg
= CSSM_ALGID_AES
;
602 mode
= CSSM_ALGMODE_CBC_IV8
;
604 expectEqualText
= CSSM_TRUE
;
607 mode
= CSSM_ALGMODE_CBCPadIV8
;
608 padding
= CSSM_PADDING_PKCS5
;
612 encrAlg
= keyAlg
= CSSM_ALGID_BLOWFISH
;
615 mode
= CSSM_ALGMODE_CBC_IV8
;
617 expectEqualText
= CSSM_TRUE
;
620 mode
= CSSM_ALGMODE_CBCPadIV8
;
621 padding
= CSSM_PADDING_PKCS5
;
625 encrAlg
= keyAlg
= CSSM_ALGID_CAST
;
628 mode
= CSSM_ALGMODE_CBC_IV8
;
630 expectEqualText
= CSSM_TRUE
;
633 mode
= CSSM_ALGMODE_CBCPadIV8
;
634 padding
= CSSM_PADDING_PKCS5
;
638 encrAlg
= keyAlg
= CSSM_ALGID_NONE
;
641 mode
= CSSM_ALGMODE_CBC_IV8
;
643 expectEqualText
= CSSM_TRUE
;
646 mode
= CSSM_ALGMODE_CBCPadIV8
;
647 padding
= CSSM_PADDING_PKCS5
;
651 if(!quiet
|| verbose
) {
652 printf("Testing alg %s\n", algStr
);
654 for(loop
=1; ; loop
++) {
655 simpleGenData(&ptext
, minPtextSize
, maxPtextSize
);
657 /* i.e., no padding --> align ptext */
658 ptext
.Length
= ((ptext
.Length
+ blockSize
- 1) / blockSize
) * blockSize
;
661 actKeySizeInBits
= randKeySizeBits(keyAlg
, OT_Encrypt
);
663 /* else constant, spec'd by user, may be 0 (default per alg) */
664 /* mix up some random and derived keys, as well as staging and "who does
666 pPwd
= (loop
& 1) ? &pwd
: NULL
;
669 stagedEncr
= stagedDecr
= CSSM_TRUE
;
672 stagedEncr
= (loop
& 2) ? CSSM_TRUE
: CSSM_FALSE
;
673 stagedDecr
= (loop
& 4) ? CSSM_TRUE
: CSSM_FALSE
;
677 stagedEncr
= CSSM_FALSE
;
678 stagedDecr
= CSSM_FALSE
;
680 if(!stagedEncr
&& !cspMallocs
) {
681 mallocCtext
= (ptext
.Data
[0] & 1) ? CSSM_TRUE
: CSSM_FALSE
;
684 mallocCtext
= CSSM_FALSE
;
686 if(!stagedDecr
&& !cspMallocs
) {
687 mallocPtext
= (ptext
.Data
[0] & 2) ? CSSM_TRUE
: CSSM_FALSE
;
690 mallocPtext
= CSSM_FALSE
;
696 refKey
= (ptext
.Data
[0] & 4) ? CSSM_TRUE
: CSSM_FALSE
;
702 if(verbose
|| ((loop
% LOOP_NOTIFY
) == 0)) {
703 printf("..loop %d text size %lu keySizeBits %u\n",
704 loop
, (unsigned long)ptext
.Length
, (unsigned)actKeySizeInBits
);
706 printf(" refKey %d derive %d stagedEncr %d stagedDecr %d mallocCtext %d "
708 (int)refKey
, (pPwd
== NULL
) ? 0 : 1, (int)stagedEncr
, (int)stagedDecr
,
709 (int)mallocCtext
, (int)mallocPtext
);
715 /* PBE - cook up random password */
716 simpleGenData(pPwd
, APPLE_PBE_MIN_PASSWORD
, PWD_LENGTH_MAX
);
739 if(pauseInterval
&& ((loop
% pauseInterval
) == 0)) {
742 printf("Hit CR to proceed, q to abort: ");
748 if(loops
&& (loop
== loops
)) {
759 cspShutdown(cspHand
, bareCsp
);
762 printf("ModuleDetach/Unload complete; hit CR to exit: ");
765 if((rtn
== 0) && !quiet
) {
766 printf("%s test complete\n", argv
[0]);
769 CSSM_FREE(ptext
.Data
);