1 /* Copyright (c) 1998,2003-2005,2008 Apple Inc.
3 * symDelta.c - Ensure that varying each parameter in a symmetric
4 * encryption op does in fact change the ciphertext.
8 * July 18 2000 Doug Mitchell at Apple
15 #include <Security/cssm.h>
16 #include <Security/cssmapple.h>
19 #include "cspdlTesting.h"
21 /* we need to know a little bit about AES for this test.... */
22 #define AES_BLOCK_SIZE 16 /* bytes */
28 #define MIN_PTEXT_SIZE AES_BLOCK_SIZE /* for non-padding tests */
29 #define MAX_PTEXT_SIZE 1000
30 #define MAX_IV_SIZE AES_BLOCK_SIZE
33 * Enumerate algs our own way to allow iteration.
35 typedef unsigned privAlg
;
47 * Ditto for modes. ALGMODE_NONE not iterated, it's a special case for
50 typedef unsigned privMode
;
53 pma_CBC_IV8
, // no pad - requires well-aligned ptext
54 pma_ECB
, // no IV, no pad - requires well-aligned ptext
57 #define ENCR_ALG_FIRST pka_ASC
58 #define ENCR_ALG_LAST pka_AES
60 #define ENCR_MODE_FIRST pma_CBC_PadIV8
61 #define ENCR_MODE_LAST pma_ECB
64 * Args passed to each test and to testCommon; these completely define
65 * the paramters for one encryption op.
68 CSSM_CSP_HANDLE cspHand
;
69 CSSM_ALGORITHMS keyAlg
;
70 CSSM_ALGORITHMS encrAlg
;
72 uint32 effectiveKeySizeInBits
; // 0 means not used
73 uint32 rounds
; // ditto
74 const char *keyAlgStr
;
75 CSSM_ENCRYPT_MODE encrMode
;
76 const char *encrModeStr
;
79 CSSM_BOOL useInitVector
; // encrypt needs an IV
81 CSSM_DATA initVector
; // Data mallocd and init in main()
82 CSSM_KEY_PTR key
; // gen'd in main
87 static void usage(char **argv
)
89 printf("usage: %s [options]\n", argv
[0]);
90 printf(" Options:\n");
91 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF
);
92 printf(" e(xport)\n");
93 printf(" r(epeatOnly)\n");
94 printf(" p(ause after each loop)\n");
95 printf(" D (CSP/DL; default = bare CSP)\n");
102 * Given a privAlg value, return various associated stuff.
104 static void algInfo(privAlg alg
, // pka_DES, etc.
105 CSSM_ALGORITHMS
*keyAlg
, // CSSM_ALGID_DES, etc. RETURNED
106 // key alg for key gen algs
107 CSSM_ALGORITHMS
*encrAlg
, // encrypt/decrypt alg for key
109 const char **algStr
, // RETURNED
110 CSSM_SIZE
*ivSize
) // RETURNED
115 *keyAlg
= *encrAlg
= CSSM_ALGID_DES
;
119 *keyAlg
= CSSM_ALGID_3DES_3KEY
;
120 *encrAlg
= CSSM_ALGID_3DES_3KEY_EDE
;
124 *keyAlg
= *encrAlg
= CSSM_ALGID_RC2
;
128 *keyAlg
= *encrAlg
= CSSM_ALGID_RC4
;
129 /* initVector false */
134 *keyAlg
= *encrAlg
= CSSM_ALGID_RC5
;
138 *keyAlg
= *encrAlg
= CSSM_ALGID_AES
;
140 *ivSize
= AES_BLOCK_SIZE
;
143 *keyAlg
= *encrAlg
= CSSM_ALGID_ASC
;
144 /* initVector false */
149 printf("BRRZZZT! Update algInfo()!\n");
150 testError(CSSM_TRUE
);
154 /* given a privMode, return related info */
155 static void modeInfo(
158 CSSM_ENCRYPT_MODE
*cdsaMode
,
159 const char **modeStr
,
160 CSSM_PADDING
*pad
, // PKCS5 or NONE
161 CSSM_BOOL
*useInitVector
) // RETURNED, for encrypt/decrypt
163 *useInitVector
= CSSM_FALSE
;
165 /* first deal with modeless algorithms */
169 *cdsaMode
= CSSM_ALGMODE_NONE
;
171 *pad
= CSSM_PADDING_NONE
;
179 *cdsaMode
= CSSM_ALGMODE_CBCPadIV8
;
180 *modeStr
= "CBCPadIV8";
181 *useInitVector
= CSSM_TRUE
;
182 *pad
= CSSM_PADDING_PKCS5
;
185 *cdsaMode
= CSSM_ALGMODE_CBC_IV8
;
186 *modeStr
= "CBC_IV8";
187 *useInitVector
= CSSM_TRUE
;
188 *pad
= CSSM_PADDING_NONE
;
191 *cdsaMode
= CSSM_ALGMODE_ECB
;
193 *pad
= CSSM_PADDING_NONE
;
196 printf("BRRZZZT! Update modeInfo()!\n");
197 testError(CSSM_TRUE
);
202 * Given alg and mode, determine alignment of ptext size. 0 means no
203 * alignment necessary.
207 CSSM_ENCRYPT_MODE mode
)
218 case CSSM_ALGMODE_CBC_IV8
:
219 case CSSM_ALGMODE_ECB
:
220 if(alg
== CSSM_ALGID_AES
) {
221 return AES_BLOCK_SIZE
;
231 /* a handy "compare two CSSM_DATAs" ditty */
232 static CSSM_BOOL
compareData(const CSSM_DATA_PTR d1
,
233 const CSSM_DATA_PTR d2
)
235 if(d1
->Length
!= d2
->Length
) {
238 if(memcmp(d1
->Data
, d2
->Data
, d1
->Length
)) {
244 /* generate random one-bit byte */
245 static uint8
randBit()
247 return 1 << genRand(0, 7);
253 static void copyCssmKey(
254 const CSSM_KEY_PTR key1
,
257 key2
->KeyHeader
= key1
->KeyHeader
;
258 key2
->KeyData
.Data
= NULL
;
259 key2
->KeyData
.Length
= 0;
260 appCopyCssmData(&key1
->KeyData
, &key2
->KeyData
);
264 * Encrypt ptext using specified parameters
266 static int encryptCom(CSSM_CSP_HANDLE cspHand
,
267 const char *testName
,
271 CSSM_ENCRYPT_MODE mode
,
272 CSSM_PADDING padding
, // CSSM_PADDING_PKCS1, etc.
273 CSSM_DATA_PTR iv
, // may be NULL
274 uint32 effectiveKeySizeInBits
, // may be 0
275 uint32 rounds
, // ditto
276 CSSM_DATA_PTR ctext
, // RETURNED
279 CSSM_CC_HANDLE cryptHand
;
281 CSSM_SIZE bytesEncrypted
;
285 cryptHand
= genCryptHandle(cspHand
,
292 effectiveKeySizeInBits
,
295 return testError(quiet
);
300 crtn
= CSSM_EncryptData(cryptHand
,
309 printError("CSSM_EncryptData", crtn
);
310 rtn
= testError(quiet
);
313 if(remData
.Length
!= 0) {
314 ctext
->Data
= (uint8
*)appRealloc(ctext
->Data
, bytesEncrypted
, NULL
);
315 memmove(ctext
->Data
+ ctext
->Length
,
317 bytesEncrypted
- ctext
->Length
);
318 appFreeCssmData(&remData
, CSSM_FALSE
);
320 ctext
->Length
= bytesEncrypted
;
323 if(CSSM_DeleteContext(cryptHand
)) {
324 printError("CSSM_DeleteContext", 0);
331 * Common test portion
332 * encrypt ptext with args in targ1;
333 * encrypt ptext with args in targ2;
334 * compare 2 ctexts; expect failure;
336 static int testCommon(const char *testName
,
340 CSSM_DATA ctext1
= {0, NULL
};
341 CSSM_DATA ctext2
= {0, NULL
};
343 if(encryptCom(targs1
->cspHand
,
351 targs1
->effectiveKeySizeInBits
,
357 if(encryptCom(targs2
->cspHand
,
365 targs2
->effectiveKeySizeInBits
,
371 if(compareData(&ctext1
, &ctext2
)) {
372 printf("***%s: Unexpected Data compare!\n", testName
);
373 return testError(targs1
->quiet
);
375 appFreeCssmData(&ctext1
, CSSM_FALSE
);
376 appFreeCssmData(&ctext2
, CSSM_FALSE
);
381 ** inidividual tests.
383 #define KEY_LABEL1 "noLabel1"
384 #define KEY_LABEL2 "noLabel2"
385 #define KEY_LABEL_LEN strlen(KEY_LABEL1)
386 #define REPEAT_ON_ERROR 1
389 * Ensure initVector alters ctext.
391 static int initVectTest(testArgs
*targs
)
395 testArgs mungeArgs
= *targs
;
399 printf(" ...modifying init vector\n");
402 /* get munged copy of iv */
403 mungeIV
.Length
= targs
->initVector
.Length
;
404 mungeIV
.Data
= (uint8
*)CSSM_MALLOC(mungeIV
.Length
);
405 memmove(mungeIV
.Data
, targs
->initVector
.Data
, mungeIV
.Length
);
406 mungeArgs
.initVector
= mungeIV
;
407 mungeDex
= genRand(0, mungeIV
.Length
- 1);
408 mungeBits
= randBit();
409 mungeIV
.Data
[mungeDex
] ^= mungeBits
;
410 if(testCommon("initVectTest", targs
, &mungeArgs
)) {
413 appFreeCssmData(&mungeIV
, CSSM_FALSE
);
418 * Ensure effectiveKeySizeInBits alters ctext. RC2 only.
420 static int effectSizeTest(testArgs
*targs
)
422 testArgs mungeArgs
= *targs
;
425 printf(" ...modifying effective key size\n");
427 mungeArgs
.effectiveKeySizeInBits
-= 8;
428 return testCommon("effectSizeTest", targs
, &mungeArgs
);
432 * Ensure rounds alters ctext. RC5 only.
434 static int roundsTest(testArgs
*targs
)
436 testArgs mungeArgs
= *targs
;
439 printf(" ...modifying rounds\n");
441 switch(targs
->rounds
) {
443 mungeArgs
.rounds
= 12;
446 mungeArgs
.rounds
= 16;
449 mungeArgs
.rounds
= 8;
452 printf("***ACK! roundsTest needs work!\n");
455 return testCommon("roundsTest", targs
, &mungeArgs
);
460 * ensure encryption algorithm alters ctext.
462 static int encrAlgTest(testArgs
*targs
)
464 testArgs mungeArgs
= *targs
;
465 CSSM_KEY mungeKey
= *targs
->key
;
467 /* come up with different encrypt alg - not all work */
468 switch(targs
->encrAlg
) {
469 case CSSM_ALGID_DES
: // fixed size key
470 case CSSM_ALGID_3DES_3KEY_EDE
:
473 case CSSM_ALGID_RC4
: // no IV
474 mungeArgs
.encrAlg
= CSSM_ALGID_ASC
;
476 case CSSM_ALGID_ASC
: // no IV
477 mungeArgs
.encrAlg
= CSSM_ALGID_RC4
;
480 mungeArgs
.encrAlg
= CSSM_ALGID_RC5
;
483 mungeArgs
.encrAlg
= CSSM_ALGID_RC2
;
486 mungeArgs
.encrAlg
= CSSM_ALGID_RC5
;
487 mungeArgs
.initVector
.Length
= 8;
491 /* we're assuming this is legal - a shallow copy of a key, followed by a blind
492 * reassignment of its algorithm... */
493 mungeKey
.KeyHeader
.AlgorithmId
= mungeArgs
.encrAlg
;
494 mungeArgs
.key
= &mungeKey
;
497 printf(" ...modifying encryption alg\n");
500 return testCommon("encrAlgTest", targs
, &mungeArgs
);
504 * ensure encryption mode alters ctext.
506 static int encrModeTest(testArgs
*targs
)
508 testArgs mungeArgs
= *targs
;
510 /* come up with different encrypt mode - not all work */
511 switch(targs
->encrMode
) {
512 case CSSM_ALGMODE_NONE
: // i.e., RC4, ASC
513 case CSSM_ALGMODE_CBCPadIV8
: // others, only one which does
516 case CSSM_ALGMODE_CBC_IV8
:
517 mungeArgs
.encrMode
= CSSM_ALGMODE_ECB
;
518 mungeArgs
.useInitVector
= CSSM_FALSE
;
520 case CSSM_ALGMODE_ECB
:
521 mungeArgs
.encrMode
= CSSM_ALGMODE_CBC_IV8
;
522 mungeArgs
.useInitVector
= CSSM_TRUE
;
525 printf("Update encrModeTest\n");
529 printf(" ...modifying encryption mode\n");
532 return testCommon("encrModeTest", targs
, &mungeArgs
);
536 * Ensure ptext alters ctext.
538 static int ptextTest(testArgs
*targs
)
542 testArgs mungeArgs
= *targs
;
543 CSSM_DATA mungePtext
;
546 printf(" ...modifying plaintext\n");
549 /* get munged copy of ptext */
550 mungePtext
.Length
= targs
->ptext
->Length
;
551 mungePtext
.Data
= (uint8
*)CSSM_MALLOC(mungePtext
.Length
);
552 memmove(mungePtext
.Data
, targs
->ptext
->Data
, mungePtext
.Length
);
553 mungeArgs
.ptext
= &mungePtext
;
554 mungeDex
= genRand(0, mungePtext
.Length
- 1);
555 mungeBits
= randBit();
556 mungePtext
.Data
[mungeDex
] ^= mungeBits
;
557 if(testCommon("ptextTest", targs
, &mungeArgs
)) {
560 appFreeCssmData(&mungePtext
, CSSM_FALSE
);
565 * Ensure key alters ctext. Requires raw key, of course.
567 static int keyTest(testArgs
*targs
)
571 testArgs mungeArgs
= *targs
;
577 printf(" ...modifying key\n");
580 /* get munged copy of key */
581 copyCssmKey(targs
->key
, &mungeKey
);
582 mungeArgs
.key
= &mungeKey
;
584 maxByte
= mungeKey
.KeyData
.Length
- 1;
585 if(targs
->effectiveKeySizeInBits
) {
586 /* skip MS byte - partially used */
589 mungeDex
= genRand(0, maxByte
);
592 switch(targs
->keyAlg
) {
594 case CSSM_ALGID_DESX
:
595 case CSSM_ALGID_3DES_3KEY
:
596 /* skip lsb - DES parity bit */
602 mungeBits
= 1 << genRand(minBit
, 7);
603 mungeKey
.KeyData
.Data
[mungeDex
] ^= mungeBits
;
604 if(testCommon("keyTest", targs
, &mungeArgs
)) {
607 appFreeCssmData(&mungeKey
.KeyData
, CSSM_FALSE
);
611 int main(int argc
, char **argv
)
617 CSSM_DATA initVector
;
623 uint32 alignRequired
;
624 CSSM_BOOL refKeys
= CSSM_FALSE
;
630 unsigned loops
= LOOPS_DEF
;
631 CSSM_BOOL quiet
= CSSM_FALSE
;
632 CSSM_BOOL doPause
= CSSM_FALSE
;
633 CSSM_BOOL verbose
= CSSM_FALSE
;
634 CSSM_BOOL repeatOnly
= CSSM_FALSE
;
635 CSSM_BOOL bareCsp
= CSSM_TRUE
;
637 for(arg
=1; arg
<argc
; arg
++) {
641 loops
= atoi(&argp
[2]);
650 bareCsp
= CSSM_FALSE
;
651 #if CSPDL_ALL_KEYS_ARE_REF
659 repeatOnly
= CSSM_TRUE
;
667 /* statically allocate ptext and initVector; data and length
668 * change in test loop */
669 ptext
.Data
= (uint8
*)CSSM_MALLOC(MAX_PTEXT_SIZE
);
670 initVector
.Data
= (uint8
*)CSSM_MALLOC(MAX_IV_SIZE
);
671 targs
.ptext
= &ptext
;
672 targs
.initVector
= initVector
;
673 targs
.verbose
= verbose
;
676 printf("Starting symDelta; args: ");
677 for(i
=1; i
<argc
; i
++) {
678 printf("%s ", argv
[i
]);
681 targs
.cspHand
= cspDlDbStartup(bareCsp
, NULL
);
682 if(targs
.cspHand
== 0) {
686 for(loop
=1; ; loop
++) {
688 printf("...loop %d\n", loop
);
690 /* change once per outer loop */
691 simpleGenData(&ptext
, MIN_PTEXT_SIZE
, MAX_PTEXT_SIZE
);
692 origLen
= ptext
.Length
;
693 simpleGenData(&initVector
, MAX_IV_SIZE
, MAX_IV_SIZE
);
694 targs
.useRefKey
= refKeys
;
696 for(encrAlg
=ENCR_ALG_FIRST
; encrAlg
<=ENCR_ALG_LAST
; encrAlg
++) {
697 /* Cook up encryption-related args */
702 &targs
.initVector
.Length
);
704 /* random key size */
705 targs
.effectiveKeySizeInBits
= randKeySizeBits(targs
.keyAlg
, OT_Encrypt
);
706 targs
.keySizeInBits
= (targs
.effectiveKeySizeInBits
+ 7) & ~7;
707 if(targs
.keySizeInBits
== targs
.effectiveKeySizeInBits
) {
708 /* same size, ignore effective */
709 targs
.effectiveKeySizeInBits
= 0;
712 printf(" ...Encrypt alg %s keySizeInBits %u effectKeySize %u\n",
713 targs
.keyAlgStr
, (unsigned)targs
.keySizeInBits
,
714 (unsigned)targs
.effectiveKeySizeInBits
);
717 /* generate raw key for this keyAlg */
718 targs
.key
= cspGenSymKey(targs
.cspHand
,
725 if(targs
.key
== NULL
) {
726 if(testError(quiet
)) {
727 goto testDone
; // abort
730 continue; // next key alg
735 * Inner loop: iterate thru modes for algorithms which
738 for(pmode
=ENCR_MODE_FIRST
;
739 pmode
<=ENCR_MODE_LAST
;
742 /* Cook up mode-related args */
743 modeInfo(targs
.keyAlg
,
748 &targs
.useInitVector
);
750 if(targs
.keyAlg
== CSSM_ALGID_RC5
) {
751 /* roll the dice, pick one of three values for rounds */
752 unsigned die
= genRand(1,3);
769 printf(" ...mode %s\n", targs
.encrModeStr
);
772 alignRequired
= alignInfo(targs
.encrAlg
, targs
.encrMode
);
774 /* truncate ptext - we'll restore it at end of loop */
775 ptext
.Length
&= (~(alignRequired
- 1));
777 if(targs
.useInitVector
) {
778 if(initVectTest(&targs
)) {
784 if(targs
.effectiveKeySizeInBits
!= 0) {
785 if(effectSizeTest(&targs
)) {
791 if(targs
.rounds
!= 0) {
792 if(roundsTest(&targs
)) {
798 if(!targs
.useRefKey
) {
799 /* can't do this with ref keys due to key/encr alg mismatch */
800 if(encrAlgTest(&targs
)) {
806 if(encrModeTest(&targs
)) {
810 if(ptextTest(&targs
)) {
814 if(!targs
.useRefKey
) {
815 if(keyTest(&targs
)) {
822 /* restore possible rounded ptext length */
823 ptext
.Length
= origLen
;
825 if(targs
.encrMode
== CSSM_ALGMODE_NONE
) {
826 /* one mode, we're done */
833 cspFreeKey(targs
.cspHand
, targs
.key
);
834 CSSM_FREE(targs
.key
);
838 if(testError(quiet
)) {
842 if(loops
&& (loop
== loops
)) {
848 CSSM_ModuleDetach(targs
.cspHand
);
849 if(!quiet
&& (rtn
== 0)) {
850 printf("%s test complete\n", argv
[0]);