1/* Copyright (c) 1998,2003-2005,2008 Apple Inc. 2 * 3 * pbeTest.c - test CSP PBE-style DeriveKey(). 4 * 5 * Revision History 6 * ---------------- 7 * 15 May 2000 Doug Mitchell 8 * Ported to X/CDSA2. 9 * 13 Aug 1998 Doug Mitchell at NeXT 10 * Created. 11 */ 12#include <stdlib.h> 13#include <stdio.h> 14#include <time.h> 15#include <string.h> 16#include <Security/cssm.h> 17#include "cspwrap.h" 18#include "common.h" 19#include "cspdlTesting.h" 20 21/* we need to know a little bit about AES for this test.... */ 22#define AES_BLOCK_SIZE 16 /* bytes */ 23 24/* 25 * Defaults. 26 */ 27#define LOOPS_DEF 10 28#define MIN_PTEXT_SIZE AES_BLOCK_SIZE /* for non-padding tests */ 29#define MAX_PTEXT_SIZE 1000 30#define MAX_PASSWORD_SIZE 64 31#define MAX_SALT_SIZE 32 32#define MIN_ITER_COUNT 1000 33#define MAX_ITER_COUNT 2000 34#define MAX_IV_SIZE AES_BLOCK_SIZE 35 36/* min values not currently exported by CSP */ 37#define APPLE_PBE_MIN_PASSWORD 8 38#define APPLE_PBE_MIN_SALT 8 39 40/* static IV for derive algorithms which don't create one */ 41CSSM_DATA staticIv = {MAX_IV_SIZE, (uint8 *)"someIvOrOther..."}; 42 43/* 44 * Enumerate algs our own way to allow iteration. 45 */ 46typedef unsigned privAlg; 47enum { 48 /* PBE algs */ 49 pbe_pbkdf2 = 1, 50 // other unsupported for now 51 pbe_PKCS12 = 1, 52 pbe_MD5, 53 pbe_MD2, 54 pbe_SHA1, 55 56 /* key gen algs */ 57 pka_ASC, 58 pka_RC4, 59 pka_DES, 60 pka_RC2, 61 pka_RC5, 62 pka_3DES, 63 pka_AES 64}; 65 66#define PBE_ALG_FIRST pbe_pbkdf2 67#define PBE_ALG_LAST pbe_pbkdf2 68#define ENCR_ALG_FIRST pka_ASC 69#define ENCR_ALG_LAST pka_AES 70#define ENCR_ALG_LAST_EXPORT pka_RC5 71 72/* 73 * Args passed to each test 74 */ 75typedef struct { 76 CSSM_CSP_HANDLE cspHand; 77 CSSM_ALGORITHMS keyAlg; 78 CSSM_ALGORITHMS encrAlg; 79 uint32 keySizeInBits; 80 uint32 effectiveKeySizeInBits; // 0 means not used 81 const char *keyAlgStr; 82 CSSM_ENCRYPT_MODE encrMode; 83 CSSM_PADDING encrPad; 84 CSSM_ALGORITHMS deriveAlg; 85 const char *deriveAlgStr; 86 CSSM_DATA_PTR ptext; 87 CSSM_DATA_PTR password; 88 CSSM_DATA_PTR salt; 89 uint32 iterCount; 90 CSSM_BOOL useInitVector; // encrypt needs an IV 91 uint32 ivSize; 92 CSSM_BOOL genInitVector; // DeriveKey generates an IV 93 CSSM_BOOL useRefKey; 94 CSSM_BOOL quiet; 95} testArgs; 96 97static void usage(char **argv) 98{ 99 printf("usage: %s [options]\n", argv[0]); 100 printf(" Options:\n"); 101 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF); 102 printf(" e(xport)\n"); 103 printf(" r(epeatOnly)\n"); 104 printf(" z(ero length password)\n"); 105 printf(" p(ause after each loop)\n"); 106 printf(" D (CSP/DL; default = bare CSP)\n"); 107 printf(" q(uiet)\n"); 108 printf(" h(elp)\n"); 109 exit(1); 110} 111 112/* 113 * Given a privAlg value, return various associated stuff. 114 */ 115static void algInfo(privAlg alg, // pbe_MD5, etc. 116 CSSM_ALGORITHMS *cdsaAlg, // CSSM_ALGID_MD5_PBE, etc. RETURNED 117 // key alg for key gen algs 118 CSSM_ALGORITHMS *encrAlg, // encrypt/decrypt alg for key 119 // gen algs 120 CSSM_ENCRYPT_MODE *mode, // RETURNED 121 CSSM_PADDING *padding, // RETURNED 122 CSSM_BOOL *useInitVector, // RETURNED, for encrypt/decrypt 123 uint32 *ivSize, // RETURNED, in bytes 124 CSSM_BOOL *genInitVector, // RETURNED, for deriveKey 125 const char **algStr) // RETURNED 126{ 127 /* default or irrelevant fields */ 128 *mode = CSSM_ALGMODE_NONE; 129 *useInitVector = CSSM_FALSE; 130 *genInitVector = CSSM_FALSE; // DeriveKey doesn't do this now 131 *padding = CSSM_PADDING_PKCS1; 132 *ivSize = 8; // thje usual size, if needed 133 *encrAlg = CSSM_ALGID_NONE; 134 135 switch(alg) { 136 case pbe_pbkdf2: 137 *cdsaAlg = CSSM_ALGID_PKCS5_PBKDF2; 138 *algStr = "PBKDF2"; 139 return; 140 /* these are not supported */ 141 #if 0 142 case pbe_PKCS12: 143 *cdsaAlg = CSSM_ALGID_SHA1_PBE_PKCS12; 144 *algStr = "PKCS12"; 145 return; 146 case pbe_MD5: 147 *cdsaAlg = CSSM_ALGID_MD5_PBE; 148 *algStr = "MD5"; 149 return; 150 case pbe_MD2: 151 *cdsaAlg = CSSM_ALGID_MD2_PBE; 152 *algStr = "MD2"; 153 return; 154 case pbe_SHA1: 155 *cdsaAlg = CSSM_ALGID_SHA1_PBE; 156 *algStr = "SHA1"; 157 return; 158 case pka_ASC: 159 *cdsaAlg = CSSM_ALGID_ASC; 160 *algStr = "ASC"; 161 return; 162 #endif 163 case pka_DES: 164 *cdsaAlg = *encrAlg = CSSM_ALGID_DES; 165 *useInitVector = CSSM_TRUE; 166 *mode = CSSM_ALGMODE_CBCPadIV8; 167 *algStr = "DES"; 168 return; 169 case pka_3DES: 170 *cdsaAlg = CSSM_ALGID_3DES_3KEY; 171 *encrAlg = CSSM_ALGID_3DES_3KEY_EDE; 172 *useInitVector = CSSM_TRUE; 173 *mode = CSSM_ALGMODE_CBCPadIV8; 174 *algStr = "3DES"; 175 return; 176 case pka_AES: 177 *cdsaAlg = *encrAlg = CSSM_ALGID_AES; 178 *useInitVector = CSSM_TRUE; 179 *mode = CSSM_ALGMODE_CBCPadIV8; 180 *padding = CSSM_PADDING_PKCS5; 181 *ivSize = AES_BLOCK_SIZE; // per the default block size 182 *algStr = "AES"; 183 return; 184 case pka_RC2: 185 *cdsaAlg = *encrAlg = CSSM_ALGID_RC2; 186 *useInitVector = CSSM_TRUE; 187 *mode = CSSM_ALGMODE_CBCPadIV8; 188 *algStr = "RC2"; 189 return; 190 case pka_RC4: 191 *cdsaAlg = *encrAlg = CSSM_ALGID_RC4; 192 /* initVector false */ 193 *mode = CSSM_ALGMODE_NONE; 194 *algStr = "RC4"; 195 return; 196 case pka_RC5: 197 *cdsaAlg = *encrAlg = CSSM_ALGID_RC5; 198 *algStr = "RC5"; 199 *mode = CSSM_ALGMODE_CBCPadIV8; 200 *useInitVector = CSSM_TRUE; 201 return; 202 case pka_ASC: 203 *cdsaAlg = *encrAlg = CSSM_ALGID_ASC; 204 /* initVector false */ 205 *algStr = "ASC"; 206 *mode = CSSM_ALGMODE_NONE; 207 return; 208 default: 209 printf("BRRZZZT! Update algInfo()!\n"); 210 testError(CSSM_TRUE); 211 } 212} 213 214/* a handy "compare two CSSM_DATAs" ditty */ 215static CSSM_BOOL compareData(const CSSM_DATA_PTR d1, 216 const CSSM_DATA_PTR d2) 217{ 218 if(d1->Length != d2->Length) { 219 return CSSM_FALSE; 220 } 221 if(memcmp(d1->Data, d2->Data, d1->Length)) { 222 return CSSM_FALSE; 223 } 224 return CSSM_TRUE; 225} 226 227/* generate random one-bit byte */ 228static uint8 randBit() 229{ 230 return 1 << genRand(0, 7); 231} 232 233/* 234 * Writer debug - assertion failure when ctext[1].Data is NULL 235 * but length is nonzero 236 */ 237#define SAFE_CTEXT_ARRAY 0 238 239/* 240 * Encrypt ptext using specified key, IV, effectiveKeySizeInBits 241 */ 242static int encryptCom(CSSM_CSP_HANDLE cspHand, 243 const char *testName, 244 CSSM_DATA_PTR ptext, 245 CSSM_KEY_PTR key, 246 CSSM_ALGORITHMS alg, 247 CSSM_ENCRYPT_MODE mode, 248 CSSM_PADDING padding, // CSSM_PADDING_PKCS1, etc. 249 CSSM_DATA_PTR iv, // may be NULL 250 uint32 effectiveKeySizeInBits, // may be 0 251 CSSM_DATA_PTR ctext, // RETURNED 252 CSSM_BOOL quiet) 253{ 254 CSSM_CC_HANDLE cryptHand; 255 CSSM_RETURN crtn; 256 CSSM_SIZE bytesEncrypted; 257 CSSM_DATA remData; 258 int rtn; 259 #if SAFE_CTEXT_ARRAY 260 CSSM_DATA safeCtext[2]; 261 safeCtext[0] = *ctext; 262 safeCtext[1].Data = NULL; 263 safeCtext[1].Length = 10; // lie, but shouldn't use this! 264 #else 265 // printf("+++ ctext[0] = %d:0x%x; ctext[1] = %d:0x%x\n", 266 // ctext[0].Length, ctext[0].Data, 267 // ctext[1].Length, ctext[1].Data); 268 #endif 269 270 cryptHand = genCryptHandle(cspHand, 271 alg, 272 mode, 273 padding, 274 key, 275 NULL, // no 2nd key 276 iv, // InitVector 277 effectiveKeySizeInBits, 278 0); // rounds 279 if(cryptHand == 0) { 280 return testError(quiet); 281 } 282 283 remData.Data = NULL; 284 remData.Length = 0; 285 crtn = CSSM_EncryptData(cryptHand, 286 ptext, 287 1, 288 #if SAFE_CTEXT_ARRAY 289 &safeCtext[0], 290 #else 291 ctext, 292 #endif 293 1, 294 &bytesEncrypted, 295 &remData); 296 #if SAFE_CTEXT_ARRAY 297 *ctext = safeCtext[0]; 298 #endif 299 300 if(crtn) { 301 printError("CSSM_EncryptData", crtn); 302 rtn = testError(quiet); 303 goto done; 304 } 305 if(remData.Length != 0) { 306 //printf("***WARNING: nonzero remData on encrypt!\n"); 307 /* new for CDSA2 - possible remData even if we ask the CSP to 308 * malloc ctext */ 309 ctext->Data = (uint8 *)appRealloc(ctext->Data, bytesEncrypted, NULL); 310 memmove(ctext->Data + ctext->Length, 311 remData.Data, 312 bytesEncrypted - ctext->Length); 313 appFreeCssmData(&remData, CSSM_FALSE); 314 } 315 /* new for CDSA 2 */ 316 ctext->Length = bytesEncrypted; 317 rtn = 0; 318done: 319 if(CSSM_DeleteContext(cryptHand)) { 320 printError("CSSM_DeleteContext", 0); 321 rtn = 1; 322 } 323 return rtn; 324} 325 326/* 327 * Decrypt ctext using specified key, IV, effectiveKeySizeInBits 328 */ 329static int decryptCom(CSSM_CSP_HANDLE cspHand, 330 const char *testName, 331 CSSM_DATA_PTR ctext, 332 CSSM_KEY_PTR key, 333 CSSM_ALGORITHMS alg, 334 CSSM_ENCRYPT_MODE mode, 335 CSSM_PADDING padding, 336 CSSM_DATA_PTR iv, // may be NULL 337 uint32 effectiveKeySizeInBits, // may be 0 338 CSSM_DATA_PTR ptext, // RETURNED 339 CSSM_BOOL quiet) 340{ 341 CSSM_CC_HANDLE cryptHand; 342 CSSM_RETURN crtn; 343 CSSM_SIZE bytesDecrypted; 344 CSSM_DATA remData; 345 int rtn; 346 347 cryptHand = genCryptHandle(cspHand, 348 alg, 349 mode, 350 padding, 351 key, 352 NULL, // no 2nd key 353 iv, // InitVector 354 effectiveKeySizeInBits, 355 0); // rounds 356 if(cryptHand == 0) { 357 return testError(quiet); 358 } 359 remData.Data = NULL; 360 remData.Length = 0; 361 crtn = CSSM_DecryptData(cryptHand, 362 ctext, 363 1, 364 ptext, 365 1, 366 &bytesDecrypted, 367 &remData); 368 if(crtn) { 369 printError("CSSM_DecryptData", crtn); 370 rtn = testError(quiet); 371 goto done; 372 } 373 if(remData.Length != 0) { 374 //printf("***WARNING: nonzero remData on decrypt!\n"); 375 /* new for CDSA2 - possible remData even if we ask the CSP to 376 * malloc ptext */ 377 ptext->Data = (uint8 *)appRealloc(ptext->Data, bytesDecrypted, NULL); 378 memmove(ptext->Data + ptext->Length, 379 remData.Data, 380 bytesDecrypted - ptext->Length); 381 appFreeCssmData(&remData, CSSM_FALSE); 382 } 383 /* new for CDSA 2 */ 384 ptext->Length = bytesDecrypted; 385 rtn = 0; 386done: 387 if(CSSM_DeleteContext(cryptHand)) { 388 printError("CSSM_DeleteContext", 0); 389 rtn = 1; 390 } 391 return rtn; 392} 393 394/* 395 * Common test portion 396 * encrypt ptext with key1, iv1 397 * encrypt ptext with key2, iv2 398 * compare 2 ctexts; expect failure; 399 */ 400 401#define TRAP_WRITER_ERR 1 402 403static int testCommon(CSSM_CSP_HANDLE cspHand, 404 const char *testName, 405 CSSM_ALGORITHMS encrAlg, 406 CSSM_ENCRYPT_MODE encrMode, 407 CSSM_PADDING encrPad, 408 uint32 effectiveKeySizeInBits, 409 CSSM_DATA_PTR ptext, 410 CSSM_KEY_PTR key1, 411 CSSM_DATA_PTR iv1, 412 CSSM_KEY_PTR key2, 413 CSSM_DATA_PTR iv2, 414 CSSM_BOOL quiet) 415{ 416 CSSM_DATA ctext1; 417 CSSM_DATA ctext2; 418 ctext1.Data = NULL; 419 ctext1.Length = 0; 420 ctext2.Data = NULL; 421 ctext2.Length = 0; 422 if(encryptCom(cspHand, 423 testName, 424 ptext, 425 key1, 426 encrAlg, 427 encrMode, 428 encrPad, 429 iv1, 430 effectiveKeySizeInBits, 431 &ctext1, 432 quiet)) { 433 return 1; 434 } 435 #if TRAP_WRITER_ERR 436 if(ctext2.Data != NULL){ 437 printf("Hey! encryptCom(ptext, ctext1 modified ctext2!\n"); 438 if(testError(quiet)) { 439 return 1; 440 } 441 } 442 #endif 443 if(encryptCom(cspHand, 444 testName, 445 ptext, 446 key2, 447 encrAlg, 448 encrMode, 449 encrPad, 450 iv2, 451 effectiveKeySizeInBits, 452 &ctext2, 453 quiet)) { 454 return 1; 455 } 456 if(compareData(&ctext1, &ctext2)) { 457 printf("***%s: Unexpected Data compare!\n", testName); 458 return testError(quiet); 459 } 460 appFreeCssmData(&ctext1, CSSM_FALSE); 461 appFreeCssmData(&ctext2, CSSM_FALSE); 462 return 0; 463} 464 465/** 466 ** inidividual tests. 467 **/ 468#define KEY_LABEL1 "noLabel1" 469#define KEY_LABEL2 "noLabel2" 470#define KEY_LABEL_LEN strlen(KEY_LABEL1) 471#define REPEAT_ON_ERROR 1 472 473/* test repeatability - the only test here which actually decrypts */ 474static int repeatTest(testArgs *targs) 475{ 476 /* 477 generate two keys with same params; 478 encrypt ptext with key1; 479 decrypt ctext with key2; 480 compare; expect success; 481 */ 482 CSSM_KEY_PTR key1; 483 CSSM_KEY_PTR key2; 484 CSSM_DATA iv1; 485 CSSM_DATA iv2; 486 CSSM_DATA_PTR ivp1; 487 CSSM_DATA_PTR ivp2; 488 CSSM_DATA ctext; 489 CSSM_DATA rptext; 490 CSSM_BOOL gotErr = CSSM_FALSE; 491 492 if(targs->useInitVector) { 493 if(targs->genInitVector) { 494 ivp1 = &iv1; 495 ivp2 = &iv2; 496 } 497 else { 498 staticIv.Length = targs->ivSize; 499 ivp1 = ivp2 = &staticIv; 500 } 501 } 502 else { 503 ivp1 = ivp2 = NULL; 504 } 505 /* these need to be init'd regardless */ 506 iv1.Data = NULL; 507 iv1.Length = 0; 508 iv2.Data = NULL; 509 iv2.Length = 0; 510 ctext.Data = NULL; 511 ctext.Length = 0; 512 rptext.Data = NULL; 513 rptext.Length = 0; 514repeatDerive: 515 key1 = cspDeriveKey(targs->cspHand, 516 targs->deriveAlg, 517 targs->keyAlg, 518 KEY_LABEL1, 519 KEY_LABEL_LEN, 520 CSSM_KEYUSE_ENCRYPT, 521 targs->keySizeInBits, 522 targs->useRefKey, 523 targs->password, 524 targs->salt, 525 targs->iterCount, 526 &iv1); 527 if(key1 == NULL) { 528 return testError(targs->quiet); 529 } 530 key2 = cspDeriveKey(targs->cspHand, 531 targs->deriveAlg, 532 targs->keyAlg, 533 KEY_LABEL2, 534 KEY_LABEL_LEN, 535 CSSM_KEYUSE_DECRYPT, 536 targs->keySizeInBits, 537 targs->useRefKey, 538 targs->password, 539 targs->salt, 540 targs->iterCount, 541 &iv2); 542 if(key2 == NULL) { 543 return testError(targs->quiet); 544 } 545repeatEnc: 546 if(encryptCom(targs->cspHand, 547 "repeatTest", 548 targs->ptext, 549 key1, 550 targs->encrAlg, 551 targs->encrMode, 552 targs->encrPad, 553 ivp1, 554 targs->effectiveKeySizeInBits, 555 &ctext, 556 targs->quiet)) { 557 return 1; 558 } 559 if(decryptCom(targs->cspHand, 560 "repeatTest", 561 &ctext, 562 key2, 563 targs->encrAlg, 564 targs->encrMode, 565 targs->encrPad, 566 ivp2, 567 targs->effectiveKeySizeInBits, 568 &rptext, 569 targs->quiet)) { 570 return 1; 571 } 572 if(gotErr || !compareData(targs->ptext, &rptext)) { 573 printf("***Data miscompare in repeatTest\n"); 574 if(REPEAT_ON_ERROR) { 575 char str; 576 577 gotErr = CSSM_TRUE; 578 fpurge(stdin); 579 printf("Repeat enc/dec (r), repeat derive (d), continue (c), abort (any)? "); 580 str = getchar(); 581 switch(str) { 582 case 'r': 583 appFreeCssmData(&ctext, CSSM_FALSE); 584 appFreeCssmData(&rptext, CSSM_FALSE); 585 goto repeatEnc; 586 case 'd': 587 appFreeCssmData(&ctext, CSSM_FALSE); 588 appFreeCssmData(&rptext, CSSM_FALSE); 589 appFreeCssmData(&iv1, CSSM_FALSE); 590 appFreeCssmData(&iv2, CSSM_FALSE); 591 cspFreeKey(targs->cspHand, key1); 592 cspFreeKey(targs->cspHand, key2); 593 goto repeatDerive; 594 case 'c': 595 break; 596 default: 597 return 1; 598 } 599 } 600 else { 601 return testError(targs->quiet); 602 } 603 } 604 appFreeCssmData(&ctext, CSSM_FALSE); 605 appFreeCssmData(&rptext, CSSM_FALSE); 606 appFreeCssmData(&iv1, CSSM_FALSE); 607 appFreeCssmData(&iv2, CSSM_FALSE); 608 cspFreeKey(targs->cspHand, key1); 609 cspFreeKey(targs->cspHand, key2); 610 CSSM_FREE(key1); 611 CSSM_FREE(key2); 612 return 0; 613} 614 615/* ensure iterCount alters key */ 616static int iterTest(testArgs *targs) 617{ 618 /* 619 generate key1(iterCount), key2(iterCount+1); 620 encrypt ptext with key1; 621 encrypt ptext with key2; 622 compare 2 ctexts; expect failure; 623 */ 624 CSSM_KEY_PTR key1; 625 CSSM_KEY_PTR key2; 626 CSSM_DATA iv1; 627 CSSM_DATA iv2; 628 CSSM_DATA_PTR ivp1; 629 CSSM_DATA_PTR ivp2; 630 if(targs->useInitVector) { 631 if(targs->genInitVector) { 632 ivp1 = &iv1; 633 ivp2 = &iv2; 634 } 635 else { 636 staticIv.Length = targs->ivSize; 637 ivp1 = ivp2 = &staticIv; 638 } 639 } 640 else { 641 ivp1 = ivp2 = NULL; 642 } 643 /* these need to be init'd regardless */ 644 iv1.Data = NULL; 645 iv1.Length = 0; 646 iv2.Data = NULL; 647 iv2.Length = 0; 648 key1 = cspDeriveKey(targs->cspHand, 649 targs->deriveAlg, 650 targs->keyAlg, 651 KEY_LABEL1, 652 KEY_LABEL_LEN, 653 CSSM_KEYUSE_ENCRYPT, 654 targs->keySizeInBits, 655 targs->useRefKey, 656 targs->password, 657 targs->salt, 658 targs->iterCount, 659 &iv1); 660 if(key1 == NULL) { 661 return testError(targs->quiet); 662 } 663 key2 = cspDeriveKey(targs->cspHand, 664 targs->deriveAlg, 665 targs->keyAlg, 666 KEY_LABEL2, 667 KEY_LABEL_LEN, 668 CSSM_KEYUSE_ENCRYPT, 669 targs->keySizeInBits, 670 targs->useRefKey, 671 targs->password, 672 targs->salt, 673 targs->iterCount + 1, // the changed param 674 &iv2); 675 if(key2 == NULL) { 676 return testError(targs->quiet); 677 } 678 if(testCommon(targs->cspHand, 679 "iterTest", 680 targs->encrAlg, 681 targs->encrMode, 682 targs->encrPad, 683 targs->effectiveKeySizeInBits, 684 targs->ptext, 685 key1, 686 ivp1, 687 key2, 688 ivp2, 689 targs->quiet)) { 690 return 1; 691 } 692 appFreeCssmData(&iv1, CSSM_FALSE); 693 appFreeCssmData(&iv2, CSSM_FALSE); 694 cspFreeKey(targs->cspHand, key1); 695 cspFreeKey(targs->cspHand, key2); 696 CSSM_FREE(key1); 697 CSSM_FREE(key2); 698 return 0; 699} 700 701/* ensure password alters key */ 702static int passwordTest(testArgs *targs) 703{ 704 /* 705 generate key1(password), key2(munged password); 706 encrypt ptext with key1; 707 encrypt ptext with key2; 708 compare 2 ctexts; expect failure; 709 */ 710 CSSM_KEY_PTR key1; 711 CSSM_KEY_PTR key2; 712 CSSM_DATA iv1; 713 CSSM_DATA iv2; 714 CSSM_DATA_PTR ivp1; 715 CSSM_DATA_PTR ivp2; 716 uint32 mungeDex; 717 uint32 mungeBits; 718 if(targs->useInitVector) { 719 if(targs->genInitVector) { 720 ivp1 = &iv1; 721 ivp2 = &iv2; 722 } 723 else { 724 staticIv.Length = targs->ivSize; 725 ivp1 = ivp2 = &staticIv; 726 } 727 } 728 else { 729 ivp1 = ivp2 = NULL; 730 } 731 /* these need to be init'd regardless */ 732 iv1.Data = NULL; 733 iv1.Length = 0; 734 iv2.Data = NULL; 735 iv2.Length = 0; 736 key1 = cspDeriveKey(targs->cspHand, 737 targs->deriveAlg, 738 targs->keyAlg, 739 KEY_LABEL1, 740 KEY_LABEL_LEN, 741 CSSM_KEYUSE_ENCRYPT, 742 targs->keySizeInBits, 743 targs->useRefKey, 744 targs->password, 745 targs->salt, 746 targs->iterCount, 747 &iv1); 748 if(key1 == NULL) { 749 return testError(targs->quiet); 750 } 751 /* munge password */ 752 mungeDex = genRand(0, targs->password->Length - 1); 753 mungeBits = randBit(); 754 targs->password->Data[mungeDex] ^= mungeBits; 755 key2 = cspDeriveKey(targs->cspHand, 756 targs->deriveAlg, 757 targs->keyAlg, 758 KEY_LABEL2, 759 KEY_LABEL_LEN, 760 CSSM_KEYUSE_ENCRYPT, 761 targs->keySizeInBits, 762 targs->useRefKey, 763 targs->password, // the changed param 764 targs->salt, 765 targs->iterCount, 766 &iv2); 767 if(key2 == NULL) { 768 return testError(targs->quiet); 769 } 770 if(testCommon(targs->cspHand, 771 "passwordTest", 772 targs->encrAlg, 773 targs->encrMode, 774 targs->encrPad, 775 targs->effectiveKeySizeInBits, 776 targs->ptext, 777 key1, 778 ivp1, 779 key2, 780 ivp2, 781 targs->quiet)) { 782 return 1; 783 } 784 /* restore */ 785 targs->password->Data[mungeDex] ^= mungeBits; 786 appFreeCssmData(&iv1, CSSM_FALSE); 787 appFreeCssmData(&iv2, CSSM_FALSE); 788 cspFreeKey(targs->cspHand, key1); 789 cspFreeKey(targs->cspHand, key2); 790 CSSM_FREE(key1); 791 CSSM_FREE(key2); 792 return 0; 793} 794 795/* ensure salt alters key */ 796static int saltTest(testArgs *targs) 797{ 798 /* 799 generate key1(seed), key2(munged seed); 800 encrypt ptext with key1; 801 encrypt ptext with key2; 802 compare 2 ctexts; expect failure; 803 */ 804 CSSM_KEY_PTR key1; 805 CSSM_KEY_PTR key2; 806 CSSM_DATA iv1; 807 CSSM_DATA iv2; 808 CSSM_DATA_PTR ivp1; 809 CSSM_DATA_PTR ivp2; 810 uint32 mungeDex; 811 uint32 mungeBits; 812 if(targs->useInitVector) { 813 if(targs->genInitVector) { 814 ivp1 = &iv1; 815 ivp2 = &iv2; 816 } 817 else { 818 staticIv.Length = targs->ivSize; 819 ivp1 = ivp2 = &staticIv; 820 } 821 } 822 else { 823 ivp1 = ivp2 = NULL; 824 } 825 /* these need to be init'd regardless */ 826 iv1.Data = NULL; 827 iv1.Length = 0; 828 iv2.Data = NULL; 829 iv2.Length = 0; 830 key1 = cspDeriveKey(targs->cspHand, 831 targs->deriveAlg, 832 targs->keyAlg, 833 KEY_LABEL1, 834 KEY_LABEL_LEN, 835 CSSM_KEYUSE_ENCRYPT, 836 targs->keySizeInBits, 837 targs->useRefKey, 838 targs->password, 839 targs->salt, 840 targs->iterCount, 841 &iv1); 842 if(key1 == NULL) { 843 return testError(targs->quiet); 844 } 845 /* munge salt */ 846 mungeDex = genRand(0, targs->salt->Length - 1); 847 mungeBits = randBit(); 848 targs->salt->Data[mungeDex] ^= mungeBits; 849 key2 = cspDeriveKey(targs->cspHand, 850 targs->deriveAlg, 851 targs->keyAlg, 852 KEY_LABEL2, 853 KEY_LABEL_LEN, 854 CSSM_KEYUSE_ENCRYPT, 855 targs->keySizeInBits, 856 targs->useRefKey, 857 targs->password, 858 targs->salt, // the changed param 859 targs->iterCount, 860 &iv2); 861 if(key2 == NULL) { 862 return testError(targs->quiet); 863 } 864 if(testCommon(targs->cspHand, 865 "saltTest", 866 targs->encrAlg, 867 targs->encrMode, 868 targs->encrPad, 869 targs->effectiveKeySizeInBits, 870 targs->ptext, 871 key1, 872 ivp1, 873 key2, 874 ivp2, 875 targs->quiet)) { 876 return 1; 877 } 878 /* restore */ 879 targs->salt->Data[mungeDex] ^= mungeBits; 880 appFreeCssmData(&iv1, CSSM_FALSE); 881 appFreeCssmData(&iv2, CSSM_FALSE); 882 cspFreeKey(targs->cspHand, key1); 883 cspFreeKey(targs->cspHand, key2); 884 CSSM_FREE(key1); 885 CSSM_FREE(key2); 886 return 0; 887} 888 889/* ensure initVector alters ctext. This isn't testing PBE per se, but 890 * it's a handy place to verify this function. */ 891static int initVectTest(testArgs *targs) 892{ 893 /* 894 generate key1; 895 encrypt ptext with key1 and initVector; 896 encrypt ptext with key1 and munged initVector; 897 compare 2 ctexts; expect failure; 898 */ 899 CSSM_KEY_PTR key1; 900 CSSM_DATA iv1; 901 CSSM_DATA iv2; 902 uint32 mungeDex; 903 uint32 mungeBits; 904 905 if(targs->genInitVector) { 906 iv1.Data = NULL; 907 iv1.Length = 0; 908 } 909 else { 910 iv1 = staticIv; 911 } 912 key1 = cspDeriveKey(targs->cspHand, 913 targs->deriveAlg, 914 targs->keyAlg, 915 KEY_LABEL1, 916 KEY_LABEL_LEN, 917 CSSM_KEYUSE_ENCRYPT, 918 targs->keySizeInBits, 919 targs->useRefKey, 920 targs->password, 921 targs->salt, 922 targs->iterCount, 923 &iv1); 924 if(key1 == NULL) { 925 return testError(targs->quiet); 926 } 927 928 /* get munged copy of iv */ 929 iv2.Data = (uint8 *)CSSM_MALLOC(iv1.Length); 930 iv2.Length = iv1.Length; 931 memmove(iv2.Data, iv1.Data, iv1.Length); 932 mungeDex = genRand(0, iv1.Length - 1); 933 mungeBits = randBit(); 934 iv2.Data[mungeDex] ^= mungeBits; 935 if(testCommon(targs->cspHand, 936 "initVectTest", 937 targs->encrAlg, 938 targs->encrMode, 939 targs->encrPad, 940 targs->effectiveKeySizeInBits, 941 targs->ptext, 942 key1, 943 &iv1, 944 key1, 945 &iv2, // the changed param 946 targs->quiet)) { 947 return 1; 948 } 949 if(targs->genInitVector) { 950 appFreeCssmData(&iv1, CSSM_FALSE); 951 } 952 appFreeCssmData(&iv2, CSSM_FALSE); 953 cspFreeKey(targs->cspHand, key1); 954 CSSM_FREE(key1); 955 return 0; 956} 957 958#if 0 959/* only one algorithm supported */ 960/* ensure deriveAlg alters key */ 961static int deriveAlgTest(testArgs *targs) 962{ 963 /* 964 generate key1(deriveAlg), key2(some other deriveAlg); 965 encrypt ptext with key1; 966 encrypt ptext with key2; 967 compare 2 ctexts; expect failure; 968 */ 969 CSSM_KEY_PTR key1; 970 CSSM_KEY_PTR key2; 971 CSSM_DATA iv1; 972 CSSM_DATA iv2; 973 CSSM_DATA_PTR ivp1; 974 CSSM_DATA_PTR ivp2; 975 uint32 mungeAlg; 976 977 if(targs->useInitVector) { 978 if(targs->genInitVector) { 979 ivp1 = &iv1; 980 ivp2 = &iv2; 981 } 982 else { 983 staticIv.Length = targs->ivSize; 984 ivp1 = ivp2 = &staticIv; 985 } 986 } 987 else { 988 ivp1 = ivp2 = NULL; 989 } 990 991 /* these need to be init'd regardless */ 992 iv1.Data = NULL; 993 iv1.Length = 0; 994 iv2.Data = NULL; 995 iv2.Length = 0; 996 key1 = cspDeriveKey(targs->cspHand, 997 targs->deriveAlg, 998 targs->keyAlg, 999 KEY_LABEL1, 1000 KEY_LABEL_LEN, 1001 CSSM_KEYUSE_ENCRYPT, 1002 targs->keySizeInBits, 1003 targs->useRefKey, 1004 targs->password, 1005 targs->salt, 1006 targs->iterCount, 1007 &iv1); 1008 if(key1 == NULL) { 1009 return testError(quiet); 1010 } 1011 1012 /* munge deriveAlg */ 1013 switch(targs->deriveAlg) { 1014 case CSSM_ALGID_MD5_PBE: 1015 mungeAlg = CSSM_ALGID_MD2_PBE; 1016 break; 1017 case CSSM_ALGID_MD2_PBE: 1018 mungeAlg = CSSM_ALGID_SHA1_PBE; 1019 break; 1020 case CSSM_ALGID_SHA1_PBE: 1021 mungeAlg = CSSM_ALGID_SHA1_PBE_PKCS12; 1022 break; 1023 case CSSM_ALGID_SHA1_PBE_PKCS12: 1024 mungeAlg = CSSM_ALGID_MD5_PBE; 1025 break; 1026 default: 1027 printf("BRRRZZZT! Update deriveAlgTest()!\n"); 1028 return testError(quiet); 1029 } 1030 key2 = cspDeriveKey(targs->cspHand, 1031 mungeAlg, // the changed param 1032 targs->keyAlg, 1033 KEY_LABEL2, 1034 KEY_LABEL_LEN, 1035 CSSM_KEYUSE_ENCRYPT, 1036 targs->keySizeInBits, 1037 targs->useRefKey, 1038 targs->password, // the changed param 1039 targs->salt, 1040 targs->iterCount, 1041 &iv2); 1042 if(key2 == NULL) { 1043 return testError(quiet); 1044 } 1045 if(testCommon(targs->cspHand, 1046 "deriveAlgTest", 1047 targs->encrAlg, 1048 targs->encrMode, 1049 targs->encrPad, 1050 targs->effectiveKeySizeInBits, 1051 targs->ptext, 1052 key1, 1053 ivp1, 1054 key2, 1055 ivp2, 1056 targs->quiet)) { 1057 return 1; 1058 } 1059 appFreeCssmData(&iv1, CSSM_FALSE); 1060 appFreeCssmData(&iv2, CSSM_FALSE); 1061 cspFreeKey(targs->cspHand, key1); 1062 cspFreeKey(targs->cspHand, key2); 1063 CSSM_FREE(key1); 1064 CSSM_FREE(key2); 1065 return 0; 1066} 1067#endif 1068 1069int main(int argc, char **argv) 1070{ 1071 int arg; 1072 char *argp; 1073 unsigned loop; 1074 CSSM_DATA ptext; 1075 testArgs targs; 1076 CSSM_DATA pwd; 1077 CSSM_DATA salt; 1078 privAlg pbeAlg; 1079 privAlg encrAlg; 1080 privAlg lastEncrAlg; 1081 int rtn = 0; 1082 CSSM_BOOL fooBool; 1083 CSSM_BOOL refKeysOnly = CSSM_FALSE; 1084 int i; 1085 1086 /* 1087 * User-spec'd params 1088 */ 1089 unsigned loops = LOOPS_DEF; 1090 CSSM_BOOL quiet = CSSM_FALSE; 1091 CSSM_BOOL doPause = CSSM_FALSE; 1092 CSSM_BOOL doExport = CSSM_FALSE; 1093 CSSM_BOOL repeatOnly = CSSM_FALSE; 1094 CSSM_BOOL bareCsp = CSSM_TRUE; 1095 CSSM_BOOL zeroLenPassword = CSSM_FALSE; 1096 1097 #if macintosh 1098 argc = ccommand(&argv); 1099 #endif 1100 for(arg=1; arg<argc; arg++) { 1101 argp = argv[arg]; 1102 switch(argp[0]) { 1103 case 'l': 1104 loops = atoi(&argp[2]); 1105 break; 1106 case 'q': 1107 quiet = CSSM_TRUE; 1108 break; 1109 case 'D': 1110 bareCsp = CSSM_FALSE; 1111 #if CSPDL_ALL_KEYS_ARE_REF 1112 refKeysOnly = CSSM_TRUE; 1113 #endif 1114 break; 1115 case 'p': 1116 doPause = CSSM_TRUE; 1117 break; 1118 case 'e': 1119 doExport = CSSM_TRUE; 1120 break; 1121 case 'r': 1122 repeatOnly = CSSM_TRUE; 1123 break; 1124 case 'z': 1125 zeroLenPassword = CSSM_TRUE; 1126 break; 1127 case 'h': 1128 default: 1129 usage(argv); 1130 } 1131 } 1132 1133 /* statically allocate ptext, password and seed; data and length 1134 * change in test loop */ 1135 pwd.Data = (uint8 *)CSSM_MALLOC(MAX_PASSWORD_SIZE); 1136 ptext.Data = (uint8 *)CSSM_MALLOC(MAX_PTEXT_SIZE); 1137 salt.Data = (uint8 *)CSSM_MALLOC(MAX_SALT_SIZE); 1138 printf("Starting pbeTest; args: "); 1139 for(i=1; i<argc; i++) { 1140 printf("%s ", argv[i]); 1141 } 1142 printf("\n"); 1143 targs.cspHand = cspDlDbStartup(bareCsp, NULL); 1144 if(targs.cspHand == 0) { 1145 exit(1); 1146 } 1147 targs.ptext = &ptext; 1148 targs.password = &pwd; 1149 targs.salt = &salt; 1150 targs.quiet = quiet; 1151 if(doExport) { 1152 lastEncrAlg = ENCR_ALG_LAST_EXPORT; 1153 } 1154 else { 1155 lastEncrAlg = ENCR_ALG_LAST; 1156 } 1157 for(loop=1; ; loop++) { 1158 if(!quiet) { 1159 printf("...loop %d\n", loop); 1160 } 1161 /* change once per outer loop */ 1162 simpleGenData(&ptext, MIN_PTEXT_SIZE, MAX_PTEXT_SIZE); 1163 if(zeroLenPassword) { 1164 pwd.Length = 0; // fixed 1165 } 1166 else { 1167 simpleGenData(&pwd, APPLE_PBE_MIN_PASSWORD, MAX_PASSWORD_SIZE); 1168 } 1169 simpleGenData(&salt, APPLE_PBE_MIN_SALT, MAX_SALT_SIZE); 1170 targs.iterCount = genRand(MIN_ITER_COUNT, MAX_ITER_COUNT); 1171 if(refKeysOnly) { 1172 targs.useRefKey = CSSM_TRUE; 1173 } 1174 else { 1175 targs.useRefKey = (loop & 1) ? CSSM_FALSE : CSSM_TRUE; 1176 } 1177 1178 for(encrAlg=ENCR_ALG_FIRST; encrAlg<=lastEncrAlg; encrAlg++) { 1179 /* Cook up encryption-related args */ 1180 algInfo(encrAlg, 1181 &targs.keyAlg, 1182 &targs.encrAlg, 1183 &targs.encrMode, 1184 &targs.encrPad, 1185 &targs.useInitVector, 1186 &targs.ivSize, 1187 &fooBool, // genInitVector 1188 &targs.keyAlgStr); 1189 /* random key size */ 1190 targs.effectiveKeySizeInBits = randKeySizeBits(targs.keyAlg, OT_Encrypt); 1191 targs.keySizeInBits = (targs.effectiveKeySizeInBits + 7) & ~7; 1192 if(targs.keySizeInBits == targs.effectiveKeySizeInBits) { 1193 /* same size, ignore effective */ 1194 targs.effectiveKeySizeInBits = 0; 1195 } 1196 if(!quiet) { 1197 printf(" ...Encrypt alg %s keySizeInBits %u effectKeySize %u\n", 1198 targs.keyAlgStr, (unsigned)targs.keySizeInBits, 1199 (unsigned)targs.effectiveKeySizeInBits); 1200 } 1201 for(pbeAlg=PBE_ALG_FIRST; pbeAlg<=PBE_ALG_LAST; pbeAlg++) { 1202 /* Cook up pbe-related args */ 1203 uint32 foo; 1204 algInfo(pbeAlg, 1205 &targs.deriveAlg, 1206 &foo, // encrAlg 1207 &foo, // mode 1208 &foo, 1209 &fooBool, // useInitVector 1210 &foo, // ivSize 1211 &targs.genInitVector, 1212 &targs.deriveAlgStr); 1213 if(!quiet) { 1214 printf(" ...PBE alg %s\n", targs.deriveAlgStr); 1215 } 1216 /* grind thru the tests */ 1217 if(repeatTest(&targs)) { 1218 rtn = 1; 1219 goto testDone; 1220 } 1221 if(repeatOnly) { 1222 continue; 1223 } 1224 if(iterTest(&targs)) { 1225 rtn = 1; 1226 goto testDone; 1227 } 1228 #if 0 1229 // not supported yet 1230 if(deriveAlgTest(&targs)) { 1231 rtn = 1; 1232 goto testDone; 1233 } 1234 #endif 1235 if(!zeroLenPassword) { 1236 /* won't work with zero length password */ 1237 if(passwordTest(&targs)) { 1238 rtn = 1; 1239 goto testDone; 1240 } 1241 } 1242 if(saltTest(&targs)) { 1243 rtn = 1; 1244 goto testDone; 1245 } 1246 if(targs.useInitVector) { 1247 if(initVectTest(&targs)) { 1248 rtn = 1; 1249 goto testDone; 1250 } 1251 } 1252 } /* for pbeAlg */ 1253 } /* for encrAlg */ 1254 if(doPause) { 1255 if(testError(quiet)) { 1256 break; 1257 } 1258 } 1259 if(loops && (loop == loops)) { 1260 break; 1261 } 1262 } /* for loop */ 1263 1264testDone: 1265 CSSM_ModuleDetach(targs.cspHand); 1266 if(!quiet && (rtn == 0)) { 1267 printf("%s test complete\n", argv[0]); 1268 } 1269 return rtn; 1270} 1271