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
8 * Created by Doug Mitchell 10/31/05.
14 #include <Security/cssm.h>
15 #include <Security/cssmapple.h>
17 #include <security_cdsa_utils/cuFileIo.h>
20 #include "cspdlTesting.h"
27 #define PTEXT_SIZE_DEF 256
28 #define BLOCK_SIZE_MAX 32 /* bytes */
31 * Enumerate algs our own way to allow iteration.
34 ALG_ASC
= 0, /* first must be 0 */
47 #define ALG_FIRST ALG_ASC
48 #define ALG_LAST ALG_CAST
50 static void usage(char **argv
)
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");
66 * map SymAlg to test params
71 CSSM_ALGORITHMS cssmAlg
;
72 CSSM_ENCRYPT_MODE mode
;
74 CSSM_SIZE keySizeBits
;
75 CSSM_SIZE ivLen
; // in bytes
78 static const SymAlgParams symAlgParams
[] =
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
,
96 { ALG_AES256
, "AES256", CSSM_ALGID_AES
, CSSM_ALGMODE_CBCPadIV8
, CSSM_PADDING_PKCS5
,
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 }
104 static void genFileNames(
111 sprintf(keyFile
, "key_%s", algStr
);
112 sprintf(ptextFile
, "ptext_%s", algStr
);
113 sprintf(ctextFile
, "ctext_%s", algStr
);
114 sprintf(ivFile
, "iv_%s", algStr
);
117 /* encrypt, write blobs (key, plaintext, ciphertext, optional IV) to disk */
118 static int doEncrypt(
119 CSSM_CSP_HANDLE cspHand
,
120 const SymAlgParams
*algParams
,
121 CSSM_DATA
*ptext
, // mallocd, length valid, we fill data
125 CSSM_KEY_PTR symKey
= NULL
;
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
];
139 printf("...encrypting, alg %s\n", algParams
->algStr
);
142 /* generate reference key (works with CSPDL) */
143 symKey
= cspGenSymKey(cspHand
, algParams
->cssmAlg
,
145 CSSM_KEYUSE_ANY
, algParams
->keySizeBits
, CSSM_TRUE
);
147 printf("***Error generating key for alg %s size %u bits\n",
148 algParams
->algStr
, (unsigned)algParams
->keySizeBits
);
149 return testError(quiet
);
152 /* get key in raw format (to get the raw blob we write to disk) */
153 crtn
= cspRefKeyToRaw(cspHand
, symKey
, &rawKey
);
155 printf("***Error generating raw key for alg %s size %u bits\n",
156 algParams
->algStr
, (unsigned)algParams
->keySizeBits
);
157 return testError(quiet
);
160 appGetRandomBytes(ptext
->Data
, (unsigned)ptext
->Length
);
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.
166 if(algParams
->ivLen
> 16) {
167 blockSize
= algParams
->ivLen
;
169 if(algParams
->ivLen
) {
170 appGetRandomBytes(iv
, algParams
->ivLen
);
171 ivd
.Length
= algParams
->ivLen
;
175 crtn
= cspStagedEncrypt(cspHand
,
176 algParams
->cssmAlg
, algParams
->mode
, algParams
->padding
,
183 printf("***Error encrypting for alg %s size %u bits\n",
184 algParams
->algStr
, (unsigned)algParams
->keySizeBits
);
185 return testError(quiet
);
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
);
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
);
206 CSSM_FreeKey(cspHand
, NULL
, symKey
, CSSM_FALSE
);
207 CSSM_FreeKey(cspHand
, NULL
, &rawKey
, CSSM_FALSE
);
208 CSSM_FREE(ctext
.Data
);
212 /* read blobs (key, plaintext, ciphertext, optional IV) from disk, decrypt, compare plaintext */
213 static int doDecrypt(
214 CSSM_CSP_HANDLE cspHand
,
215 const SymAlgParams
*algParams
,
221 unsigned symKeyLen
; // in bytes
222 CSSM_DATA symKeyData
;
225 unsigned ctextLen
= 0;
227 CSSM_DATA rptext
= {0, NULL
}; // recovered/decrytped
228 uint8
*refPTextChars
;
229 unsigned refPtextLen
;
230 CSSM_DATA refPtext
= {0, NULL
}; // expected
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
];
242 printf("...decrypting, alg %s\n", algParams
->algStr
);
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.
249 if(algParams
->ivLen
> 16) {
250 blockSize
= algParams
->ivLen
;
252 if(algParams
->ivLen
) {
254 ivd
.Length
= algParams
->ivLen
;
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
);
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
);
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
)) {
281 ctext
.Data
= ctextChars
;
282 ctext
.Length
= ctextLen
;
283 refPtext
.Data
= refPTextChars
;
284 refPtext
.Length
= refPtextLen
;
287 symKeyData
.Data
= symKeyBits
;
288 symKeyData
.Length
= symKeyLen
;
290 crtn
= cspGenSymKeyWithBits(cspHand
, algParams
->cssmAlg
,
291 CSSM_KEYUSE_ANY
, &symKeyData
, symKeyLen
, &symKey
);
293 printf("***Error creating key for alg %s keySize %u\n",
294 algParams
->algStr
, (unsigned)algParams
->keySizeBits
);
295 return testError(quiet
);
298 crtn
= cspStagedDecrypt(cspHand
,
299 algParams
->cssmAlg
, algParams
->mode
, algParams
->padding
,
306 printf("***Error decrypting for alg %s size %u bits\n",
307 algParams
->algStr
, (unsigned)algParams
->keySizeBits
);
308 return testError(quiet
);
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
);
319 CSSM_FreeKey(cspHand
, NULL
, &symKey
, CSSM_FALSE
);
320 free(symKeyBits
); // mallocd by readFile()
323 CSSM_FREE(rptext
.Data
); // mallocd by CSP
331 int main(int argc
, char **argv
)
336 CSSM_CSP_HANDLE cspHand
;
337 unsigned currAlg
; // ALG_xxx
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
;
367 for(arg
=3; arg
<argc
; arg
++) {
376 minAlg
= maxAlg
= ALG_ASC
;
379 minAlg
= maxAlg
= ALG_DES
;
382 minAlg
= maxAlg
= ALG_3DES
;
385 minAlg
= maxAlg
= ALG_RC2
;
388 minAlg
= maxAlg
= ALG_RC4
;
391 minAlg
= maxAlg
= ALG_RC5
;
394 minAlg
= maxAlg
= ALG_AES
;
397 minAlg
= maxAlg
= ALG_BFISH
;
400 minAlg
= maxAlg
= ALG_CAST
;
410 bareCsp
= CSSM_FALSE
;
413 ptextSize
= atoi(&argp
[2]);
423 ptext
.Data
= (uint8
*)CSSM_MALLOC(ptextSize
);
424 if(ptext
.Data
== NULL
) {
425 printf("Insufficient heap space\n");
428 ptext
.Length
= ptextSize
;
430 testStartBanner("symReference", argc
, argv
);
432 cspHand
= cspDlDbStartup(bareCsp
, NULL
);
439 printf("Error accessing directory %s. Aborting.\n", dirName
);
442 for(currAlg
=minAlg
; currAlg
<=maxAlg
; currAlg
++) {
443 const SymAlgParams
*algParams
= &symAlgParams
[currAlg
];
446 rtn
= doEncrypt(cspHand
, algParams
, &ptext
, quiet
, verbose
);
449 rtn
= doDecrypt(cspHand
, algParams
, quiet
, verbose
);
456 cspShutdown(cspHand
, bareCsp
);
457 if((rtn
== 0) && !quiet
) {
458 printf("%s test complete\n", argv
[0]);
460 CSSM_FREE(ptext
.Data
);