+/*
+ * contextReuse.cpp
+ *
+ * Verify proper operation of symmetric CSP algorithms when CSSM_CC_HANDLE
+ * (crypto context) is reused. Tests specifically for Radar 4551700, which
+ * dealt with a problem with the Gladman AES implementation handling the
+ * same context for an encrypt followed by a decrypt; other situations
+ * are tested here (e.g. encrypt followed by another encrypt including CBC)
+ * as well as all CSP symmetric algorithms.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <Security/cssm.h>
+#include <Security/cssmapple.h>
+#include "cspwrap.h"
+#include "common.h"
+#include <string.h>
+#include "cspdlTesting.h"
+
+/*
+ * Defaults.
+ */
+#define LOOPS_DEF 200
+
+#define MIN_DATA_SIZE 8
+#define MAX_DATA_SIZE 10000 /* bytes */
+#define MAX_KEY_SIZE MAX_KEY_SIZE_RC245_BYTES /* bytes */
+#define LOOP_NOTIFY 20
+
+#define RAW_MODE CSSM_ALGMODE_ECB /* doesn't work for BSAFE */
+#define RAW_MODE_STREAM CSSM_ALGMODE_NONE
+#define COOKED_MODE CSSM_ALGMODE_CBCPadIV8
+
+#define RAW_MODE_STR "ECB"
+#define RAW_MODE_STREAM_STR "None"
+#define COOKED_MODE_STR "CBC/Pad"
+
+/*
+ * Enumerate algs our own way to allow iteration.
+ */
+typedef enum {
+ ALG_ASC = 1, // not tested - no reference available
+ ALG_DES = 1,
+ ALG_RC2,
+ ALG_RC4,
+ ALG_RC5,
+ ALG_3DES,
+ ALG_AES,
+ ALG_AES192, /* 192 bit block */
+ ALG_AES256, /* 256 bit block */
+ ALG_BFISH,
+ ALG_CAST
+} SymAlg;
+#define ALG_FIRST ALG_ASC
+#define ALG_LAST ALG_CAST
+
+static void usage(char **argv)
+{
+ printf("usage: %s [options]\n", argv[0]);
+ printf(" Options:\n");
+ printf(" a=algorithm (d=DES; 3=3DES3; 2=RC2; 4=RC4; 5=RC5; a=AES; A=AES192; \n");
+ printf(" 6=AES256; b=Blowfish; c=CAST; s=ASC; default=all)\n");
+ printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
+ printf(" k=keySizeInBits\n");
+ printf(" m=maxPtextSize (default=%d)\n", MAX_DATA_SIZE);
+ printf(" n=minPtextSize (default=%d)\n", MIN_DATA_SIZE);
+ printf(" p=pauseInterval (default=0, no pause)\n");
+ printf(" D (CSP/DL; default = bare CSP)\n");
+ printf(" v(erbose)\n");
+ printf(" q(uiet)\n");
+ printf(" h(elp)\n");
+ exit(1);
+}
+
+#define LOG_STAGED_OPS 0
+#if LOG_STAGED_OPS
+#define soprintf(s) printf s
+#else
+#define soprintf(s)
+#endif
+
+/*
+ * Multipurpose encrypt. Like cspStagedEncrypt(), but it takes a
+ * context handle and doesn't have as many options.
+ */
+static CSSM_RETURN stagedEncrypt(
+ CSSM_CSP_HANDLE cspHand,
+ CSSM_CC_HANDLE cryptHand,
+ uint32 algorithm, // CSSM_ALGID_FEED, etc.
+ uint32 cipherBlockSizeBytes,// optional
+ const CSSM_DATA *iv, // init vector, optional
+ const CSSM_DATA *ptext,
+ CSSM_DATA_PTR ctext, // mallocd by caller, must be big enough!
+ CSSM_BOOL multiUpdates) // false:single update, true:multi updates
+{
+ CSSM_RETURN crtn;
+ CSSM_SIZE bytesEncrypted; // per update
+ CSSM_SIZE bytesEncryptedTotal = 0;
+ CSSM_RETURN ocrtn = CSSM_OK; // 'our' crtn
+ unsigned toMove; // remaining
+ unsigned thisMove; // bytes to encrypt on this update
+ CSSM_DATA thisPtext; // running ptr into ptext
+ CSSM_DATA thisCtext; // running ptr into ctext
+ CSSM_BOOL restoreErr = CSSM_FALSE;
+ CSSM_RETURN savedErr = CSSM_OK;
+ CSSM_SIZE ctextLen;
+
+ if(cipherBlockSizeBytes) {
+ crtn = AddContextAttribute(cryptHand,
+ CSSM_ATTRIBUTE_BLOCK_SIZE,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ cipherBlockSizeBytes);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ }
+
+ thisPtext = *ptext;
+ thisCtext = *ctext;
+ memset(ctext->Data, 0, ctext->Length);
+ ctextLen = ctext->Length;
+
+ crtn = CSSM_EncryptDataInit(cryptHand);
+ if(crtn) {
+ printError("CSSM_EncryptDataInit", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+
+ toMove = ptext->Length;
+ while(toMove) {
+ if(multiUpdates) {
+ thisMove = genRand(1, toMove);
+ }
+ else {
+ /* just do one pass thru this loop */
+ thisMove = toMove;
+ }
+ thisPtext.Length = thisMove;
+ crtn = CSSM_EncryptDataUpdate(cryptHand,
+ &thisPtext,
+ 1,
+ &thisCtext,
+ 1,
+ &bytesEncrypted);
+ if(crtn) {
+ printError("CSSM_EncryptDataUpdate", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ soprintf(("*** EncryptDataUpdate: ptextLen 0x%x bytesEncrypted 0x%x\n",
+ (unsigned)thisMove, (unsigned)bytesEncrypted));
+
+ // NOTE: We return the proper length in ctext....
+ ctextLen -= bytesEncrypted; // bump out ptr
+ thisCtext.Length = ctextLen;
+ thisCtext.Data += bytesEncrypted;
+ bytesEncryptedTotal += bytesEncrypted;
+ thisPtext.Data += thisMove; // bump in ptr
+ toMove -= thisMove;
+ }
+ /* OK, one more */
+ crtn = CSSM_EncryptDataFinal(cryptHand, &thisCtext);
+ if(crtn) {
+ printError("CSSM_EncryptDataFinal", crtn);
+ savedErr = crtn;
+ restoreErr = CSSM_TRUE;
+ goto abort;
+ }
+ soprintf(("*** EncryptDataFinal: bytesEncrypted 0x%x\n",
+ (unsigned)thisCtext.Length));
+ bytesEncryptedTotal += thisCtext.Length;
+ ctext->Length = bytesEncryptedTotal;
+abort:
+ if(restoreErr) {
+ /* give caller the error from the encrypt */
+ ocrtn = savedErr;
+ }
+ return ocrtn;
+}
+
+/*
+ * Multipurpose decrypt. Like cspStagedDecrypt(), but it takes a
+ * context handle and doesn't have as many options.
+ */
+CSSM_RETURN stagedDecrypt(
+ CSSM_CSP_HANDLE cspHand,
+ CSSM_CC_HANDLE cryptHand,
+ uint32 algorithm, // CSSM_ALGID_FEED, etc.
+ uint32 cipherBlockSizeBytes,// optional
+ const CSSM_DATA *iv, // init vector, optional
+ const CSSM_DATA *ctext,
+ CSSM_DATA_PTR ptext, // mallocd by caller, must be big enough!
+ CSSM_BOOL multiUpdates) // false:single update, true:multi updates
+{
+ CSSM_RETURN crtn;
+ CSSM_SIZE bytesDecrypted; // per update
+ CSSM_SIZE bytesDecryptedTotal = 0;
+ CSSM_RETURN ocrtn = CSSM_OK; // 'our' crtn
+ unsigned toMove; // remaining
+ unsigned thisMove; // bytes to decrypt on this update
+ CSSM_DATA thisCtext; // running ptr into ptext
+ CSSM_DATA thisPtext; // running ptr into ctext
+ CSSM_SIZE ptextLen;
+
+ if(cipherBlockSizeBytes) {
+ crtn = AddContextAttribute(cryptHand,
+ CSSM_ATTRIBUTE_BLOCK_SIZE,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ cipherBlockSizeBytes);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ }
+
+ thisCtext = *ctext;
+ thisPtext = *ptext;
+ memset(ptext->Data, 0, ptext->Length);
+ ptextLen = ptext->Length;
+
+ crtn = CSSM_DecryptDataInit(cryptHand);
+ if(crtn) {
+ printError("CSSM_DecryptDataInit", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+
+ toMove = ctext->Length;
+ while(toMove) {
+ if(multiUpdates) {
+ thisMove = genRand(1, toMove);
+ }
+ else {
+ /* just do one pass thru this loop */
+ thisMove = toMove;
+ }
+ thisCtext.Length = thisMove;
+ crtn = CSSM_DecryptDataUpdate(cryptHand,
+ &thisCtext,
+ 1,
+ &thisPtext,
+ 1,
+ &bytesDecrypted);
+ if(crtn) {
+ printError("CSSM_DecryptDataUpdate", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ soprintf(("*** DecryptDataUpdate: ctextLen 0x%x bytesDecrypted 0x%x\n",
+ (unsigned)thisMove, (unsigned)bytesDecrypted));
+
+ // NOTE: We return the proper length in ptext....
+ ptextLen -= bytesDecrypted; // bump out ptr
+ thisPtext.Length = ptextLen;
+ thisPtext.Data += bytesDecrypted;
+ bytesDecryptedTotal += bytesDecrypted;
+ thisCtext.Data += thisMove; // bump in ptr
+ toMove -= thisMove;
+ }
+ /* OK, one more */
+ crtn = CSSM_DecryptDataFinal(cryptHand, &thisPtext);
+ if(crtn) {
+ printError("CSSM_DecryptDataFinal", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ soprintf(("*** DecryptDataFinal: bytesEncrypted 0x%x\n",
+ (unsigned)thisPtext.Length));
+ bytesDecryptedTotal += thisPtext.Length;
+ ptext->Length = bytesDecryptedTotal;
+abort:
+ return ocrtn;
+}
+
+static int doTest(
+ CSSM_CSP_HANDLE cspHand,
+ const CSSM_DATA *ptext,
+ const CSSM_DATA *ctext1,
+ const CSSM_DATA *ctext2,
+ const CSSM_DATA *rptext,
+ const CSSM_DATA *keyData,
+ const CSSM_DATA *iv,
+ uint32 keyAlg, // CSSM_ALGID_xxx of the key
+ uint32 encrAlg, // encrypt/decrypt
+ uint32 encrMode,
+ uint32 padding,
+ uint32 keySizeInBits,
+ uint32 cipherBlockSizeBytes,
+ CSSM_BOOL quiet)
+{
+ CSSM_DATA lctext1;
+ CSSM_DATA lctext2;
+ CSSM_DATA lrptext;
+ int rtn = 0;
+ CSSM_RETURN crtn;
+ CSSM_CC_HANDLE ccHand1 = 0;
+ CSSM_CC_HANDLE ccHand2 = 0;
+ CSSM_KEY key1;
+ CSSM_KEY key2;
+ uint8 dummy[cipherBlockSizeBytes];
+ CSSM_DATA dummyData = {cipherBlockSizeBytes, dummy};
+
+ /*
+ * generate two equivalent keys key1 and key2;
+ * generate two CC handles ccHand1, ccHand2;
+ * encrypt dummy data with ccHand1 to get it cooked;
+ * encrypt ptext with ccHand1 ==> ctext1;
+ * encrypt ptext with ccHand2 ==> ctext2;
+ * Compare ctext1 and ctext2;
+ * decrypt ctext1 with ccHand1, compare with ptext;
+ */
+ crtn = cspGenSymKeyWithBits(cspHand, keyAlg, CSSM_KEYUSE_ANY,
+ keyData, keySizeInBits / 8, &key1);
+ if(crtn) {
+ return crtn;
+ }
+ crtn = cspGenSymKeyWithBits(cspHand, keyAlg, CSSM_KEYUSE_ANY,
+ keyData, keySizeInBits / 8, &key2);
+ if(crtn) {
+ return crtn;
+ }
+ ccHand1 = genCryptHandle(cspHand,
+ encrAlg,
+ encrMode,
+ padding,
+ &key1,
+ NULL, // pubKey
+ iv,
+ 0, // effectiveKeySizeInBits
+ 0); // rounds
+ if(ccHand1 == 0) {
+ return CSSMERR_CSP_INTERNAL_ERROR;
+ }
+ ccHand2 = genCryptHandle(cspHand,
+ encrAlg,
+ encrMode,
+ padding,
+ &key2,
+ NULL, // pubKey
+ iv,
+ 0, // effectiveKeySizeInBits
+ 0); // rounds
+ if(ccHand2 == 0) {
+ return CSSMERR_CSP_INTERNAL_ERROR;
+ }
+
+ /* dummy encrypt to heat up ccHand1 */
+ appGetRandomBytes(dummy, sizeof(dummy));
+ lctext1 = *ctext1;
+ crtn = stagedEncrypt(cspHand, ccHand1, encrAlg, cipherBlockSizeBytes,
+ iv, &dummyData, &lctext1, CSSM_FALSE);
+ if(crtn) {
+ return crtn;
+ }
+
+ /* encrypt ptext with ccHand1 and ccHand2, compare ctext */
+ lctext1 = *ctext1;
+ crtn = stagedEncrypt(cspHand, ccHand1, encrAlg, cipherBlockSizeBytes,
+ iv, ptext, &lctext1, CSSM_TRUE);
+ if(crtn) {
+ return crtn;
+ }
+ lctext2 = *ctext2;
+ crtn = stagedEncrypt(cspHand, ccHand2, encrAlg, cipherBlockSizeBytes,
+ iv, ptext, &lctext2, CSSM_TRUE);
+ if(crtn) {
+ return crtn;
+ }
+ if(!appCompareCssmData(&lctext1, &lctext2)) {
+ printf("***Ciphertext miscompare\n");
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+
+ /* decrypt with ccHand1, compare with ptext */
+ lrptext = *rptext;
+ crtn = stagedDecrypt(cspHand, ccHand1, encrAlg, cipherBlockSizeBytes,
+ iv, &lctext1, &lrptext, CSSM_TRUE);
+ if(crtn) {
+ return crtn;
+ }
+ if(!appCompareCssmData(&lctext1, &lctext2)) {
+ printf("***Plaintext miscompare\n");
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+
+ if(ccHand1) {
+ CSSM_DeleteContext(ccHand1);
+ }
+ if(ccHand2) {
+ CSSM_DeleteContext(ccHand2);
+ }
+ return rtn;
+}
+
+
+int main(int argc, char **argv)
+{
+ int arg;
+ char *argp;
+ unsigned loop;
+ CSSM_DATA ptext;
+ CSSM_DATA ctext1;
+ CSSM_DATA ctext2;
+ CSSM_DATA rptext;
+ CSSM_CSP_HANDLE cspHand;
+ const char *algStr;
+ uint32 keyAlg; // CSSM_ALGID_xxx of the key
+ uint32 encrAlg; // CSSM_ALGID_xxx of encr/decr
+ unsigned currAlg; // ALG_xxx
+ uint32 keySizeInBits;
+ int rtn = 0;
+ CSSM_DATA keyData;
+ CSSM_DATA initVector;
+ uint32 minTextSize;
+ uint32 rawMode;
+ uint32 cookedMode;
+ const char *rawModeStr;
+ const char *cookedModeStr;
+ uint32 algBlockSizeBytes;
+
+ /*
+ * User-spec'd params
+ */
+ CSSM_BOOL keySizeSpec = CSSM_FALSE; // false: use rand key size
+ unsigned minAlg = ALG_FIRST;
+ unsigned maxAlg = ALG_LAST;
+ unsigned loops = LOOPS_DEF;
+ CSSM_BOOL verbose = CSSM_FALSE;
+ CSSM_BOOL quiet = CSSM_FALSE;
+ unsigned pauseInterval = 0;
+ uint32 padding;
+ CSSM_BOOL bareCsp = CSSM_TRUE;
+ unsigned maxPtextSize = MAX_DATA_SIZE;
+ unsigned minPtextSize = MIN_DATA_SIZE;
+
+ for(arg=1; arg<argc; arg++) {
+ argp = argv[arg];
+ switch(argp[0]) {
+ case 'a':
+ if(argp[1] != '=') {
+ usage(argv);
+ }
+ switch(argp[2]) {
+ case 'd':
+ minAlg = maxAlg = ALG_DES;
+ break;
+ case '3':
+ minAlg = maxAlg = ALG_3DES;
+ break;
+ case '2':
+ minAlg = maxAlg = ALG_RC2;
+ break;
+ case '4':
+ minAlg = maxAlg = ALG_RC4;
+ break;
+ case '5':
+ minAlg = maxAlg = ALG_RC5;
+ break;
+ case 'a':
+ minAlg = maxAlg = ALG_AES;
+ break;
+ case 'A':
+ minAlg = maxAlg = ALG_AES192;
+ break;
+ case '6':
+ minAlg = maxAlg = ALG_AES256;
+ break;
+ case 'b':
+ minAlg = maxAlg = ALG_BFISH;
+ break;
+ case 'c':
+ minAlg = maxAlg = ALG_CAST;
+ break;
+ case 's':
+ minAlg = maxAlg = ALG_ASC;
+ break;
+ default:
+ usage(argv);
+ }
+ break;
+ case 'l':
+ loops = atoi(&argp[2]);
+ break;
+ case 'k':
+ keySizeInBits = atoi(&argp[2]);
+ keySizeSpec = CSSM_TRUE;
+ break;
+ case 'v':
+ verbose = CSSM_TRUE;
+ break;
+ case 'D':
+ bareCsp = CSSM_FALSE;
+ break;
+ case 'm':
+ maxPtextSize = atoi(&argp[2]);
+ break;
+ case 'n':
+ minPtextSize = atoi(&argp[2]);
+ break;
+ case 'q':
+ quiet = CSSM_TRUE;
+ break;
+ case 'p':
+ pauseInterval = atoi(&argp[2]);;
+ break;
+ case 'h':
+ default:
+ usage(argv);
+ }
+ }
+ ptext.Data = (uint8 *)CSSM_MALLOC(maxPtextSize);
+ if(ptext.Data == NULL) {
+ printf("Insufficient heap space\n");
+ exit(1);
+ }
+ /* ptext length set in test loop */
+ appSetupCssmData(&ctext1, 2 * maxPtextSize);
+ appSetupCssmData(&ctext2, 2 * maxPtextSize);
+ appSetupCssmData(&rptext, 2 * maxPtextSize);
+
+ keyData.Data = (uint8 *)CSSM_MALLOC(MAX_KEY_SIZE);
+ if(keyData.Data == NULL) {
+ printf("Insufficient heap space\n");
+ exit(1);
+ }
+ keyData.Length = MAX_KEY_SIZE;
+
+ initVector.Data = (uint8 *)"someStrangeInitVect";
+
+ testStartBanner("contextReuse", argc, argv);
+
+ cspHand = cspDlDbStartup(bareCsp, NULL);
+ if(cspHand == 0) {
+ exit(1);
+ }
+ if(pauseInterval) {
+ fpurge(stdin);
+ printf("Top of test; hit CR to proceed: ");
+ getchar();
+ }
+ for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) {
+ /* some default values... */
+ padding = CSSM_PADDING_PKCS5;
+ rawMode = RAW_MODE;
+ cookedMode = COOKED_MODE;
+ rawModeStr = RAW_MODE_STR;
+ cookedModeStr = COOKED_MODE_STR;
+ padding = CSSM_PADDING_PKCS5;
+
+ switch(currAlg) {
+ case ALG_DES:
+ encrAlg = keyAlg = CSSM_ALGID_DES;
+ algStr = "DES";
+ algBlockSizeBytes = 8;
+ break;
+ case ALG_3DES:
+ /* currently the only one with different key and encr algs */
+ keyAlg = CSSM_ALGID_3DES_3KEY;
+ encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
+ algStr = "3DES";
+ algBlockSizeBytes = 8;
+ break;
+ case ALG_RC2:
+ encrAlg = keyAlg = CSSM_ALGID_RC2;
+ algStr = "RC2";
+ algBlockSizeBytes = 8;
+ break;
+ case ALG_RC4:
+ encrAlg = keyAlg = CSSM_ALGID_RC4;
+ algStr = "RC4";
+ algBlockSizeBytes = 0;
+ rawMode = RAW_MODE_STREAM;
+ cookedMode = RAW_MODE_STREAM;
+ rawModeStr = RAW_MODE_STREAM_STR;
+ cookedModeStr = RAW_MODE_STREAM_STR;
+ break;
+ case ALG_RC5:
+ encrAlg = keyAlg = CSSM_ALGID_RC5;
+ algStr = "RC5";
+ algBlockSizeBytes = 8;
+ break;
+ case ALG_AES:
+ encrAlg = keyAlg = CSSM_ALGID_AES;
+ algStr = "AES";
+ algBlockSizeBytes = 16;
+ break;
+ case ALG_AES192:
+ encrAlg = keyAlg = CSSM_ALGID_AES;
+ algStr = "AES192";
+ algBlockSizeBytes = 24;
+ break;
+ case ALG_AES256:
+ encrAlg = keyAlg = CSSM_ALGID_AES;
+ algStr = "AES256";
+ algBlockSizeBytes = 32;
+ break;
+ case ALG_BFISH:
+ encrAlg = keyAlg = CSSM_ALGID_BLOWFISH;
+ algStr = "Blowfish";
+ algBlockSizeBytes = 8;
+ break;
+ case ALG_CAST:
+ encrAlg = keyAlg = CSSM_ALGID_CAST;
+ algStr = "CAST";
+ algBlockSizeBytes = 8;
+ break;
+ }
+
+ /* assume for now all algs require IV */
+ initVector.Length = algBlockSizeBytes ? algBlockSizeBytes : 8;
+
+ if(!quiet || verbose) {
+ printf("Testing alg %s\n", algStr);
+ }
+ for(loop=1; ; loop++) {
+ /* mix up raw/cooked */
+ uint32 mode;
+ const char *modeStr;
+ CSSM_BOOL paddingEnabled;
+
+ if(loop & 1) {
+ mode = rawMode;
+ modeStr = rawModeStr;
+ }
+ else {
+ mode = cookedMode;
+ modeStr = cookedModeStr;
+ }
+ switch(mode) {
+ case CSSM_ALGMODE_CBCPadIV8:
+ paddingEnabled = CSSM_TRUE;
+ break;
+ default:
+ /* all others - right? */
+ paddingEnabled = CSSM_FALSE;
+ break;
+ }
+ minTextSize = minPtextSize; // default
+ if(!paddingEnabled && algBlockSizeBytes && (minTextSize < algBlockSizeBytes)) {
+ /* i.e., no padding, adjust min ptext size */
+ minTextSize = algBlockSizeBytes;
+ }
+ simpleGenData(&ptext, minTextSize, maxPtextSize);
+ if(!paddingEnabled && algBlockSizeBytes) {
+ /* align ptext */
+ ptext.Length = (ptext.Length / algBlockSizeBytes) * algBlockSizeBytes;
+ }
+
+ simpleGenData(&keyData, MAX_KEY_SIZE, MAX_KEY_SIZE);
+
+ if(!keySizeSpec) {
+ /* random but byte-aligned */
+ keySizeInBits = randKeySizeBits(keyAlg, OT_Encrypt);
+ keySizeInBits = (keySizeInBits + 7) & ~7;
+ }
+ /* else constant, spec'd by user, may be 0 (default per alg) */
+ if(!quiet) {
+ if(verbose || ((loop % LOOP_NOTIFY) == 0)) {
+ if(algBlockSizeBytes) {
+ printf("..loop %d text size %lu keySizeBits %u"
+ " blockSize %u mode %s\n",
+ loop, (unsigned long)ptext.Length, (unsigned)keySizeInBits,
+ (unsigned)algBlockSizeBytes, modeStr);
+ }
+ else {
+ printf("..loop %d text size %lu keySizeBits %u"
+ " mode %s\n",
+ loop, (unsigned long)ptext.Length, (unsigned)keySizeInBits,
+ modeStr);
+ }
+ }
+ }
+
+ if(doTest(cspHand,
+ &ptext,
+ &ctext1,
+ &ctext2,
+ &rptext,
+ &keyData,
+ &initVector,
+ keyAlg,
+ encrAlg,
+ mode,
+ padding,
+ keySizeInBits,
+ algBlockSizeBytes,
+ quiet)) {
+ rtn = 1;
+ break;
+ }
+ if(pauseInterval && ((loop % pauseInterval) == 0)) {
+ char c;
+ fpurge(stdin);
+ printf("Hit CR to proceed, q to abort: ");
+ c = getchar();
+ if(c == 'q') {
+ goto testDone;
+ }
+ }
+ if(loops && (loop == loops)) {
+ break;
+ }
+ } /* main loop */
+ if(rtn) {
+ break;
+ }
+
+ } /* for algs */
+
+testDone:
+ cspShutdown(cspHand, bareCsp);
+ if(pauseInterval) {
+ fpurge(stdin);
+ printf("ModuleDetach/Unload complete; hit CR to exit: ");
+ getchar();
+ }
+ if((rtn == 0) && !quiet) {
+ printf("%s test complete\n", argv[0]);
+ }
+ CSSM_FREE(ptext.Data);
+ CSSM_FREE(keyData.Data);
+ return rtn;
+}
+
+