2 * ccSymCompat.c - test compatibilty of two different implementations of a
3 * given symmetric encryption algorithm - one in CommonCrypto (which we
4 * might link against directly, not using libSystem, via Makefile tweaking),
5 * the other in either libcrypto (for Blowfish and CAST), BSAFE, or the
6 * NIST reference port for AES.
8 * Written by Doug Mitchell.
14 #include <Security/cssm.h>
15 #include <Security/cssmapple.h>
18 #include "bsafeUtils.h"
19 #include "ssleayUtils.h"
20 #include "rijndaelApi.h"
22 #include <CommonCrypto/CommonCryptor.h>
29 #define MIN_DATA_SIZE 8
30 #define MAX_DATA_SIZE 10000 /* bytes */
31 #define MAX_KEY_SIZE MAX_KEY_SIZE_RC245_BYTES /* bytes */
32 #define LOOP_NOTIFY 20
34 #define NO_PAD_MODE CSSM_ALGMODE_ECB /* doesn't work for BSAFE */
35 #define NO_PAD_MODE_BSAFE CSSM_ALGMODE_CBC_IV8
38 * Enumerate algs our own way to allow iteration.
41 ALG_AES_128
= 1, /* 128 bit block, 128 bit key */
42 ALG_AES_192
, /* 128 bit block, 192 bit key */
43 ALG_AES_256
, /* 128 bit block, 256 bit key */
48 /* not supported by CommonCrypto */
53 #define ALG_FIRST ALG_AES_128
54 #define ALG_LAST ALG_RC4
56 static void usage(char **argv
)
58 printf("usage: %s [options]\n", argv
[0]);
59 printf(" Options:\n");
60 printf(" a=algorithm (d=DES; 3=3DES3; a=AES128; n=AES192; A=AES256; c=CAST;\n");
61 printf(" 4=RC4; default=all)\n");
62 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF
);
63 printf(" k=keySizeInBits\n");
64 printf(" e(ncrypt only)\n");
65 printf(" m=maxPtextSize (default=%d)\n", MAX_DATA_SIZE
);
66 printf(" n=minPtextSize (default=%d)\n", MIN_DATA_SIZE
);
67 printf(" p=pauseInterval (default=0, no pause)\n");
68 printf(" s (all ops single-shot, not staged)\n");
69 printf(" o (no padding, disable CBC if possible)\n");
70 printf(" z (keys and plaintext all zeroes)\n");
71 printf(" v(erbose)\n");
78 * encrypt/decrypt using reference BSAFE.
80 static CSSM_RETURN
encryptDecryptBSAFE(
82 CSSM_ALGORITHMS encrAlg
,
83 CSSM_ENCRYPT_MODE encrMode
,
84 const CSSM_DATA
*iv
, //Êoptional per mode
86 uint32 effectiveKeyBits
, // optional per key alg
87 uint32 rounds
, // ditto
88 const CSSM_DATA
*key
, // raw key bytes
89 const CSSM_DATA
*inText
,
90 CSSM_DATA_PTR outText
) // mallocd and returned
95 crtn
= buGenSymKey(keySizeInBits
, key
, &buKey
);
99 crtn
= buEncryptDecrypt(buKey
,
100 forEncrypt
, // forEncrypt
113 * encrypt/decrypt using reference ssleay.
115 static CSSM_RETURN
encryptDecryptEAY(
116 CSSM_BOOL forEncrypt
,
117 CSSM_ALGORITHMS encrAlg
,
118 CSSM_ENCRYPT_MODE encrMode
,
119 const CSSM_DATA
*iv
, // optional per mode
120 uint32 keySizeInBits
,
121 const CSSM_DATA
*key
, // raw key bytes, Length ignored
122 const CSSM_DATA
*inText
,
123 CSSM_DATA_PTR outText
) // mallocd and returned
127 CSSM_DATA ckey
= *key
;
128 ckey
.Length
= keySizeInBits
/ 8;
130 crtn
= eayGenSymKey(encrAlg
, forEncrypt
, &ckey
, &eayKey
);
134 crtn
= eayEncryptDecrypt(eayKey
,
146 * encrypt/decrypt using reference AES.
148 static CSSM_RETURN
encryptDecryptAES(
149 CSSM_BOOL forEncrypt
,
150 CSSM_ALGORITHMS encrAlg
,
151 CSSM_ENCRYPT_MODE encrMode
,
152 const CSSM_DATA
*iv
, //Êoptional per mode
153 uint32 keySizeInBits
,
154 uint32 effectiveKeyBits
, // optional per key alg
155 uint32 cipherBlockSize
,
156 uint32 rounds
, // ditto
157 const CSSM_DATA
*key
, // raw key bytes
158 const CSSM_DATA
*inText
,
159 CSSM_DATA_PTR outText
) // mallocd and returned
162 cipherInstance aesCipher
;
167 if(cipherBlockSize
== 0) {
168 cipherBlockSize
= MIN_AES_BLOCK_BITS
;
171 case CSSM_ALGMODE_CBC_IV8
:
175 case CSSM_ALGMODE_ECB
:
180 printf("***AES reference implementation doesn't do padding (yet)\n");
183 /* fixme - adjust for padding if necessary */
184 outText
->Data
= (uint8
*)CSSM_MALLOC(inText
->Length
);
185 outText
->Length
= inText
->Length
;
186 artn
= _makeKey(&aesKey
,
187 forEncrypt
? DIR_ENCRYPT
: DIR_DECRYPT
,
192 printf("***AES makeKey returned %d\n", artn
);
193 return CSSM_ERRCODE_INTERNAL_ERROR
;
195 artn
= _cipherInit(&aesCipher
,
200 printf("***AES cipherInit returned %d\n", artn
);
201 return CSSM_ERRCODE_INTERNAL_ERROR
;
204 artn
= _blockEncrypt(&aesCipher
,
206 (BYTE
*)inText
->Data
,
208 (BYTE
*)outText
->Data
);
211 artn
= _blockDecrypt(&aesCipher
,
213 (BYTE
*)inText
->Data
,
215 (BYTE
*)outText
->Data
);
218 printf("***AES encrypt/decrypt returned %d\n", artn
);
219 return CSSM_ERRCODE_INTERNAL_ERROR
;
225 * Encrypt/decrypt, one-shot, using one of the various reference implementations.
227 static CSSM_RETURN
encryptDecryptRef(
228 CSSM_BOOL forEncrypt
,
229 CSSM_ALGORITHMS encrAlg
,
230 CSSM_ENCRYPT_MODE encrMode
,
231 const CSSM_DATA
*iv
, // optional per mode
232 uint32 keySizeInBits
,
233 uint32 effectiveKeyBits
, // optional per key alg
234 uint32 cipherBlockSize
,
235 uint32 rounds
, // ditto
236 const CSSM_DATA
*key
, // raw key bytes
237 const CSSM_DATA
*inText
,
238 CSSM_DATA_PTR outText
) // mallocd and returned
242 return encryptDecryptAES(
254 case CSSM_ALGID_BLOWFISH
:
255 case CSSM_ALGID_CAST
:
256 return encryptDecryptEAY(
266 return encryptDecryptBSAFE(
281 * encrypt/decrypt using CommonCrypto.
283 static CSSM_RETURN
encryptDecryptCC(
284 CSSM_BOOL forEncrypt
,
285 CSSM_ALGORITHMS encrAlg
,
286 CSSM_ENCRYPT_MODE encrMode
,
287 CSSM_PADDING padding
, // CSSM_PADDING_PKCS1, etc.
288 uint32 cipherBlockSize
,
289 CSSM_BOOL multiUpdates
, // false:single update, true:multi updates
290 const CSSM_DATA
*iv
, // optional per mode
291 uint32 keySizeInBits
,
292 const CSSM_DATA
*key
, // raw key bytes
293 const CSSM_DATA
*inText
,
294 CSSM_DATA_PTR outText
) // mallocd and returned
296 CCCryptorRef cryptor
= NULL
;
297 uint8
*intext
= inText
->Data
;
298 uint32 intextLen
= inText
->Length
;
300 size_t outtextLen
; /* mallocd size of outtext */
301 size_t outBytes
= 0; /* bytes actually produced in outtext */
302 CCCryptorStatus crtn
;
305 /* convert crypt params from CDSA to CommonCrypto */
307 CCOperation ccOp
= forEncrypt
? kCCEncrypt
: kCCDecrypt
;
308 CCOptions ccOpts
= 0;
313 ccAlg
= kCCAlgorithmDES
;
314 blockSize
= kCCBlockSizeDES
;
316 case CSSM_ALGID_3DES_3KEY_EDE
:
317 ccAlg
= kCCAlgorithm3DES
;
318 blockSize
= kCCBlockSize3DES
;
321 ccAlg
= kCCAlgorithmAES128
;
322 blockSize
= kCCBlockSizeAES128
;
324 case CSSM_ALGID_CAST
:
325 ccAlg
= kCCAlgorithmCAST
;
326 blockSize
= kCCBlockSizeCAST
;
329 ccAlg
= kCCAlgorithmRC4
;
333 printf("***BRRZAP! Unknown algorithm in encryptDecryptCC()\n");
336 if(padding
!= CSSM_PADDING_NONE
) {
337 ccOpts
|= kCCOptionPKCS7Padding
;
340 case CSSM_ALGMODE_CBC_IV8
:
341 /* testing DES against BSAFE */
345 case CSSM_ALGMODE_ECB
:
348 case CSSM_ALGMODE_CBCPadIV8
:
349 /* padding and cbc */
352 case CSSM_ALGMODE_NONE
:
358 printf("***Bad mode (%lu)\n", (unsigned long)encrMode
);
362 ccOpts
|= kCCOptionECBMode
;
365 /* alloc outtext - round up to next cipherblock boundary for encrypt */
369 blocks
= (intextLen
+ blockSize
) / blockSize
;
372 blocks
= intextLen
/ blockSize
;
374 outtextLen
= blocks
* blockSize
;
377 outtextLen
= intextLen
;
380 outtext
= (uint8
*)CSSM_MALLOC(outtextLen
);
381 memset(outtext
, 0x55, outtextLen
);
385 crtn
= CCCrypt(ccOp
, ccAlg
, ccOpts
,
386 key
->Data
, keySizeInBits
/ 8, ccIv
,
388 outtext
, outtextLen
, &outtextLen
);
390 printf("***CCCrypt returned %ld\n", (long)crtn
);
393 outText
->Data
= outtext
;
394 outText
->Length
= outtextLen
;
398 /* staged, random sized updates */
399 crtn
= CCCryptorCreate(ccOp
, ccAlg
, ccOpts
,
400 key
->Data
, keySizeInBits
/ 8, ccIv
,
403 printf("***CCCryptorInit returned %ld\n", (long)crtn
);
407 size_t toMove
= intextLen
; /* total to go */
408 size_t thisMoveOut
; /* output from CCCryptUpdate()/CCCryptFinal() */
409 uint8
*outp
= outtext
;
413 uint32 thisMoveIn
; /* input to CCryptUpdate() */
415 thisMoveIn
= genRand(1, toMove
);
416 crtn
= CCCryptorUpdate(cryptor
, inp
, thisMoveIn
,
417 outp
, outtextLen
, &thisMoveOut
);
419 printf("***CCCryptorUpdate returned %ld\n", (long)crtn
);
423 toMove
-= thisMoveIn
;
425 outtextLen
-= thisMoveOut
;
426 outBytes
+= thisMoveOut
;
428 crtn
= CCCryptorFinal(cryptor
, outp
, outtextLen
, &thisMoveOut
);
430 printf("***CCCryptorFinal returned %ld\n", (long)crtn
);
433 outBytes
+= thisMoveOut
;
434 outText
->Data
= outtext
;
435 outText
->Length
= outBytes
;
439 CCCryptorRelease(cryptor
);
447 const CSSM_DATA
*ptext
,
448 const CSSM_DATA
*keyData
,
450 uint32 keyAlg
, // CSSM_ALGID_xxx of the key
451 uint32 encrAlg
, // encrypt/decrypt
454 uint32 keySizeInBits
,
455 uint32 efectiveKeySizeInBits
,
456 uint32 cipherBlockSize
,
457 CSSM_BOOL stagedEncr
,
458 CSSM_BOOL stagedDecr
,
460 CSSM_BOOL encryptOnly
)
462 CSSM_DATA ctextRef
= {0, NULL
}; // ciphertext, reference
463 CSSM_DATA ctextTest
= {0, NULL
}; // ciphertext, test
464 CSSM_DATA rptext
= {0, NULL
}; // recovered plaintext
469 if(encrAlg
== CSSM_ALGID_RC5
) {
470 /* roll the dice, pick one of three values for rounds */
471 unsigned die
= genRand(1,3);
486 * encrypt with each method;
487 * verify ciphertexts compare;
488 * decrypt with test code;
489 * verify recovered plaintext and incoming plaintext compare;
491 crtn
= encryptDecryptRef(CSSM_TRUE
,
496 efectiveKeySizeInBits
,
503 return testError(quiet
);
505 crtn
= encryptDecryptCC(CSSM_TRUE
,
517 return testError(quiet
);
520 /* ensure both methods resulted in same ciphertext */
521 if(ctextRef
.Length
!= ctextTest
.Length
) {
522 printf("Ctext length mismatch (1)\n");
523 rtn
= testError(quiet
);
528 if(memcmp(ctextRef
.Data
, ctextTest
.Data
, ctextTest
.Length
)) {
529 printf("Ctext miscompare\n");
530 rtn
= testError(quiet
);
541 /* decrypt with the test method */
542 crtn
= encryptDecryptCC(CSSM_FALSE
,
554 return testError(quiet
);
556 if(rptext
.Length
!= ptext
->Length
) {
557 printf("ptext length mismatch (1)\n");
558 rtn
= testError(quiet
);
563 if(memcmp(rptext
.Data
, ptext
->Data
, ptext
->Length
)) {
564 printf("ptext miscompare\n");
565 const unsigned char *cp
= (const unsigned char *)rptext
.Data
;
566 printf("rptext %p: %02X %02X %02X %02X...\n",
567 cp
, cp
[0], cp
[1], cp
[2], cp
[3]);
568 rtn
= testError(quiet
);
575 CSSM_FREE(ctextTest
.Data
);
577 if(ctextRef
.Length
) {
578 CSSM_FREE(ctextRef
.Data
);
581 CSSM_FREE(rptext
.Data
);
587 int main(int argc
, char **argv
)
593 CSSM_BOOL stagedEncr
;
594 CSSM_BOOL stagedDecr
;
596 uint32 keyAlg
; // CSSM_ALGID_xxx of the key
597 uint32 encrAlg
; // CSSM_ALGID_xxx of encr/decr
599 unsigned currAlg
; // ALG_xxx
600 uint32 actKeySizeInBits
;
601 uint32 effectKeySizeInBits
;
603 uint32 blockSize
; // for noPadding case
605 CSSM_DATA initVector
;
611 CSSM_BOOL keySizeSpec
= CSSM_FALSE
; // false: use rand key size
612 unsigned minAlg
= ALG_FIRST
;
613 unsigned maxAlg
= ALG_LAST
;
614 unsigned loops
= LOOPS_DEF
;
615 CSSM_BOOL verbose
= CSSM_FALSE
;
616 CSSM_BOOL quiet
= CSSM_FALSE
;
617 unsigned pauseInterval
= 0;
620 CSSM_BOOL noPadding
= CSSM_FALSE
;
621 CSSM_BOOL encryptOnly
= CSSM_FALSE
;
622 uint32 cipherBlockSize
= 0; // AES only, bits, 0 ==> default
623 unsigned maxPtextSize
= MAX_DATA_SIZE
;
624 unsigned minPtextSize
= MIN_DATA_SIZE
;
625 CSSM_BOOL oneShotOnly
= CSSM_FALSE
;
626 CSSM_BOOL allZeroes
= CSSM_FALSE
;
628 for(arg
=1; arg
<argc
; arg
++) {
638 minAlg
= maxAlg
= ALG_ASC
;
642 minAlg
= maxAlg
= ALG_DES
;
645 minAlg
= maxAlg
= ALG_3DES
;
648 minAlg
= maxAlg
= ALG_RC2
;
651 minAlg
= maxAlg
= ALG_RC4
;
654 minAlg
= maxAlg
= ALG_RC5
;
657 minAlg
= maxAlg
= ALG_AES_128
;
660 minAlg
= maxAlg
= ALG_AES_192
;
661 noPadding
= CSSM_TRUE
; // current restriction in
662 // our reference implementation
665 minAlg
= maxAlg
= ALG_AES_256
;
666 noPadding
= CSSM_TRUE
; // current restriction in
667 // our reference implementation
670 minAlg
= maxAlg
= ALG_BFISH
;
671 noPadding
= CSSM_TRUE
;
674 minAlg
= maxAlg
= ALG_CAST
;
675 noPadding
= CSSM_TRUE
;
682 loops
= atoi(&argp
[2]);
685 actKeySizeInBits
= effectKeySizeInBits
= atoi(&argp
[2]);
686 keySizeSpec
= CSSM_TRUE
;
689 cipherBlockSize
= atoi(&argp
[2]);
692 oneShotOnly
= CSSM_TRUE
;
698 encryptOnly
= CSSM_TRUE
;
701 maxPtextSize
= atoi(&argp
[2]);
704 minPtextSize
= atoi(&argp
[2]);
710 allZeroes
= CSSM_TRUE
;
713 pauseInterval
= atoi(&argp
[2]);;
716 noPadding
= CSSM_TRUE
;
723 ptext
.Data
= (uint8
*)CSSM_MALLOC(maxPtextSize
);
724 if(ptext
.Data
== NULL
) {
725 printf("Insufficient heap space\n");
728 /* ptext length set in test loop */
730 keyData
.Data
= (uint8
*)CSSM_MALLOC(MAX_KEY_SIZE
);
731 if(keyData
.Data
== NULL
) {
732 printf("Insufficient heap space\n");
735 keyData
.Length
= MAX_KEY_SIZE
;
737 initVector
.Data
= (uint8
*)"someStrangeInitVect";
739 printf("Starting ccSymCompat; args: ");
740 for(i
=1; i
<argc
; i
++) {
741 printf("%s ", argv
[i
]);
746 printf("Top of test; hit CR to proceed: ");
749 for(currAlg
=minAlg
; currAlg
<=maxAlg
; currAlg
++) {
750 /* some default values... */
751 mode
= CSSM_ALGMODE_NONE
;
752 padding
= CSSM_PADDING_NONE
;
753 const char *padStr
= "Off";
754 const char *modeStr
= "None";
756 blockSize
= 0; // i.e., don't align
759 encrAlg
= keyAlg
= CSSM_ALGID_DES
;
762 mode
= NO_PAD_MODE_BSAFE
;
767 mode
= CSSM_ALGMODE_CBCPadIV8
;
770 padding
= CSSM_PADDING_PKCS1
;
774 /* currently the only one with different key and encr algs */
775 keyAlg
= CSSM_ALGID_3DES_3KEY
;
776 encrAlg
= CSSM_ALGID_3DES_3KEY_EDE
;
779 mode
= NO_PAD_MODE_BSAFE
;
784 mode
= CSSM_ALGMODE_CBCPadIV8
;
785 padding
= CSSM_PADDING_PKCS1
;
791 encrAlg
= keyAlg
= CSSM_ALGID_RC2
;
794 mode
= NO_PAD_MODE_BSAFE
;
799 mode
= CSSM_ALGMODE_CBCPadIV8
;
800 padding
= CSSM_PADDING_PKCS1
; // what does padding do here?
806 encrAlg
= keyAlg
= CSSM_ALGID_RC4
;
808 mode
= CSSM_ALGMODE_NONE
;
811 encrAlg
= keyAlg
= CSSM_ALGID_RC5
;
814 mode
= NO_PAD_MODE_BSAFE
;
819 mode
= CSSM_ALGMODE_CBCPadIV8
;
820 padding
= CSSM_PADDING_PKCS1
; // eh?
826 encrAlg
= keyAlg
= CSSM_ALGID_AES
;
828 /* padding not supported in ref implementation */
832 /* also means no CBC */
833 mode
= CSSM_ALGMODE_ECB
;
837 mode
= CSSM_ALGMODE_CBC_IV8
;
841 effectKeySizeInBits
= actKeySizeInBits
= kCCKeySizeAES128
* 8;
844 encrAlg
= keyAlg
= CSSM_ALGID_AES
;
847 /* padding not supported in ref implementation */
851 /* also means no CBC */
852 mode
= CSSM_ALGMODE_ECB
;
856 mode
= CSSM_ALGMODE_CBC_IV8
;
860 effectKeySizeInBits
= actKeySizeInBits
= kCCKeySizeAES192
* 8;
863 encrAlg
= keyAlg
= CSSM_ALGID_AES
;
866 /* padding not supported in ref implementation */
870 /* also means no CBC */
871 mode
= CSSM_ALGMODE_ECB
;
875 mode
= CSSM_ALGMODE_CBC_IV8
;
879 effectKeySizeInBits
= actKeySizeInBits
= kCCKeySizeAES256
* 8;
882 encrAlg
= keyAlg
= CSSM_ALGID_BLOWFISH
;
884 /* libcrypt doesn't do padding */
885 mode
= CSSM_ALGMODE_CBC_IV8
;
890 encrAlg
= keyAlg
= CSSM_ALGID_CAST
;
892 /* libcrypt doesn't do padding */
893 mode
= CSSM_ALGMODE_CBC_IV8
;
899 /* assume for now all algs require IV */
900 initVector
.Length
= blockSize
? blockSize
: 8;
902 if(!quiet
|| verbose
) {
903 printf("Testing alg %s\n", algStr
);
905 for(loop
=1; ; loop
++) {
906 minTextSize
= minPtextSize
; // default
907 if((blockSize
!= 0) && (minTextSize
< blockSize
)) {
908 /* i.e., AES, adjust min ptext size */
909 minTextSize
= blockSize
;
911 simpleGenData(&ptext
, minTextSize
, maxPtextSize
);
913 /* i.e., no padding --> align ptext */
914 ptext
.Length
= (ptext
.Length
/ blockSize
) * blockSize
;
917 memset(ptext
.Data
, 0, ptext
.Length
);
918 memset(keyData
.Data
, 0, MAX_KEY_SIZE
);
919 keyData
.Length
= MAX_KEY_SIZE
;
922 simpleGenData(&keyData
, MAX_KEY_SIZE
, MAX_KEY_SIZE
);
927 * CommonCrypto's AES does one key size only
929 if(keyAlg
!= CSSM_ALGID_AES
) {
930 effectKeySizeInBits
= randKeySizeBits(keyAlg
, OT_Encrypt
);
932 * generate keys with well aligned sizes; effectiveKeySize
933 * differs only if not well aligned
935 actKeySizeInBits
= (effectKeySizeInBits
+ 7) & ~7;
938 /* else constant, spec'd by user, may be 0 (default per alg) */
941 stagedEncr
= CSSM_FALSE
;
942 stagedDecr
= CSSM_FALSE
;
945 stagedEncr
= (loop
& 1) ? CSSM_TRUE
: CSSM_FALSE
;
946 stagedDecr
= (loop
& 2) ? CSSM_TRUE
: CSSM_FALSE
;
949 if(verbose
|| ((loop
% LOOP_NOTIFY
) == 0)) {
950 if(cipherBlockSize
) {
951 printf("..loop %d text size %lu keySizeBits %u"
952 " blockSize %u stagedEncr %d stagedDecr %d mode %s pad %s\n",
953 loop
, (unsigned long)ptext
.Length
, (unsigned)effectKeySizeInBits
,
954 (unsigned)cipherBlockSize
, (int)stagedEncr
, (int)stagedDecr
,
958 printf("..loop %d text size %lu keySizeBits %u"
959 " stagedEncr %d stagedDecr %d mode %s pad %s\n",
960 loop
, (unsigned long)ptext
.Length
, (unsigned)effectKeySizeInBits
,
961 (int)stagedEncr
, (int)stagedDecr
, modeStr
, padStr
);
974 actKeySizeInBits
, // FIXME - test effective key size
983 if(pauseInterval
&& ((loop
% pauseInterval
) == 0)) {
986 printf("Hit CR to proceed, q to abort: ");
992 if(loops
&& (loop
== loops
)) {
1005 printf("ModuleDetach/Unload complete; hit CR to exit: ");
1008 if((rtn
== 0) && !quiet
) {
1009 printf("%s test complete\n", argv
[0]);
1011 CSSM_FREE(ptext
.Data
);
1012 CSSM_FREE(keyData
.Data
);