2 * symCompat.c - test compatibilty of two different implementations of a
3 * given symmetric encryption algorithm - one in the standard AppleCSP,
4 * the other in either libcrypto (for Blowfish and CAST), BSAFE, or the
5 * NIST reference port for AES.
7 * Written by Doug Mitchell.
13 #include <Security/cssm.h>
14 #include <Security/cssmapple.h>
17 #include "bsafeUtils.h"
18 #include "ssleayUtils.h"
19 #include "rijndaelApi.h"
21 #include "cspdlTesting.h"
28 #define MIN_DATA_SIZE 8
29 #define MAX_DATA_SIZE 10000 /* bytes */
30 #define MAX_KEY_SIZE MAX_KEY_SIZE_RC245_BYTES /* bytes */
31 #define LOOP_NOTIFY 20
33 #define RAW_MODE CSSM_ALGMODE_ECB /* doesn't work for BSAFE */
34 #define RAW_MODE_BSAFE CSSM_ALGMODE_CBC_IV8
36 #define COOKED_MODE CSSM_ALGMODE_CBCPadIV8
37 #define RAW_MODE_STREAM CSSM_ALGMODE_NONE
39 #define RAW_MODE_STR "ECB"
40 #define RAW_MODE_BSAFE_STR "CBC/noPad"
41 #define COOKED_MODE_STR "CBC/Pad"
42 #define RAW_MODE_STREAM_STR "None"
45 * Enumerate algs our own way to allow iteration.
48 // ALG_ASC = 1, // not tested - no reference available
55 ALG_AES192
, /* 192 bit block */
56 ALG_AES256
, /* 256 bit block */
60 #define ALG_FIRST ALG_DES
61 #define ALG_LAST ALG_CAST
63 static void usage(char **argv
)
65 printf("usage: %s [options]\n", argv
[0]);
66 printf(" Options:\n");
67 printf(" a=algorithm (d=DES; 3=3DES3; 2=RC2; 4=RC4; 5=RC5; a=AES; A=AES192; \n");
68 printf(" 6=AES256; b=Blowfish; c=CAST; default=all)\n");
69 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF
);
70 printf(" k=keySizeInBits\n");
71 printf(" e(ncrypt only)\n");
72 printf(" m=maxPtextSize (default=%d)\n", MAX_DATA_SIZE
);
73 printf(" n=minPtextSize (default=%d)\n", MIN_DATA_SIZE
);
74 printf(" p=pauseInterval (default=0, no pause)\n");
75 printf(" s (all ops single-shot, not staged)\n");
76 printf(" o (raw - no padding or CBC if possible)\n");
77 printf(" O (cooked - padding and CBC if possible)\n");
78 printf(" z (keys and plaintext all zeroes)\n");
79 printf(" D (CSP/DL; default = bare CSP)\n");
80 printf(" y (use ssleay EVP; AES128 only)\n");
81 printf(" v(erbose)\n");
88 * encrypt/decrypt using reference BSAFE.
90 static CSSM_RETURN
encryptDecryptBSAFE(
92 CSSM_ALGORITHMS encrAlg
,
93 CSSM_ENCRYPT_MODE encrMode
,
94 const CSSM_DATA
*iv
, //Êoptional per mode
96 uint32 effectiveKeyBits
, // optional per key alg
97 uint32 rounds
, // ditto
98 const CSSM_DATA
*key
, // raw key bytes
99 const CSSM_DATA
*inText
,
100 CSSM_DATA_PTR outText
) // mallocd and returned
105 crtn
= buGenSymKey(keySizeInBits
, key
, &buKey
);
109 crtn
= buEncryptDecrypt(buKey
,
110 forEncrypt
, // forEncrypt
123 * encrypt/decrypt using reference ssleay.
125 static CSSM_RETURN
encryptDecryptEAY(
126 CSSM_BOOL forEncrypt
,
127 CSSM_ALGORITHMS encrAlg
,
128 CSSM_ENCRYPT_MODE encrMode
,
129 const CSSM_DATA
*iv
, //Êoptional per mode
130 uint32 keySizeInBits
,
131 const CSSM_DATA
*key
, // raw key bytes, Length ignored
132 const CSSM_DATA
*inText
,
133 CSSM_DATA_PTR outText
) // mallocd and returned
137 CSSM_DATA ckey
= *key
;
138 ckey
.Length
= keySizeInBits
/ 8;
140 crtn
= eayGenSymKey(encrAlg
, forEncrypt
, &ckey
, &eayKey
);
144 crtn
= eayEncryptDecrypt(eayKey
,
156 * encrypt/decrypt using reference AES.
158 static CSSM_RETURN
encryptDecryptAES(
159 CSSM_BOOL forEncrypt
,
160 CSSM_ALGORITHMS encrAlg
,
161 CSSM_ENCRYPT_MODE encrMode
,
162 const CSSM_DATA
*iv
, //Êoptional per mode
163 uint32 keySizeInBits
,
164 uint32 effectiveKeyBits
, // optional per key alg
165 uint32 cipherBlockSize
,
166 uint32 rounds
, // ditto
167 const CSSM_DATA
*key
, // raw key bytes
168 const CSSM_DATA
*inText
,
169 CSSM_DATA_PTR outText
) // mallocd and returned
172 cipherInstance aesCipher
;
177 if(cipherBlockSize
== 0) {
178 cipherBlockSize
= MIN_AES_BLOCK_BITS
;
181 case CSSM_ALGMODE_CBC_IV8
:
185 case CSSM_ALGMODE_ECB
:
190 printf("***AES reference implementation doesn't do padding (yet)\n");
193 /* fixme - adjust for padding if necessary */
194 outText
->Data
= (uint8
*)CSSM_MALLOC(inText
->Length
);
195 outText
->Length
= inText
->Length
;
196 artn
= _makeKey(&aesKey
,
197 forEncrypt
? DIR_ENCRYPT
: DIR_DECRYPT
,
202 printf("***AES makeKey returned %d\n", artn
);
203 return CSSM_ERRCODE_INTERNAL_ERROR
;
205 artn
= _cipherInit(&aesCipher
,
210 printf("***AES cipherInit returned %d\n", artn
);
211 return CSSM_ERRCODE_INTERNAL_ERROR
;
214 artn
= _blockEncrypt(&aesCipher
,
216 (BYTE
*)inText
->Data
,
218 (BYTE
*)outText
->Data
);
221 artn
= _blockDecrypt(&aesCipher
,
223 (BYTE
*)inText
->Data
,
225 (BYTE
*)outText
->Data
);
228 printf("***AES encrypt/decrypt returned %d\n", artn
);
229 return CSSM_ERRCODE_INTERNAL_ERROR
;
235 * Encrypt/decrypt, one-shot, using one of the various reference implementations.
237 static CSSM_RETURN
encryptDecryptRef(
238 CSSM_BOOL forEncrypt
,
239 CSSM_ALGORITHMS encrAlg
,
240 CSSM_ENCRYPT_MODE encrMode
,
241 const CSSM_DATA
*iv
, // optional per mode
242 uint32 keySizeInBits
,
243 uint32 effectiveKeyBits
, // optional per key alg
244 uint32 cipherBlockSize
,
245 uint32 rounds
, // ditto
246 CSSM_BOOL useEvp
, // AES only
247 const CSSM_DATA
*key
, // raw key bytes
248 const CSSM_DATA
*inText
,
249 CSSM_DATA_PTR outText
) // mallocd and returned
253 if(useEvp
&& (cipherBlockSize
== 128)) {
254 return (CSSM_RETURN
)evpEncryptDecrypt(encrAlg
, forEncrypt
,
255 key
, keySizeInBits
, encrMode
, iv
, inText
, outText
);
258 return encryptDecryptAES(
271 case CSSM_ALGID_BLOWFISH
:
272 case CSSM_ALGID_CAST
:
273 return encryptDecryptEAY(
283 if(useEvp
&& (encrAlg
== CSSM_ALGID_DES
)) {
284 return (CSSM_RETURN
)evpEncryptDecrypt(encrAlg
, forEncrypt
,
285 key
, keySizeInBits
, encrMode
, iv
, inText
, outText
);
288 return encryptDecryptBSAFE(
304 * encrypt/decrypt using CSSM.
306 static CSSM_RETURN
encryptDecryptCSSM(
307 CSSM_CSP_HANDLE cspHand
,
308 CSSM_BOOL forEncrypt
,
309 CSSM_ALGORITHMS keyAlg
,
310 CSSM_ALGORITHMS encrAlg
,
311 CSSM_ENCRYPT_MODE encrMode
,
312 CSSM_PADDING padding
, // CSSM_PADDING_PKCS1, etc.
314 CSSM_BOOL multiUpdates
, // false:single update, true:multi updates
315 const CSSM_DATA
*iv
, //Êoptional per mode
316 uint32 keySizeInBits
,
317 uint32 effectiveKeyBits
, // optional per key alg
318 uint32 cipherBlockSize
,
319 uint32 rounds
, // ditto
320 const CSSM_DATA
*key
, // raw key bytes
321 const CSSM_DATA
*inText
,
322 CSSM_BOOL genRaw
, // first generate raw key (CSPDL)
323 CSSM_DATA_PTR outText
) // mallocd and returned
325 CSSM_KEY_PTR symKey
; // mallocd by cspGenSymKey or a ptr
327 CSSM_KEY refKey
; // in case of genRaw
328 CSSM_BOOL refKeyGenerated
= CSSM_FALSE
;
329 unsigned keyBytes
= (keySizeInBits
+ 7) / 8;
333 crtn
= cspGenSymKeyWithBits(cspHand
,
335 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
343 refKeyGenerated
= CSSM_TRUE
;
346 /* cook up a raw symmetric key */
347 symKey
= cspGenSymKey(cspHand
,
351 CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
,
353 CSSM_FALSE
); // ref key
355 return CSSM_ERRCODE_INTERNAL_ERROR
;
357 if(symKey
->KeyData
.Length
!= keyBytes
) {
358 printf("***Generated key size error (exp %d, got %lu)\n",
359 keyBytes
, symKey
->KeyData
.Length
);
360 return CSSM_ERRCODE_INTERNAL_ERROR
;
362 memmove(symKey
->KeyData
.Data
, key
->Data
, keyBytes
);
364 outText
->Data
= NULL
;
367 if(keySizeInBits
== effectiveKeyBits
) {
368 effectiveKeyBits
= 0;
373 crtn
= cspStagedEncrypt(cspHand
,
378 NULL
, // no second key
388 crtn
= cspStagedDecrypt(cspHand
,
393 NULL
, // no second key
402 cspFreeKey(cspHand
, symKey
);
403 if(!refKeyGenerated
) {
404 /* key itself mallocd by cspGenSymKey */
412 static int doTest(CSSM_CSP_HANDLE cspHand
,
413 const CSSM_DATA
*ptext
,
414 const CSSM_DATA
*keyData
,
416 uint32 keyAlg
, // CSSM_ALGID_xxx of the key
417 uint32 encrAlg
, // encrypt/decrypt
420 uint32 keySizeInBits
,
421 uint32 efectiveKeySizeInBits
,
422 uint32 cipherBlockSize
,
423 CSSM_BOOL useEvp
, // AES only
424 CSSM_BOOL stagedEncr
,
425 CSSM_BOOL stagedDecr
,
427 CSSM_BOOL encryptOnly
,
428 CSSM_BOOL genRaw
) // first generate raw key (CSPDL)
430 CSSM_DATA ctextRef
= {0, NULL
}; // ciphertext, reference
431 CSSM_DATA ctextTest
= {0, NULL
}; // ciphertext, test
432 CSSM_DATA rptext
= {0, NULL
}; // recovered plaintext
437 if(encrAlg
== CSSM_ALGID_RC5
) {
438 /* roll the dice, pick one of three values for rounds */
439 unsigned die
= genRand(1,3);
454 * encrypt with each method;
455 * verify ciphertexts compare;
456 * decrypt with test code;
457 * verify recovered plaintext and incoming plaintext compare;
459 crtn
= encryptDecryptRef(CSSM_TRUE
,
464 efectiveKeySizeInBits
,
472 return testError(quiet
);
474 crtn
= encryptDecryptCSSM(cspHand
,
483 efectiveKeySizeInBits
,
491 return testError(quiet
);
494 /* ensure both methods resulted in same ciphertext */
495 if(ctextRef
.Length
!= ctextTest
.Length
) {
496 printf("Ctext length mismatch (1)\n");
497 rtn
= testError(quiet
);
502 if(memcmp(ctextRef
.Data
, ctextTest
.Data
, ctextTest
.Length
)) {
503 printf("Ctext miscompare\n");
504 rtn
= testError(quiet
);
515 /* decrypt with the test method */
516 crtn
= encryptDecryptCSSM(cspHand
,
525 efectiveKeySizeInBits
,
533 return testError(quiet
);
535 if(rptext
.Length
!= ptext
->Length
) {
536 printf("ptext length mismatch (1)\n");
537 rtn
= testError(quiet
);
542 if(memcmp(rptext
.Data
, ptext
->Data
, ptext
->Length
)) {
543 printf("ptext miscompare\n");
544 rtn
= testError(quiet
);
550 if(ctextTest
.Length
) {
551 CSSM_FREE(ctextTest
.Data
);
553 if(ctextRef
.Length
) {
554 CSSM_FREE(ctextRef
.Data
);
557 CSSM_FREE(rptext
.Data
);
563 int main(int argc
, char **argv
)
569 CSSM_CSP_HANDLE cspHand
;
570 CSSM_BOOL stagedEncr
;
571 CSSM_BOOL stagedDecr
;
573 uint32 keyAlg
; // CSSM_ALGID_xxx of the key
574 uint32 encrAlg
; // CSSM_ALGID_xxx of encr/decr
576 unsigned currAlg
; // ALG_xxx
577 uint32 actKeySizeInBits
;
578 uint32 effectKeySizeInBits
;
581 CSSM_DATA initVector
;
582 CSSM_BOOL genRaw
= CSSM_FALSE
; // first generate raw key (CSPDL)
586 const char *rawModeStr
;
587 const char *cookedModeStr
;
593 CSSM_BOOL keySizeSpec
= CSSM_FALSE
; // false: use rand key size
594 unsigned minAlg
= ALG_FIRST
;
595 unsigned maxAlg
= ALG_LAST
;
596 unsigned loops
= LOOPS_DEF
;
597 CSSM_BOOL verbose
= CSSM_FALSE
;
598 CSSM_BOOL quiet
= CSSM_FALSE
;
599 unsigned pauseInterval
= 0;
601 CSSM_BOOL bareCsp
= CSSM_TRUE
;
602 CSSM_BOOL encryptOnly
= CSSM_FALSE
;
603 unsigned maxPtextSize
= MAX_DATA_SIZE
;
604 unsigned minPtextSize
= MIN_DATA_SIZE
;
605 CSSM_BOOL oneShotOnly
= CSSM_FALSE
;
606 CSSM_BOOL allZeroes
= CSSM_FALSE
;
607 CSSM_BOOL rawCookedSpecd
= CSSM_FALSE
; // when true, use allRaw only
608 CSSM_BOOL allRaw
= CSSM_FALSE
;
609 CSSM_BOOL useEvp
= CSSM_FALSE
;
611 for(arg
=1; arg
<argc
; arg
++) {
620 minAlg
= maxAlg
= ALG_DES
;
623 minAlg
= maxAlg
= ALG_3DES
;
626 minAlg
= maxAlg
= ALG_RC2
;
629 minAlg
= maxAlg
= ALG_RC4
;
632 minAlg
= maxAlg
= ALG_RC5
;
635 minAlg
= maxAlg
= ALG_AES
;
638 minAlg
= maxAlg
= ALG_AES192
;
641 minAlg
= maxAlg
= ALG_AES256
;
644 minAlg
= maxAlg
= ALG_BFISH
;
647 minAlg
= maxAlg
= ALG_CAST
;
654 loops
= atoi(&argp
[2]);
657 actKeySizeInBits
= effectKeySizeInBits
= atoi(&argp
[2]);
658 keySizeSpec
= CSSM_TRUE
;
664 bareCsp
= CSSM_FALSE
;
665 #if CSPDL_ALL_KEYS_ARE_REF
670 encryptOnly
= CSSM_TRUE
;
673 maxPtextSize
= atoi(&argp
[2]);
676 minPtextSize
= atoi(&argp
[2]);
679 allZeroes
= CSSM_TRUE
;
682 oneShotOnly
= CSSM_TRUE
;
688 pauseInterval
= atoi(&argp
[2]);;
691 rawCookedSpecd
= CSSM_TRUE
;
695 rawCookedSpecd
= CSSM_TRUE
;
696 allRaw
= CSSM_FALSE
; // i.e., use cooked
706 ptext
.Data
= (uint8
*)CSSM_MALLOC(maxPtextSize
);
707 if(ptext
.Data
== NULL
) {
708 printf("Insufficient heap space\n");
711 /* ptext length set in test loop */
713 keyData
.Data
= (uint8
*)CSSM_MALLOC(MAX_KEY_SIZE
);
714 if(keyData
.Data
== NULL
) {
715 printf("Insufficient heap space\n");
718 keyData
.Length
= MAX_KEY_SIZE
;
720 initVector
.Data
= (uint8
*)"someStrangeInitVect";
722 printf("Starting symCompat; args: ");
723 for(i
=1; i
<argc
; i
++) {
724 printf("%s ", argv
[i
]);
727 cspHand
= cspDlDbStartup(bareCsp
, NULL
);
733 printf("Top of test; hit CR to proceed: ");
736 for(currAlg
=minAlg
; currAlg
<=maxAlg
; currAlg
++) {
737 /* some default values... */
738 padding
= CSSM_PADDING_PKCS1
;
741 encrAlg
= keyAlg
= CSSM_ALGID_DES
;
745 /* this one requires padding */
747 cookedMode
= COOKED_MODE
;
748 rawModeStr
= RAW_MODE_STR
;
749 cookedModeStr
= COOKED_MODE_STR
;
750 padding
= CSSM_PADDING_PKCS5
;
753 rawMode
= RAW_MODE_BSAFE
;
754 cookedMode
= CSSM_ALGMODE_CBCPadIV8
;
755 rawModeStr
= RAW_MODE_BSAFE_STR
;
756 cookedModeStr
= COOKED_MODE_STR
;
760 /* currently the only one with different key and encr algs */
761 keyAlg
= CSSM_ALGID_3DES_3KEY
;
762 encrAlg
= CSSM_ALGID_3DES_3KEY_EDE
;
765 rawMode
= RAW_MODE_BSAFE
;
766 cookedMode
= CSSM_ALGMODE_CBCPadIV8
;
767 rawModeStr
= RAW_MODE_BSAFE_STR
;
768 cookedModeStr
= COOKED_MODE_STR
;
771 encrAlg
= keyAlg
= CSSM_ALGID_RC2
;
774 rawMode
= RAW_MODE_BSAFE
;
775 cookedMode
= CSSM_ALGMODE_CBCPadIV8
;
776 rawModeStr
= RAW_MODE_BSAFE_STR
;
777 cookedModeStr
= COOKED_MODE_STR
;
780 encrAlg
= keyAlg
= CSSM_ALGID_RC4
;
783 rawMode
= RAW_MODE_STREAM
;
784 cookedMode
= RAW_MODE_STREAM
;
785 rawModeStr
= RAW_MODE_STREAM_STR
;
786 cookedModeStr
= RAW_MODE_STREAM_STR
;
789 encrAlg
= keyAlg
= CSSM_ALGID_RC5
;
792 rawMode
= RAW_MODE_BSAFE
;
793 cookedMode
= CSSM_ALGMODE_CBCPadIV8
;
794 rawModeStr
= RAW_MODE_BSAFE_STR
;
795 cookedModeStr
= COOKED_MODE_STR
;
798 encrAlg
= keyAlg
= CSSM_ALGID_AES
;
803 cookedMode
= COOKED_MODE
;
804 rawModeStr
= RAW_MODE_STR
;
805 cookedModeStr
= COOKED_MODE_STR
;
806 padding
= CSSM_PADDING_PKCS7
;
809 /* padding not supported in ref implementation */
811 cookedMode
= RAW_MODE_BSAFE
;
812 rawModeStr
= RAW_MODE_STR
;
813 cookedModeStr
= RAW_MODE_BSAFE_STR
;
817 encrAlg
= keyAlg
= CSSM_ALGID_AES
;
819 /* padding not supported in ref implementation */
822 cookedMode
= RAW_MODE_BSAFE
;
823 rawModeStr
= RAW_MODE_STR
;
824 cookedModeStr
= RAW_MODE_BSAFE_STR
;
827 encrAlg
= keyAlg
= CSSM_ALGID_AES
;
829 /* padding not supported in ref implementation */
832 cookedMode
= RAW_MODE_BSAFE
;
833 rawModeStr
= RAW_MODE_STR
;
834 cookedModeStr
= RAW_MODE_BSAFE_STR
;
837 encrAlg
= keyAlg
= CSSM_ALGID_BLOWFISH
;
840 /* libcrypt doesn't do padding or ECB */
841 rawMode
= RAW_MODE_BSAFE
;
842 cookedMode
= RAW_MODE_BSAFE
;
843 rawModeStr
= RAW_MODE_BSAFE_STR
;
844 cookedModeStr
= RAW_MODE_BSAFE_STR
;
847 encrAlg
= keyAlg
= CSSM_ALGID_CAST
;
850 /* libcrypt doesn't do padding or ECB */
851 rawMode
= RAW_MODE_BSAFE
;
852 cookedMode
= RAW_MODE_BSAFE
;
853 rawModeStr
= RAW_MODE_BSAFE_STR
;
854 cookedModeStr
= RAW_MODE_BSAFE_STR
;
858 /* assume for now all algs require IV */
859 initVector
.Length
= algBlockSize
? algBlockSize
: 8;
861 if(!quiet
|| verbose
) {
862 printf("Testing alg %s\n", algStr
);
864 for(loop
=1; ; loop
++) {
865 /* mix up raw/cooked */
868 CSSM_BOOL paddingEnabled
;
873 modeStr
= rawModeStr
;
877 modeStr
= cookedModeStr
;
883 modeStr
= rawModeStr
;
887 modeStr
= cookedModeStr
;
891 case CSSM_ALGMODE_CBCPadIV8
:
892 paddingEnabled
= CSSM_TRUE
;
895 /* all others - right? */
896 paddingEnabled
= CSSM_FALSE
;
899 minTextSize
= minPtextSize
; // default
900 if(!paddingEnabled
&& algBlockSize
&& (minTextSize
< algBlockSize
)) {
901 /* i.e., no padding, adjust min ptext size */
902 minTextSize
= algBlockSize
;
904 simpleGenData(&ptext
, minTextSize
, maxPtextSize
);
905 if(!paddingEnabled
&& algBlockSize
) {
907 ptext
.Length
= (ptext
.Length
/ algBlockSize
) * algBlockSize
;
912 stagedEncr
= CSSM_FALSE
;
913 stagedDecr
= CSSM_FALSE
;
916 stagedEncr
= (loop
& 2) ? CSSM_TRUE
: CSSM_FALSE
;
917 stagedDecr
= (loop
& 4) ? CSSM_TRUE
: CSSM_FALSE
;
921 memset(ptext
.Data
, 0, ptext
.Length
);
922 memset(keyData
.Data
, 0, MAX_KEY_SIZE
);
923 keyData
.Length
= MAX_KEY_SIZE
;
926 simpleGenData(&keyData
, MAX_KEY_SIZE
, MAX_KEY_SIZE
);
930 effectKeySizeInBits
= randKeySizeBits(keyAlg
, OT_Encrypt
);
932 * generate keys with well aligned sizes; effectiveKeySize
933 * differs only if not well aligned
935 actKeySizeInBits
= (effectKeySizeInBits
+ 7) & ~7;
937 /* else constant, spec'd by user, may be 0 (default per alg) */
939 if(verbose
|| ((loop
% LOOP_NOTIFY
) == 0)) {
941 printf("..loop %d text size %lu keySizeBits %u"
942 " blockSize %u stageEncr %d stageDecr %d mode %s\n",
943 loop
, (unsigned long)ptext
.Length
, (unsigned)effectKeySizeInBits
,
944 (unsigned)algBlockSize
, (int)stagedEncr
, (int)stagedDecr
,
948 printf("..loop %d text size %lu keySizeBits %u"
949 " stageEncr %d stageDecr %d mode %s\n",
950 loop
, (unsigned long)ptext
.Length
, (unsigned)effectKeySizeInBits
,
951 (int)stagedEncr
, (int)stagedDecr
, modeStr
);
965 actKeySizeInBits
, // FIXME - test effective key size
976 if(pauseInterval
&& ((loop
% pauseInterval
) == 0)) {
979 printf("Hit CR to proceed, q to abort: ");
985 if(loops
&& (loop
== loops
)) {
996 cspShutdown(cspHand
, bareCsp
);
999 printf("ModuleDetach/Unload complete; hit CR to exit: ");
1002 if((rtn
== 0) && !quiet
) {
1003 printf("%s test complete\n", argv
[0]);
1005 CSSM_FREE(ptext
.Data
);
1006 CSSM_FREE(keyData
.Data
);