]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/cspxutils/pbeTest/pbeTest.c
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / pbeTest / pbeTest.c
diff --git a/SecurityTests/cspxutils/pbeTest/pbeTest.c b/SecurityTests/cspxutils/pbeTest/pbeTest.c
new file mode 100644 (file)
index 0000000..ddce2c7
--- /dev/null
@@ -0,0 +1,1270 @@
+/* Copyright (c) 1998,2003-2005,2008 Apple Inc.
+ *
+ * pbeTest.c - test CSP PBE-style DeriveKey().
+ *
+ * Revision History
+ * ----------------
+ *  15 May 2000 Doug Mitchell
+ *             Ported to X/CDSA2. 
+ *  13 Aug 1998        Doug Mitchell at NeXT
+ *             Created.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <Security/cssm.h>
+#include "cspwrap.h"
+#include "common.h"
+#include "cspdlTesting.h"
+
+/* we need to know a little bit about AES for this test.... */
+#define AES_BLOCK_SIZE         16              /* bytes */
+
+/*
+ * Defaults.
+ */
+#define LOOPS_DEF                      10
+#define MIN_PTEXT_SIZE         AES_BLOCK_SIZE          /* for non-padding tests */
+#define MAX_PTEXT_SIZE         1000
+#define MAX_PASSWORD_SIZE      64
+#define MAX_SALT_SIZE          32
+#define MIN_ITER_COUNT         1000
+#define MAX_ITER_COUNT         2000
+#define MAX_IV_SIZE                    AES_BLOCK_SIZE
+
+/* min values not currently exported by CSP */
+#define APPLE_PBE_MIN_PASSWORD 8
+#define APPLE_PBE_MIN_SALT             8
+
+/* static IV for derive algorithms which don't create one */
+CSSM_DATA staticIv = {MAX_IV_SIZE, (uint8 *)"someIvOrOther..."};
+
+/*
+ * Enumerate algs our own way to allow iteration.
+ */
+typedef unsigned privAlg;
+enum {
+       /* PBE algs */
+       pbe_pbkdf2 = 1,
+       // other unsupported for now
+       pbe_PKCS12 = 1,
+       pbe_MD5,
+       pbe_MD2,
+       pbe_SHA1,
+       
+       /* key gen algs */
+       pka_ASC,
+       pka_RC4,
+       pka_DES,
+       pka_RC2,
+       pka_RC5,
+       pka_3DES,
+       pka_AES
+};
+
+#define PBE_ALG_FIRST                  pbe_pbkdf2
+#define PBE_ALG_LAST                   pbe_pbkdf2
+#define ENCR_ALG_FIRST                 pka_ASC
+#define ENCR_ALG_LAST                  pka_AES
+#define ENCR_ALG_LAST_EXPORT   pka_RC5
+
+/*
+ * Args passed to each test
+ */
+typedef struct {
+       CSSM_CSP_HANDLE         cspHand;
+       CSSM_ALGORITHMS         keyAlg;
+       CSSM_ALGORITHMS         encrAlg;
+       uint32                          keySizeInBits;
+       uint32                          effectiveKeySizeInBits; // 0 means not used
+       const char                      *keyAlgStr;
+       CSSM_ENCRYPT_MODE       encrMode;
+       CSSM_PADDING            encrPad;
+       CSSM_ALGORITHMS         deriveAlg;
+       const char                      *deriveAlgStr;
+       CSSM_DATA_PTR           ptext;
+       CSSM_DATA_PTR           password;
+       CSSM_DATA_PTR           salt;
+       uint32                          iterCount;
+       CSSM_BOOL                       useInitVector;          // encrypt needs an IV
+       uint32                          ivSize;
+       CSSM_BOOL                       genInitVector;          // DeriveKey generates an IV
+       CSSM_BOOL                       useRefKey;
+       CSSM_BOOL                       quiet;
+} testArgs;
+
+static void usage(char **argv)
+{
+       printf("usage: %s [options]\n", argv[0]);
+       printf("   Options:\n");
+       printf("   l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
+       printf("   e(xport)\n");
+       printf("   r(epeatOnly)\n");
+       printf("   z(ero length password)\n");
+       printf("   p(ause after each loop)\n");
+       printf("   D (CSP/DL; default = bare CSP)\n");
+       printf("   q(uiet)\n");
+       printf("   h(elp)\n");
+       exit(1);
+}
+
+/*
+ * Given a privAlg value, return various associated stuff.
+ */
+static void algInfo(privAlg alg,                       // pbe_MD5, etc.
+       CSSM_ALGORITHMS         *cdsaAlg,               // CSSM_ALGID_MD5_PBE, etc. RETURNED
+                                                                               //   key alg for key gen algs
+       CSSM_ALGORITHMS         *encrAlg,               // encrypt/decrypt alg for key 
+                                                                               //   gen algs
+       CSSM_ENCRYPT_MODE       *mode,                  // RETURNED
+       CSSM_PADDING            *padding,               // RETURNED
+       CSSM_BOOL                       *useInitVector, // RETURNED, for encrypt/decrypt
+       uint32                          *ivSize,                // RETURNED, in bytes
+       CSSM_BOOL                       *genInitVector, // RETURNED, for deriveKey
+       const char                      **algStr)               // RETURNED
+{
+       /* default or irrelevant fields */
+       *mode = CSSM_ALGMODE_NONE;
+       *useInitVector = CSSM_FALSE;
+       *genInitVector = CSSM_FALSE;            // DeriveKey doesn't do this now
+       *padding = CSSM_PADDING_PKCS1;
+       *ivSize = 8;                                            // thje usual size, if needed
+       *encrAlg = CSSM_ALGID_NONE;
+       
+       switch(alg) {
+               case pbe_pbkdf2:
+                       *cdsaAlg = CSSM_ALGID_PKCS5_PBKDF2;
+                       *algStr = "PBKDF2";
+                       return;
+               /* these are not supported */
+               #if 0
+               case pbe_PKCS12:
+                       *cdsaAlg = CSSM_ALGID_SHA1_PBE_PKCS12;
+                       *algStr = "PKCS12";
+                       return;
+               case pbe_MD5:
+                       *cdsaAlg = CSSM_ALGID_MD5_PBE;
+                       *algStr = "MD5";
+                       return;
+               case pbe_MD2:
+                       *cdsaAlg = CSSM_ALGID_MD2_PBE;
+                       *algStr = "MD2";
+                       return;
+               case pbe_SHA1:
+                       *cdsaAlg = CSSM_ALGID_SHA1_PBE;
+                       *algStr = "SHA1";
+                       return;
+               case pka_ASC:
+                       *cdsaAlg = CSSM_ALGID_ASC;
+                       *algStr = "ASC";
+                       return;
+               #endif 
+               case pka_DES:
+                       *cdsaAlg = *encrAlg = CSSM_ALGID_DES;
+                       *useInitVector = CSSM_TRUE;
+                       *mode = CSSM_ALGMODE_CBCPadIV8;
+                       *algStr = "DES";
+                       return;
+               case pka_3DES:
+                       *cdsaAlg = CSSM_ALGID_3DES_3KEY;
+                       *encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
+                       *useInitVector = CSSM_TRUE;
+                       *mode = CSSM_ALGMODE_CBCPadIV8;
+                       *algStr = "3DES";
+                       return;
+               case pka_AES:
+                       *cdsaAlg = *encrAlg = CSSM_ALGID_AES;
+                       *useInitVector = CSSM_TRUE;
+                       *mode = CSSM_ALGMODE_CBCPadIV8;
+                       *padding = CSSM_PADDING_PKCS5;
+                       *ivSize = AES_BLOCK_SIZE;                       // per the default block size
+                       *algStr = "AES";
+                       return;
+               case pka_RC2:
+                       *cdsaAlg = *encrAlg = CSSM_ALGID_RC2;
+                       *useInitVector = CSSM_TRUE;
+                       *mode = CSSM_ALGMODE_CBCPadIV8;
+                       *algStr = "RC2";
+                       return;
+               case pka_RC4:
+                       *cdsaAlg = *encrAlg = CSSM_ALGID_RC4;
+                       /* initVector false */
+                       *mode = CSSM_ALGMODE_NONE;
+                       *algStr = "RC4";
+                       return;
+               case pka_RC5:
+                       *cdsaAlg = *encrAlg = CSSM_ALGID_RC5;
+                       *algStr = "RC5";
+                       *mode = CSSM_ALGMODE_CBCPadIV8;
+                       *useInitVector = CSSM_TRUE;
+                       return;
+               case pka_ASC:
+                       *cdsaAlg = *encrAlg = CSSM_ALGID_ASC;
+                       /* initVector false */
+                       *algStr = "ASC";
+                       *mode = CSSM_ALGMODE_NONE;
+                       return;
+               default:
+                       printf("BRRZZZT! Update algInfo()!\n");
+                       testError(CSSM_TRUE);
+       }
+}
+
+/* a handy "compare two CSSM_DATAs" ditty */
+static CSSM_BOOL compareData(const CSSM_DATA_PTR d1,
+       const CSSM_DATA_PTR d2)
+{
+       if(d1->Length != d2->Length) {
+               return CSSM_FALSE;
+       }
+       if(memcmp(d1->Data, d2->Data, d1->Length)) {
+               return CSSM_FALSE;
+       }
+       return CSSM_TRUE;
+}
+
+/* generate random one-bit byte */
+static uint8 randBit()
+{
+       return 1 << genRand(0, 7);
+}
+
+/*
+ * Writer debug - assertion failure when ctext[1].Data is NULL
+ * but length is nonzero
+ */
+#define SAFE_CTEXT_ARRAY       0
+
+/*
+ * Encrypt ptext using specified key, IV, effectiveKeySizeInBits
+ */
+static int encryptCom(CSSM_CSP_HANDLE cspHand,
+       const char *testName,
+       CSSM_DATA_PTR ptext,
+       CSSM_KEY_PTR key,
+       CSSM_ALGORITHMS alg,
+       CSSM_ENCRYPT_MODE mode,
+       CSSM_PADDING padding,                   // CSSM_PADDING_PKCS1, etc. 
+       CSSM_DATA_PTR iv,                               // may be NULL
+       uint32 effectiveKeySizeInBits,  // may be 0
+       CSSM_DATA_PTR ctext,                    // RETURNED
+       CSSM_BOOL quiet)
+{
+       CSSM_CC_HANDLE cryptHand;
+       CSSM_RETURN crtn;
+       CSSM_SIZE bytesEncrypted;
+       CSSM_DATA remData;
+       int rtn;
+       #if     SAFE_CTEXT_ARRAY
+       CSSM_DATA safeCtext[2];
+       safeCtext[0] = *ctext;
+       safeCtext[1].Data = NULL;
+       safeCtext[1].Length = 10;               // lie, but shouldn't use this!
+       #else
+       //      printf("+++ ctext[0] = %d:0x%x; ctext[1] = %d:0x%x\n",
+       //              ctext[0].Length, ctext[0].Data,
+       //              ctext[1].Length, ctext[1].Data);
+       #endif
+       
+       cryptHand = genCryptHandle(cspHand,
+               alg,
+               mode,
+               padding,                
+               key,
+               NULL,                   // no 2nd key
+               iv,                             // InitVector
+               effectiveKeySizeInBits,
+               0);                             // rounds
+       if(cryptHand == 0) {
+               return testError(quiet);
+       }
+       
+       remData.Data = NULL;
+       remData.Length = 0;
+       crtn = CSSM_EncryptData(cryptHand,
+               ptext,
+               1,
+               #if     SAFE_CTEXT_ARRAY
+               &safeCtext[0],
+               #else
+               ctext,
+               #endif
+               1,
+               &bytesEncrypted,
+               &remData);
+       #if     SAFE_CTEXT_ARRAY
+       *ctext = safeCtext[0];
+       #endif
+       
+       if(crtn) {
+               printError("CSSM_EncryptData", crtn);
+               rtn = testError(quiet);
+               goto done;
+       }
+       if(remData.Length != 0) {
+               //printf("***WARNING: nonzero remData on encrypt!\n");
+               /* new for CDSA2 - possible remData even if we ask the CSP to 
+                * malloc ctext */
+               ctext->Data = (uint8 *)appRealloc(ctext->Data, bytesEncrypted, NULL);
+               memmove(ctext->Data + ctext->Length, 
+                       remData.Data, 
+                       bytesEncrypted - ctext->Length);
+               appFreeCssmData(&remData, CSSM_FALSE);
+       }
+       /* new for CDSA 2 */
+       ctext->Length = bytesEncrypted;
+       rtn = 0;
+done:
+       if(CSSM_DeleteContext(cryptHand)) {
+               printError("CSSM_DeleteContext", 0);
+               rtn = 1;
+       }
+       return rtn;
+}
+
+/*
+ * Decrypt ctext using specified key, IV, effectiveKeySizeInBits
+ */
+static int decryptCom(CSSM_CSP_HANDLE cspHand,
+       const char *testName,
+       CSSM_DATA_PTR ctext,
+       CSSM_KEY_PTR key,
+       CSSM_ALGORITHMS alg,
+       CSSM_ENCRYPT_MODE mode,
+       CSSM_PADDING padding,           
+       CSSM_DATA_PTR iv,                               // may be NULL
+       uint32 effectiveKeySizeInBits,  // may be 0
+       CSSM_DATA_PTR ptext,                    // RETURNED
+       CSSM_BOOL quiet)
+{
+       CSSM_CC_HANDLE cryptHand;
+       CSSM_RETURN crtn;
+       CSSM_SIZE bytesDecrypted;
+       CSSM_DATA remData;
+       int rtn;
+
+       cryptHand = genCryptHandle(cspHand,
+               alg,
+               mode,
+               padding,                
+               key,
+               NULL,                   // no 2nd key
+               iv,                             // InitVector
+               effectiveKeySizeInBits,
+               0);                             // rounds
+       if(cryptHand == 0) {
+               return testError(quiet);
+       }
+       remData.Data = NULL;
+       remData.Length = 0;
+       crtn = CSSM_DecryptData(cryptHand,
+               ctext,
+               1,
+               ptext,
+               1,
+               &bytesDecrypted,
+               &remData);
+       if(crtn) {
+               printError("CSSM_DecryptData", crtn);
+               rtn = testError(quiet);
+               goto done;
+       }
+       if(remData.Length != 0) {
+               //printf("***WARNING: nonzero remData on decrypt!\n");
+               /* new for CDSA2 - possible remData even if we ask the CSP to 
+                * malloc ptext */
+               ptext->Data = (uint8 *)appRealloc(ptext->Data, bytesDecrypted, NULL);
+               memmove(ptext->Data + ptext->Length, 
+                       remData.Data, 
+                       bytesDecrypted - ptext->Length);
+               appFreeCssmData(&remData, CSSM_FALSE);
+       }
+       /* new for CDSA 2 */
+       ptext->Length = bytesDecrypted;
+       rtn = 0;
+done:
+       if(CSSM_DeleteContext(cryptHand)) {
+               printError("CSSM_DeleteContext", 0);
+               rtn = 1;
+       }
+       return rtn;
+}
+
+/*
+ * Common test portion
+ *   encrypt ptext with key1, iv1
+ *   encrypt ptext with key2, iv2
+ *      compare 2 ctexts; expect failure;
+ */
+#define TRAP_WRITER_ERR        1
+
+static int testCommon(CSSM_CSP_HANDLE cspHand,
+       const char *testName,
+       CSSM_ALGORITHMS encrAlg,
+       CSSM_ENCRYPT_MODE encrMode,
+       CSSM_PADDING encrPad,
+       uint32 effectiveKeySizeInBits,
+       CSSM_DATA_PTR ptext,
+       CSSM_KEY_PTR key1,
+       CSSM_DATA_PTR iv1,
+       CSSM_KEY_PTR key2,
+       CSSM_DATA_PTR iv2,
+       CSSM_BOOL quiet)
+{
+       CSSM_DATA               ctext1;
+       CSSM_DATA               ctext2;
+       ctext1.Data = NULL;
+       ctext1.Length = 0;
+       ctext2.Data = NULL;
+       ctext2.Length = 0;
+       if(encryptCom(cspHand,
+                       testName,
+                       ptext,
+                       key1,
+                       encrAlg,
+                       encrMode,
+                       encrPad,
+                       iv1,
+                       effectiveKeySizeInBits,
+                       &ctext1,
+                       quiet)) {
+               return 1;
+       }
+       #if     TRAP_WRITER_ERR
+       if(ctext2.Data != NULL){
+               printf("Hey! encryptCom(ptext, ctext1 modified ctext2!\n");
+               if(testError(quiet)) {
+                       return 1;
+               }
+       }
+       #endif
+       if(encryptCom(cspHand,
+                       testName,
+                       ptext,
+                       key2,
+                       encrAlg,
+                       encrMode,
+                       encrPad,
+                       iv2,
+                       effectiveKeySizeInBits,
+                       &ctext2,
+                       quiet)) {
+               return 1;
+       }
+       if(compareData(&ctext1, &ctext2)) {
+               printf("***%s: Unexpected Data compare!\n", testName);
+               return testError(quiet);
+       }
+       appFreeCssmData(&ctext1, CSSM_FALSE);
+       appFreeCssmData(&ctext2, CSSM_FALSE);
+       return 0;
+}
+
+/**
+ ** inidividual tests.
+ **/
+#define KEY_LABEL1             "noLabel1"
+#define KEY_LABEL2             "noLabel2"
+#define KEY_LABEL_LEN  strlen(KEY_LABEL1)
+#define REPEAT_ON_ERROR        1
+
+/* test repeatability - the only test here which actually decrypts */
+static int repeatTest(testArgs *targs)
+{
+       /*
+       generate two keys with same params;
+       encrypt ptext with key1;
+       decrypt ctext with key2;
+       compare; expect success;
+       */
+       CSSM_KEY_PTR    key1;
+       CSSM_KEY_PTR    key2;
+       CSSM_DATA               iv1;
+       CSSM_DATA               iv2;
+       CSSM_DATA_PTR   ivp1;
+       CSSM_DATA_PTR   ivp2;
+       CSSM_DATA               ctext;
+       CSSM_DATA               rptext;
+       CSSM_BOOL               gotErr = CSSM_FALSE;
+       
+       if(targs->useInitVector) {
+               if(targs->genInitVector) {
+                       ivp1 = &iv1;
+                       ivp2 = &iv2;
+               }
+               else {
+                       staticIv.Length = targs->ivSize;
+                       ivp1 = ivp2 = &staticIv;
+               }
+       }
+       else {
+               ivp1 = ivp2 = NULL;
+       }
+       /* these need to be init'd regardless */
+       iv1.Data = NULL;
+       iv1.Length = 0;
+       iv2.Data = NULL;
+       iv2.Length = 0;
+       ctext.Data = NULL;
+       ctext.Length = 0;
+       rptext.Data = NULL;
+       rptext.Length = 0;
+repeatDerive:
+       key1 = cspDeriveKey(targs->cspHand,
+               targs->deriveAlg,
+               targs->keyAlg,
+               KEY_LABEL1,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_ENCRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,
+               targs->salt,
+               targs->iterCount,
+               &iv1);
+       if(key1 == NULL) {
+               return testError(targs->quiet);
+       }
+       key2 = cspDeriveKey(targs->cspHand,
+               targs->deriveAlg,
+               targs->keyAlg,
+               KEY_LABEL2,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_DECRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,
+               targs->salt,
+               targs->iterCount,
+               &iv2);
+       if(key2 == NULL) {
+               return testError(targs->quiet);
+       }
+repeatEnc:
+       if(encryptCom(targs->cspHand,
+                       "repeatTest",
+                       targs->ptext,
+                       key1,
+                       targs->encrAlg,
+                       targs->encrMode,
+                       targs->encrPad,
+                       ivp1,
+                       targs->effectiveKeySizeInBits,
+                       &ctext,
+                       targs->quiet)) {
+               return 1;
+       }
+       if(decryptCom(targs->cspHand,
+                       "repeatTest",
+                       &ctext,
+                       key2,
+                       targs->encrAlg,
+                       targs->encrMode,
+                       targs->encrPad,
+                       ivp2,
+                       targs->effectiveKeySizeInBits,
+                       &rptext,
+                       targs->quiet)) {
+               return 1;
+       }
+       if(gotErr || !compareData(targs->ptext, &rptext)) {
+               printf("***Data miscompare in repeatTest\n");
+               if(REPEAT_ON_ERROR) {
+                       char str;
+                       
+                       gotErr = CSSM_TRUE;
+                       fpurge(stdin);
+                       printf("Repeat enc/dec (r), repeat derive (d), continue (c), abort (any)? ");
+                       str = getchar();
+                       switch(str) {
+                               case 'r':
+                                       appFreeCssmData(&ctext, CSSM_FALSE);    
+                                       appFreeCssmData(&rptext, CSSM_FALSE);   
+                                       goto repeatEnc;
+                               case 'd':
+                                       appFreeCssmData(&ctext, CSSM_FALSE);    
+                                       appFreeCssmData(&rptext, CSSM_FALSE);   
+                                       appFreeCssmData(&iv1, CSSM_FALSE);
+                                       appFreeCssmData(&iv2, CSSM_FALSE);
+                                       cspFreeKey(targs->cspHand, key1);
+                                       cspFreeKey(targs->cspHand, key2);
+                                       goto repeatDerive;
+                               case 'c':
+                                       break;
+                               default:
+                                       return 1;
+                       }
+               }
+               else {
+                       return testError(targs->quiet);
+               }
+       }
+       appFreeCssmData(&ctext, CSSM_FALSE);
+       appFreeCssmData(&rptext, CSSM_FALSE);
+       appFreeCssmData(&iv1, CSSM_FALSE);
+       appFreeCssmData(&iv2, CSSM_FALSE);
+       cspFreeKey(targs->cspHand, key1);
+       cspFreeKey(targs->cspHand, key2);
+       CSSM_FREE(key1);
+       CSSM_FREE(key2);
+       return 0;
+}
+
+/* ensure iterCount alters key */
+static int iterTest(testArgs *targs)
+{
+       /*
+       generate key1(iterCount), key2(iterCount+1);
+       encrypt ptext with key1;
+       encrypt ptext with key2;
+       compare 2 ctexts; expect failure;
+       */
+       CSSM_KEY_PTR    key1;
+       CSSM_KEY_PTR    key2;
+       CSSM_DATA               iv1;
+       CSSM_DATA               iv2;
+       CSSM_DATA_PTR   ivp1;
+       CSSM_DATA_PTR   ivp2;
+       if(targs->useInitVector) {
+               if(targs->genInitVector) {
+                       ivp1 = &iv1;
+                       ivp2 = &iv2;
+               }
+               else {
+                       staticIv.Length = targs->ivSize;
+                       ivp1 = ivp2 = &staticIv;
+               }
+       }
+       else {
+               ivp1 = ivp2 = NULL;
+       }
+       /* these need to be init'd regardless */
+       iv1.Data = NULL;
+       iv1.Length = 0;
+       iv2.Data = NULL;
+       iv2.Length = 0;
+       key1 = cspDeriveKey(targs->cspHand,
+               targs->deriveAlg,
+               targs->keyAlg,
+               KEY_LABEL1,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_ENCRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,
+               targs->salt,
+               targs->iterCount,
+               &iv1);
+       if(key1 == NULL) {
+               return testError(targs->quiet);
+       }
+       key2 = cspDeriveKey(targs->cspHand,
+               targs->deriveAlg,
+               targs->keyAlg,
+               KEY_LABEL2,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_ENCRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,
+               targs->salt,
+               targs->iterCount + 1,           // the changed param
+               &iv2);
+       if(key2 == NULL) {
+               return testError(targs->quiet);
+       }
+       if(testCommon(targs->cspHand,
+                               "iterTest",
+                               targs->encrAlg,
+                               targs->encrMode,
+                               targs->encrPad,
+                               targs->effectiveKeySizeInBits,
+                               targs->ptext,
+                               key1,
+                               ivp1,
+                               key2,
+                               ivp2,
+                               targs->quiet)) {
+               return 1;
+       }
+       appFreeCssmData(&iv1, CSSM_FALSE);
+       appFreeCssmData(&iv2, CSSM_FALSE);
+       cspFreeKey(targs->cspHand, key1);
+       cspFreeKey(targs->cspHand, key2);
+       CSSM_FREE(key1);
+       CSSM_FREE(key2);
+       return 0;
+}
+
+/* ensure password alters key */
+static int passwordTest(testArgs *targs)
+{
+       /*
+       generate key1(password), key2(munged password);
+       encrypt ptext with key1;
+       encrypt ptext with key2;
+       compare 2 ctexts; expect failure;
+       */
+       CSSM_KEY_PTR    key1;
+       CSSM_KEY_PTR    key2;
+       CSSM_DATA               iv1;
+       CSSM_DATA               iv2;
+       CSSM_DATA_PTR   ivp1;
+       CSSM_DATA_PTR   ivp2;
+       uint32                  mungeDex;
+       uint32                  mungeBits;
+       if(targs->useInitVector) {
+               if(targs->genInitVector) {
+                       ivp1 = &iv1;
+                       ivp2 = &iv2;
+               }
+               else {
+                       staticIv.Length = targs->ivSize;
+                       ivp1 = ivp2 = &staticIv;
+               }
+       }
+       else {
+               ivp1 = ivp2 = NULL;
+       }
+       /* these need to be init'd regardless */
+       iv1.Data = NULL;
+       iv1.Length = 0;
+       iv2.Data = NULL;
+       iv2.Length = 0;
+       key1 = cspDeriveKey(targs->cspHand,
+               targs->deriveAlg,
+               targs->keyAlg,
+               KEY_LABEL1,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_ENCRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,
+               targs->salt,
+               targs->iterCount,
+               &iv1);
+       if(key1 == NULL) {
+               return testError(targs->quiet);
+       }
+       /* munge password */
+       mungeDex = genRand(0, targs->password->Length - 1);
+       mungeBits = randBit();
+       targs->password->Data[mungeDex] ^= mungeBits;
+       key2 = cspDeriveKey(targs->cspHand,
+               targs->deriveAlg,
+               targs->keyAlg,
+               KEY_LABEL2,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_ENCRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,                        // the changed param
+               targs->salt,
+               targs->iterCount,
+               &iv2);
+       if(key2 == NULL) {
+               return testError(targs->quiet);
+       }
+       if(testCommon(targs->cspHand,
+                               "passwordTest",
+                               targs->encrAlg,
+                               targs->encrMode,
+                               targs->encrPad,
+                               targs->effectiveKeySizeInBits,
+                               targs->ptext,
+                               key1,
+                               ivp1,
+                               key2,
+                               ivp2,
+                               targs->quiet)) {
+               return 1;
+       }
+       /* restore  */
+       targs->password->Data[mungeDex] ^= mungeBits;
+       appFreeCssmData(&iv1, CSSM_FALSE);
+       appFreeCssmData(&iv2, CSSM_FALSE);
+       cspFreeKey(targs->cspHand, key1);
+       cspFreeKey(targs->cspHand, key2);
+       CSSM_FREE(key1);
+       CSSM_FREE(key2);
+       return 0;
+}
+
+/* ensure salt alters key */
+static int saltTest(testArgs *targs)
+{
+       /*
+       generate key1(seed), key2(munged seed);
+       encrypt ptext with key1;
+       encrypt ptext with key2;
+       compare 2 ctexts; expect failure;
+       */
+       CSSM_KEY_PTR    key1;
+       CSSM_KEY_PTR    key2;
+       CSSM_DATA               iv1;
+       CSSM_DATA               iv2;
+       CSSM_DATA_PTR   ivp1;
+       CSSM_DATA_PTR   ivp2;
+       uint32                  mungeDex;
+       uint32                  mungeBits;
+       if(targs->useInitVector) {
+               if(targs->genInitVector) {
+                       ivp1 = &iv1;
+                       ivp2 = &iv2;
+               }
+               else {
+                       staticIv.Length = targs->ivSize;
+                       ivp1 = ivp2 = &staticIv;
+               }
+       }
+       else {
+               ivp1 = ivp2 = NULL;
+       }
+       /* these need to be init'd regardless */
+       iv1.Data = NULL;
+       iv1.Length = 0;
+       iv2.Data = NULL;
+       iv2.Length = 0;
+       key1 = cspDeriveKey(targs->cspHand,
+               targs->deriveAlg,
+               targs->keyAlg,
+               KEY_LABEL1,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_ENCRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,
+               targs->salt,
+               targs->iterCount,
+               &iv1);
+       if(key1 == NULL) {
+               return testError(targs->quiet);
+       }
+       /* munge salt */
+       mungeDex = genRand(0, targs->salt->Length - 1);
+       mungeBits = randBit();
+       targs->salt->Data[mungeDex] ^= mungeBits;
+       key2 = cspDeriveKey(targs->cspHand,
+               targs->deriveAlg,
+               targs->keyAlg,
+               KEY_LABEL2,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_ENCRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,
+               targs->salt,                            // the changed param
+               targs->iterCount,
+               &iv2);
+       if(key2 == NULL) {
+               return testError(targs->quiet);
+       }
+       if(testCommon(targs->cspHand,
+                               "saltTest",
+                               targs->encrAlg,
+                               targs->encrMode,
+                               targs->encrPad,
+                               targs->effectiveKeySizeInBits,
+                               targs->ptext,
+                               key1,
+                               ivp1,
+                               key2,
+                               ivp2,
+                               targs->quiet)) {
+               return 1;
+       }
+       /* restore  */
+       targs->salt->Data[mungeDex] ^= mungeBits;
+       appFreeCssmData(&iv1, CSSM_FALSE);
+       appFreeCssmData(&iv2, CSSM_FALSE);
+       cspFreeKey(targs->cspHand, key1);
+       cspFreeKey(targs->cspHand, key2);
+       CSSM_FREE(key1);
+       CSSM_FREE(key2);
+       return 0;
+}
+
+/* ensure initVector alters ctext. This isn't testing PBE per se, but
+ * it's a handy place to verify this function. */
+static int initVectTest(testArgs *targs)
+{
+       /*
+       generate key1;
+       encrypt ptext with key1 and initVector;
+       encrypt ptext with key1 and munged initVector;
+       compare 2 ctexts; expect failure;
+       */
+       CSSM_KEY_PTR    key1;
+       CSSM_DATA               iv1;
+       CSSM_DATA               iv2;
+       uint32                  mungeDex;
+       uint32                  mungeBits;
+       
+       if(targs->genInitVector) {
+               iv1.Data = NULL;
+               iv1.Length = 0;
+       }
+       else  {
+               iv1 = staticIv;
+       }
+       key1 = cspDeriveKey(targs->cspHand,
+               targs->deriveAlg,
+               targs->keyAlg,
+               KEY_LABEL1,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_ENCRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,
+               targs->salt,
+               targs->iterCount,
+               &iv1);
+       if(key1 == NULL) {
+               return testError(targs->quiet);
+       }
+       
+       /* get munged copy of iv */
+       iv2.Data = (uint8 *)CSSM_MALLOC(iv1.Length);
+       iv2.Length = iv1.Length;
+       memmove(iv2.Data, iv1.Data, iv1.Length);
+       mungeDex = genRand(0, iv1.Length - 1);
+       mungeBits = randBit();
+       iv2.Data[mungeDex] ^= mungeBits;
+       if(testCommon(targs->cspHand,
+                               "initVectTest",
+                               targs->encrAlg,
+                               targs->encrMode,
+                               targs->encrPad,
+                               targs->effectiveKeySizeInBits,
+                               targs->ptext,
+                               key1,
+                               &iv1,
+                               key1,
+                               &iv2,   // the changed param
+                               targs->quiet)) {        
+               return 1;
+       }
+       if(targs->genInitVector) {
+               appFreeCssmData(&iv1, CSSM_FALSE);
+       }
+       appFreeCssmData(&iv2, CSSM_FALSE);
+       cspFreeKey(targs->cspHand, key1);
+       CSSM_FREE(key1);
+       return 0;
+}
+
+#if 0
+/* only one algorithm supported */
+/* ensure deriveAlg alters key */
+static int deriveAlgTest(testArgs *targs)
+{
+       /*
+       generate key1(deriveAlg), key2(some other deriveAlg);
+       encrypt ptext with key1;
+       encrypt ptext with key2;
+       compare 2 ctexts; expect failure;
+       */
+       CSSM_KEY_PTR    key1;
+       CSSM_KEY_PTR    key2;
+       CSSM_DATA       iv1;
+       CSSM_DATA       iv2;
+       CSSM_DATA_PTR   ivp1;
+       CSSM_DATA_PTR   ivp2;
+       uint32          mungeAlg;
+       
+       if(targs->useInitVector) {
+               if(targs->genInitVector) {
+                       ivp1 = &iv1;
+                       ivp2 = &iv2;
+               }
+               else {
+                       staticIv.Length = targs->ivSize;
+                       ivp1 = ivp2 = &staticIv;
+               }
+       }
+       else {
+               ivp1 = ivp2 = NULL;
+       }
+       
+       /* these need to be init'd regardless */
+       iv1.Data = NULL;
+       iv1.Length = 0;
+       iv2.Data = NULL;
+       iv2.Length = 0;
+       key1 = cspDeriveKey(targs->cspHand,
+               targs->deriveAlg,
+               targs->keyAlg,
+               KEY_LABEL1,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_ENCRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,
+               targs->salt,
+               targs->iterCount,
+               &iv1);
+       if(key1 == NULL) {
+               return testError(quiet);
+       }
+       
+       /* munge deriveAlg */
+       switch(targs->deriveAlg) {
+               case CSSM_ALGID_MD5_PBE:
+                       mungeAlg = CSSM_ALGID_MD2_PBE;
+                       break;
+               case CSSM_ALGID_MD2_PBE:
+                       mungeAlg = CSSM_ALGID_SHA1_PBE;
+                       break;
+               case CSSM_ALGID_SHA1_PBE:
+                       mungeAlg = CSSM_ALGID_SHA1_PBE_PKCS12;
+                       break;
+               case CSSM_ALGID_SHA1_PBE_PKCS12:
+                       mungeAlg = CSSM_ALGID_MD5_PBE;
+                       break;
+               default:
+                       printf("BRRRZZZT! Update deriveAlgTest()!\n");
+                       return testError(quiet);
+       }
+       key2 = cspDeriveKey(targs->cspHand,
+               mungeAlg,                               // the changed param
+               targs->keyAlg,
+               KEY_LABEL2,
+               KEY_LABEL_LEN,
+               CSSM_KEYUSE_ENCRYPT,
+               targs->keySizeInBits,
+               targs->useRefKey,
+               targs->password,                        // the changed param
+               targs->salt,
+               targs->iterCount,
+               &iv2);
+       if(key2 == NULL) {
+               return testError(quiet);
+       }
+       if(testCommon(targs->cspHand,
+                       "deriveAlgTest",
+                       targs->encrAlg,
+                       targs->encrMode,
+                       targs->encrPad,
+                       targs->effectiveKeySizeInBits,
+                       targs->ptext,
+                       key1,
+                       ivp1,
+                       key2,
+                       ivp2,
+                       targs->quiet)) {
+               return 1;
+       }
+       appFreeCssmData(&iv1, CSSM_FALSE);
+       appFreeCssmData(&iv2, CSSM_FALSE);
+       cspFreeKey(targs->cspHand, key1);
+       cspFreeKey(targs->cspHand, key2);
+       CSSM_FREE(key1);
+       CSSM_FREE(key2);
+       return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+       int                                     arg;
+       char                            *argp;
+       unsigned                        loop;
+       CSSM_DATA                       ptext;
+       testArgs                        targs;
+       CSSM_DATA                       pwd;
+       CSSM_DATA                       salt;
+       privAlg                         pbeAlg;
+       privAlg                         encrAlg;
+       privAlg                         lastEncrAlg;
+       int                             rtn = 0;
+       CSSM_BOOL                       fooBool;
+       CSSM_BOOL                       refKeysOnly = CSSM_FALSE;
+       int                                     i;
+       
+       /*
+        * User-spec'd params
+        */
+       unsigned        loops = LOOPS_DEF;
+       CSSM_BOOL       quiet = CSSM_FALSE;
+       CSSM_BOOL       doPause = CSSM_FALSE;
+       CSSM_BOOL       doExport = CSSM_FALSE;
+       CSSM_BOOL       repeatOnly = CSSM_FALSE;
+       CSSM_BOOL       bareCsp = CSSM_TRUE;
+       CSSM_BOOL       zeroLenPassword = CSSM_FALSE;
+       
+       #if     macintosh
+       argc = ccommand(&argv);
+       #endif
+       for(arg=1; arg<argc; arg++) {
+               argp = argv[arg];
+               switch(argp[0]) {
+                   case 'l':
+                               loops = atoi(&argp[2]);
+                               break;
+                   case 'q':
+                       quiet = CSSM_TRUE;
+                               break;
+                       case 'D':
+                               bareCsp = CSSM_FALSE;
+                               #if CSPDL_ALL_KEYS_ARE_REF
+                               refKeysOnly = CSSM_TRUE;
+                               #endif
+                               break;
+                   case 'p':
+                       doPause = CSSM_TRUE;
+                               break;
+                       case 'e':
+                               doExport = CSSM_TRUE;
+                               break;
+                       case 'r':
+                               repeatOnly = CSSM_TRUE;
+                               break;
+                       case 'z':
+                               zeroLenPassword = CSSM_TRUE;
+                               break;
+                   case 'h':
+                   default:
+                               usage(argv);
+               }
+       }
+
+       /* statically allocate ptext, password and seed; data and length
+        * change in test loop */
+       pwd.Data = (uint8 *)CSSM_MALLOC(MAX_PASSWORD_SIZE);
+       ptext.Data = (uint8 *)CSSM_MALLOC(MAX_PTEXT_SIZE);
+       salt.Data = (uint8 *)CSSM_MALLOC(MAX_SALT_SIZE);
+       printf("Starting pbeTest; args: ");
+       for(i=1; i<argc; i++) {
+               printf("%s ", argv[i]);
+       }
+       printf("\n");
+       targs.cspHand = cspDlDbStartup(bareCsp, NULL);
+       if(targs.cspHand == 0) {
+               exit(1);
+       }
+       targs.ptext     = &ptext;
+       targs.password  = &pwd;
+       targs.salt              = &salt;
+       targs.quiet     = quiet;
+       if(doExport) {
+               lastEncrAlg = ENCR_ALG_LAST_EXPORT;
+       }
+       else {
+               lastEncrAlg = ENCR_ALG_LAST;
+       }
+       for(loop=1; ; loop++) {
+               if(!quiet) {
+                       printf("...loop %d\n", loop);
+               }
+               /* change once per outer loop */
+               simpleGenData(&ptext, MIN_PTEXT_SIZE, MAX_PTEXT_SIZE);
+               if(zeroLenPassword) {
+                       pwd.Length = 0; // fixed
+               }
+               else {
+                       simpleGenData(&pwd, APPLE_PBE_MIN_PASSWORD, MAX_PASSWORD_SIZE);
+               }
+               simpleGenData(&salt, APPLE_PBE_MIN_SALT, MAX_SALT_SIZE);
+               targs.iterCount = genRand(MIN_ITER_COUNT, MAX_ITER_COUNT);
+               if(refKeysOnly) {
+                       targs.useRefKey = CSSM_TRUE;
+               }
+               else {
+                       targs.useRefKey = (loop & 1) ? CSSM_FALSE : CSSM_TRUE;
+               }
+               
+               for(encrAlg=ENCR_ALG_FIRST; encrAlg<=lastEncrAlg; encrAlg++) {
+                       /* Cook up encryption-related args */
+                       algInfo(encrAlg,
+                               &targs.keyAlg,
+                               &targs.encrAlg,
+                               &targs.encrMode,
+                               &targs.encrPad,
+                               &targs.useInitVector,
+                               &targs.ivSize,
+                               &fooBool,                               // genInitVector
+                               &targs.keyAlgStr);
+                       /* random key size */
+                       targs.effectiveKeySizeInBits = randKeySizeBits(targs.keyAlg, OT_Encrypt);
+                       targs.keySizeInBits = (targs.effectiveKeySizeInBits + 7) & ~7;
+                       if(targs.keySizeInBits == targs.effectiveKeySizeInBits) {
+                               /* same size, ignore effective */
+                               targs.effectiveKeySizeInBits = 0;
+                       }
+                       if(!quiet) {
+                               printf("   ...Encrypt alg %s keySizeInBits %u effectKeySize %u\n",
+                                       targs.keyAlgStr, (unsigned)targs.keySizeInBits,
+                                       (unsigned)targs.effectiveKeySizeInBits);
+                       }
+                       for(pbeAlg=PBE_ALG_FIRST; pbeAlg<=PBE_ALG_LAST; pbeAlg++) {
+                               /* Cook up pbe-related args */
+                               uint32 foo;
+                               algInfo(pbeAlg,
+                                       &targs.deriveAlg,
+                                       &foo,                   // encrAlg
+                                       &foo,                   // mode
+                                       &foo,
+                                       &fooBool,               // useInitVector
+                                       &foo,                   // ivSize
+                                       &targs.genInitVector,
+                                       &targs.deriveAlgStr);
+                               if(!quiet) {
+                                       printf("      ...PBE alg %s\n", targs.deriveAlgStr);
+                               }
+                               /* grind thru the tests */
+                               if(repeatTest(&targs)) {
+                                       rtn = 1;
+                                       goto testDone;
+                               }
+                               if(repeatOnly) {
+                                       continue;
+                               }
+                               if(iterTest(&targs)) {
+                                       rtn = 1;
+                                       goto testDone;
+                               }
+                               #if 0
+                               // not supported yet 
+                               if(deriveAlgTest(&targs)) {
+                                       rtn = 1;
+                                       goto testDone;
+                               }
+                               #endif
+                               if(!zeroLenPassword) {
+                                       /* won't work with zero length password */
+                                       if(passwordTest(&targs)) {
+                                               rtn = 1;
+                                               goto testDone;
+                                       }
+                               }
+                               if(saltTest(&targs)) {
+                                       rtn = 1;
+                                       goto testDone;
+                               }
+                               if(targs.useInitVector) {
+                                       if(initVectTest(&targs)) {
+                                               rtn = 1;
+                                               goto testDone;
+                                       }
+                               }
+                       } /* for pbeAlg */
+               } /* for encrAlg */
+               if(doPause) {
+                       if(testError(quiet)) {
+                               break;
+                       }
+               }
+               if(loops && (loop == loops)) {
+                       break;
+               }
+       } /* for loop */
+       
+testDone:
+       CSSM_ModuleDetach(targs.cspHand);
+       if(!quiet && (rtn == 0)) {
+               printf("%s test complete\n", argv[0]);
+       }
+       return rtn;
+}