1/* 2 * symReference.c - write keys and ciphertext blobs, read them back 3 * and decrypt on (possibly) a different platfrom. 4 * Intended for use in testing multiplatform 5 * compatibility (e.g. encrypt on 32 bit G4, decrypt 6 * on 64-bit G5). 7 * 8 * Created by Doug Mitchell 10/31/05. 9 */ 10 11#include <stdlib.h> 12#include <stdio.h> 13#include <time.h> 14#include <Security/cssm.h> 15#include <Security/cssmapple.h> 16#include "cspwrap.h" 17#include <security_cdsa_utils/cuFileIo.h> 18#include "common.h" 19#include <string.h> 20#include "cspdlTesting.h" 21#include <unistd.h> 22 23/* 24 * Defaults. 25 */ 26#define LOOPS_DEF 200 27#define PTEXT_SIZE_DEF 256 28#define BLOCK_SIZE_MAX 32 /* bytes */ 29 30/* 31 * Enumerate algs our own way to allow iteration. 32 */ 33typedef enum { 34 ALG_ASC = 0, /* first must be 0 */ 35 ALG_DES, 36 ALG_RC2, 37 ALG_RC4, 38 ALG_RC5, 39 ALG_3DES, 40 ALG_AES, 41 ALG_AES192, 42 ALG_AES256, 43 ALG_BFISH, 44 ALG_CAST 45} SymAlg; 46 47#define ALG_FIRST ALG_ASC 48#define ALG_LAST ALG_CAST 49 50static void usage(char **argv) 51{ 52 printf("usage: %s e|d dirName [options]\n", argv[0]); 53 printf(" e=encrypt, d=decrypt; blobs read/written in dirName\n"); 54 printf(" Options:\n"); 55 printf(" a=algorithm (d=DES; 3=3DES3; 2=RC2; 4=RC4; 5=RC5; a=AES; b=Blowfish; \n"); 56 printf(" c=CAST; s=ASC, default=all)\n"); 57 printf(" p=ptextSize (default=%d)\n", PTEXT_SIZE_DEF); 58 printf(" D (CSP/DL; default = bare CSP)\n"); 59 printf(" v(erbose)\n"); 60 printf(" q(uiet)\n"); 61 printf(" h(elp)\n"); 62 exit(1); 63} 64 65/* 66 * map SymAlg to test params 67 */ 68typedef struct { 69 SymAlg alg; 70 const char *algStr; 71 CSSM_ALGORITHMS cssmAlg; 72 CSSM_ENCRYPT_MODE mode; 73 CSSM_PADDING padding; 74 CSSM_SIZE keySizeBits; 75 CSSM_SIZE ivLen; // in bytes 76} SymAlgParams; 77 78static const SymAlgParams symAlgParams[] = 79{ 80 { ALG_ASC, "ASC", CSSM_ALGID_ASC, CSSM_ALGMODE_NONE, CSSM_PADDING_NONE, 81 CSP_ASC_KEY_SIZE_DEFAULT, 0 }, 82 { ALG_DES, "DES", CSSM_ALGID_DES, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS5, 83 CSP_DES_KEY_SIZE_DEFAULT, 8 }, 84 { ALG_RC2, "RC2", CSSM_ALGID_RC2, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS5, 85 CSP_RC2_KEY_SIZE_DEFAULT, 8 }, 86 { ALG_RC4, "RC4", CSSM_ALGID_RC4, CSSM_ALGMODE_NONE, CSSM_PADDING_NONE, 87 CSP_RC4_KEY_SIZE_DEFAULT, 0 }, 88 { ALG_RC5, "RC5", CSSM_ALGID_RC5, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS5, 89 CSP_RC5_KEY_SIZE_DEFAULT, 8 }, 90 { ALG_3DES, "3DES", CSSM_ALGID_3DES_3KEY_EDE, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS5, 91 CSP_DES3_KEY_SIZE_DEFAULT, 8 }, 92 { ALG_AES, "AES", CSSM_ALGID_AES, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS5, 93 CSP_AES_KEY_SIZE_DEFAULT, 16 }, 94 { ALG_AES192, "AES192", CSSM_ALGID_AES, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS5, 95 192, 24 }, 96 { ALG_AES256, "AES256", CSSM_ALGID_AES, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS5, 97 256, 32 }, 98 { ALG_BFISH, "Blowfish", CSSM_ALGID_BLOWFISH, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS5, 99 CSP_BFISH_KEY_SIZE_DEFAULT, 8 }, 100 { ALG_CAST, "CAST", CSSM_ALGID_CAST, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS5, 101 CSP_CAST_KEY_SIZE_DEFAULT, 8 } 102}; 103 104static void genFileNames( 105 const char *algStr, 106 char *keyFile, 107 char *ptextFile, 108 char *ctextFile, 109 char *ivFile) 110{ 111 sprintf(keyFile, "key_%s", algStr); 112 sprintf(ptextFile, "ptext_%s", algStr); 113 sprintf(ctextFile, "ctext_%s", algStr); 114 sprintf(ivFile, "iv_%s", algStr); 115} 116 117/* encrypt, write blobs (key, plaintext, ciphertext, optional IV) to disk */ 118static int doEncrypt( 119 CSSM_CSP_HANDLE cspHand, 120 const SymAlgParams *algParams, 121 CSSM_DATA *ptext, // mallocd, length valid, we fill data 122 CSSM_BOOL quiet, 123 CSSM_BOOL verbose) 124{ 125 CSSM_KEY_PTR symKey = NULL; 126 CSSM_KEY rawKey; 127 CSSM_RETURN crtn; 128 CSSM_DATA ctext = {0, NULL}; 129 uint8 iv[BLOCK_SIZE_MAX]; 130 CSSM_DATA ivd = {BLOCK_SIZE_MAX, iv}; 131 CSSM_DATA *ivp = NULL; 132 uint32 blockSize = 0; 133 char keyFile[FILENAME_MAX]; 134 char ptextFile[FILENAME_MAX]; 135 char ctextFile[FILENAME_MAX]; 136 char ivFile[FILENAME_MAX]; 137 138 if(!quiet) { 139 printf("...encrypting, alg %s\n", algParams->algStr); 140 } 141 142 /* generate reference key (works with CSPDL) */ 143 symKey = cspGenSymKey(cspHand, algParams->cssmAlg, 144 "noLabel", 7, 145 CSSM_KEYUSE_ANY, algParams->keySizeBits, CSSM_TRUE); 146 if(symKey == NULL) { 147 printf("***Error generating key for alg %s size %u bits\n", 148 algParams->algStr, (unsigned)algParams->keySizeBits); 149 return testError(quiet); 150 } 151 152 /* get key in raw format (to get the raw blob we write to disk) */ 153 crtn = cspRefKeyToRaw(cspHand, symKey, &rawKey); 154 if(crtn) { 155 printf("***Error generating raw key for alg %s size %u bits\n", 156 algParams->algStr, (unsigned)algParams->keySizeBits); 157 return testError(quiet); 158 } 159 160 appGetRandomBytes(ptext->Data, (unsigned)ptext->Length); 161 162 /* 163 * Hack: we only need to specify block size for AES192 and AES256, which 164 * we detect by their having an ivLen of greater than 16. 165 */ 166 if(algParams->ivLen > 16) { 167 blockSize = algParams->ivLen; 168 } 169 if(algParams->ivLen) { 170 appGetRandomBytes(iv, algParams->ivLen); 171 ivd.Length = algParams->ivLen; 172 ivp = &ivd; 173 } 174 175 crtn = cspStagedEncrypt(cspHand, 176 algParams->cssmAlg, algParams->mode, algParams->padding, 177 symKey, NULL, 178 0, blockSize, 0, 179 ivp, ptext, 180 &ctext, 181 CSSM_FALSE); 182 if(crtn) { 183 printf("***Error encrypting for alg %s size %u bits\n", 184 algParams->algStr, (unsigned)algParams->keySizeBits); 185 return testError(quiet); 186 } 187 188 /* write: key, IV, ptext, ctext */ 189 genFileNames(algParams->algStr, keyFile, ptextFile, ctextFile, ivFile); 190 if(writeFile(keyFile, rawKey.KeyData.Data, (unsigned)rawKey.KeyData.Length) || 191 writeFile(ptextFile, ptext->Data, (unsigned)ptext->Length) || 192 writeFile(ctextFile, ctext.Data, (unsigned)ctext.Length)) { 193 printf("***Error writing result of alg %s size %u bits\n", 194 algParams->algStr, (unsigned)algParams->keySizeBits); 195 return testError(quiet); 196 } 197 if(ivp != NULL) { 198 if(writeFile(ivFile, ivp->Data, (unsigned)ivp->Length)) { 199 printf("***Error writing IV for alg %s size %u bits\n", 200 algParams->algStr, (unsigned)algParams->keySizeBits); 201 return testError(quiet); 202 } 203 } 204 205 /* Free resources */ 206 CSSM_FreeKey(cspHand, NULL, symKey, CSSM_FALSE); 207 CSSM_FreeKey(cspHand, NULL, &rawKey, CSSM_FALSE); 208 CSSM_FREE(ctext.Data); 209 return 0; 210} 211 212/* read blobs (key, plaintext, ciphertext, optional IV) from disk, decrypt, compare plaintext */ 213static int doDecrypt( 214 CSSM_CSP_HANDLE cspHand, 215 const SymAlgParams *algParams, 216 CSSM_BOOL quiet, 217 CSSM_BOOL verbose) 218{ 219 CSSM_KEY symKey; 220 uint8 *symKeyBits; 221 unsigned symKeyLen; // in bytes 222 CSSM_DATA symKeyData; 223 CSSM_RETURN crtn; 224 uint8 *ctextChars; 225 unsigned ctextLen = 0; 226 CSSM_DATA ctext; 227 CSSM_DATA rptext = {0, NULL}; // recovered/decrytped 228 uint8 *refPTextChars; 229 unsigned refPtextLen; 230 CSSM_DATA refPtext = {0, NULL}; // expected 231 uint8 *iv = NULL; 232 unsigned ivLen; 233 CSSM_DATA ivd = {BLOCK_SIZE_MAX, iv}; 234 CSSM_DATA *ivp = NULL; 235 uint32 blockSize = 0; 236 char keyFile[FILENAME_MAX]; 237 char ptextFile[FILENAME_MAX]; 238 char ctextFile[FILENAME_MAX]; 239 char ivFile[FILENAME_MAX]; 240 241 if(!quiet) { 242 printf("...decrypting, alg %s\n", algParams->algStr); 243 } 244 245 /* 246 * Hack: we only need to specify block size for AES192 and AES256, which 247 * we detect by their having an ivLen of greater than 16. 248 */ 249 if(algParams->ivLen > 16) { 250 blockSize = algParams->ivLen; 251 } 252 if(algParams->ivLen) { 253 ivp = &ivd; 254 ivd.Length = algParams->ivLen; 255 } 256 257 /* read: key, IV, ptext, ctext */ 258 genFileNames(algParams->algStr, keyFile, ptextFile, ctextFile, ivFile); 259 if(readFile(keyFile, &symKeyBits, &symKeyLen) || 260 readFile(ptextFile, &refPTextChars, &refPtextLen) || 261 readFile(ctextFile, &ctextChars, &ctextLen)) { 262 printf("***Error reading reference blobs for alg %s size %u bits\n", 263 algParams->algStr, (unsigned)algParams->keySizeBits); 264 return testError(quiet); 265 } 266 if(ivp != NULL) { 267 if(readFile(ivFile, &iv, &ivLen)) { 268 printf("***Error writing IV for alg %s size %u bits\n", 269 algParams->algStr, (unsigned)algParams->keySizeBits); 270 return testError(quiet); 271 } 272 if(ivLen != algParams->ivLen) { 273 printf("***Unexpected IV length: expect %u found %u\n", 274 (unsigned)algParams->ivLen, (unsigned)ivLen); 275 if(testError(quiet)) { 276 return 1; 277 } 278 } 279 ivd.Data = iv; 280 } 281 ctext.Data = ctextChars; 282 ctext.Length = ctextLen; 283 refPtext.Data = refPTextChars; 284 refPtext.Length = refPtextLen; 285 286 /* generate key */ 287 symKeyData.Data = symKeyBits; 288 symKeyData.Length = symKeyLen; 289 290 crtn = cspGenSymKeyWithBits(cspHand, algParams->cssmAlg, 291 CSSM_KEYUSE_ANY, &symKeyData, symKeyLen, &symKey); 292 if(crtn) { 293 printf("***Error creating key for alg %s keySize %u\n", 294 algParams->algStr, (unsigned)algParams->keySizeBits); 295 return testError(quiet); 296 } 297 298 crtn = cspStagedDecrypt(cspHand, 299 algParams->cssmAlg, algParams->mode, algParams->padding, 300 &symKey, NULL, 301 0, blockSize, 0, 302 ivp, &ctext, 303 &rptext, 304 CSSM_FALSE); 305 if(crtn) { 306 printf("***Error decrypting for alg %s size %u bits\n", 307 algParams->algStr, (unsigned)algParams->keySizeBits); 308 return testError(quiet); 309 } 310 311 /* moment of truth */ 312 if(!appCompareCssmData(&rptext, &refPtext)) { 313 printf("***DATA MISCOMPARE AFTER DECRYPT alg %s size %u bits\n", 314 algParams->algStr, (unsigned)algParams->keySizeBits); 315 return testError(quiet); 316 } 317 318 /* Free resources */ 319 CSSM_FreeKey(cspHand, NULL, &symKey, CSSM_FALSE); 320 free(symKeyBits); // mallocd by readFile() 321 free(refPTextChars); 322 free(ctextChars); 323 CSSM_FREE(rptext.Data); // mallocd by CSP 324 if(iv) { 325 free(iv); 326 } 327 return 0; 328} 329 330 331int main(int argc, char **argv) 332{ 333 int arg; 334 char *argp; 335 CSSM_DATA ptext; 336 CSSM_CSP_HANDLE cspHand; 337 unsigned currAlg; // ALG_xxx 338 int rtn = 0; 339 340 /* 341 * User-spec'd params 342 */ 343 unsigned minAlg = ALG_FIRST; 344 unsigned maxAlg = ALG_LAST; 345 CSSM_BOOL verbose = CSSM_FALSE; 346 CSSM_BOOL quiet = CSSM_FALSE; 347 CSSM_BOOL bareCsp = CSSM_TRUE; 348 bool encrypt = false; 349 unsigned ptextSize = PTEXT_SIZE_DEF; 350 char *dirName; 351 352 if(argc < 3) { 353 usage(argv); 354 } 355 switch(argv[1][0]) { 356 case 'e': 357 encrypt = true; 358 break; 359 case 'd': 360 encrypt = false; 361 break; 362 default: 363 usage(argv); 364 } 365 dirName = argv[2]; 366 367 for(arg=3; arg<argc; arg++) { 368 argp = argv[arg]; 369 switch(argp[0]) { 370 case 'a': 371 if(argp[1] != '=') { 372 usage(argv); 373 } 374 switch(argp[2]) { 375 case 's': 376 minAlg = maxAlg = ALG_ASC; 377 break; 378 case 'd': 379 minAlg = maxAlg = ALG_DES; 380 break; 381 case '3': 382 minAlg = maxAlg = ALG_3DES; 383 break; 384 case '2': 385 minAlg = maxAlg = ALG_RC2; 386 break; 387 case '4': 388 minAlg = maxAlg = ALG_RC4; 389 break; 390 case '5': 391 minAlg = maxAlg = ALG_RC5; 392 break; 393 case 'a': 394 minAlg = maxAlg = ALG_AES; 395 break; 396 case 'b': 397 minAlg = maxAlg = ALG_BFISH; 398 break; 399 case 'c': 400 minAlg = maxAlg = ALG_CAST; 401 break; 402 default: 403 usage(argv); 404 } 405 break; 406 case 'v': 407 verbose = CSSM_TRUE; 408 break; 409 case 'D': 410 bareCsp = CSSM_FALSE; 411 break; 412 case 'p': 413 ptextSize = atoi(&argp[2]); 414 break; 415 case 'q': 416 quiet = CSSM_TRUE; 417 break; 418 case 'h': 419 default: 420 usage(argv); 421 } 422 } 423 ptext.Data = (uint8 *)CSSM_MALLOC(ptextSize); 424 if(ptext.Data == NULL) { 425 printf("Insufficient heap space\n"); 426 exit(1); 427 } 428 ptext.Length = ptextSize; 429 430 testStartBanner("symReference", argc, argv); 431 432 cspHand = cspDlDbStartup(bareCsp, NULL); 433 if(cspHand == 0) { 434 exit(1); 435 } 436 437 if(chdir(dirName)) { 438 perror(dirName); 439 printf("Error accessing directory %s. Aborting.\n", dirName); 440 exit(1); 441 } 442 for(currAlg=minAlg; currAlg<=maxAlg; currAlg++) { 443 const SymAlgParams *algParams = &symAlgParams[currAlg]; 444 445 if(encrypt) { 446 rtn = doEncrypt(cspHand, algParams, &ptext, quiet, verbose); 447 } 448 else { 449 rtn = doDecrypt(cspHand, algParams, quiet, verbose); 450 } 451 if(rtn) { 452 break; 453 } 454 } /* for algs */ 455 456 cspShutdown(cspHand, bareCsp); 457 if((rtn == 0) && !quiet) { 458 printf("%s test complete\n", argv[0]); 459 } 460 CSSM_FREE(ptext.Data); 461 return rtn; 462} 463 464 465