]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * The contents of this file are subject to the Mozilla Public | |
3 | * License Version 1.1 (the "License"); you may not use this file | |
4 | * except in compliance with the License. You may obtain a copy of | |
5 | * the License at http://www.mozilla.org/MPL/ | |
6 | * | |
7 | * Software distributed under the License is distributed on an "AS | |
8 | * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | |
9 | * implied. See the License for the specific language governing | |
10 | * rights and limitations under the License. | |
11 | * | |
12 | * The Original Code is the Netscape security libraries. | |
13 | * | |
14 | * The Initial Developer of the Original Code is Netscape | |
15 | * Communications Corporation. Portions created by Netscape are | |
16 | * Copyright (C) 1994-2000 Netscape Communications Corporation. All | |
17 | * Rights Reserved. | |
18 | * | |
19 | * Contributor(s): | |
20 | * | |
21 | * Alternatively, the contents of this file may be used under the | |
22 | * terms of the GNU General Public License Version 2 or later (the | |
23 | * "GPL"), in which case the provisions of the GPL are applicable | |
24 | * instead of those above. If you wish to allow use of your | |
25 | * version of this file only under the terms of the GPL and not to | |
26 | * allow others to use your version of this file under the MPL, | |
27 | * indicate your decision by deleting the provisions above and | |
28 | * replace them with the notice and other provisions required by | |
29 | * the GPL. If you do not delete the provisions above, a recipient | |
30 | * may use your version of this file under either the MPL or the | |
31 | * GPL. | |
32 | */ | |
33 | ||
34 | /* | |
35 | * Encryption/decryption routines for CMS implementation, none of which are exported. | |
36 | * | |
37 | */ | |
d8f41ccd | 38 | #include <limits.h> |
b1ab9ed8 A |
39 | |
40 | #include "cmslocal.h" | |
41 | ||
42 | #include "secoid.h" | |
43 | #include <security_asn1/secerr.h> | |
44 | #include <security_asn1/secasn1.h> | |
d8f41ccd A |
45 | #include <security_asn1/secport.h> |
46 | ||
b1ab9ed8 | 47 | #include <Security/SecAsn1Templates.h> |
d8f41ccd A |
48 | #include <Security/SecRandom.h> |
49 | #include <CommonCrypto/CommonCryptor.h> | |
b1ab9ed8 A |
50 | |
51 | /* | |
52 | * ------------------------------------------------------------------- | |
53 | * Cipher stuff. | |
54 | */ | |
55 | ||
56 | #if 0 | |
57 | typedef OSStatus (*nss_cms_cipher_function) (void *, unsigned char *, unsigned int *, | |
58 | unsigned int, const unsigned char *, unsigned int); | |
59 | typedef OSStatus (*nss_cms_cipher_destroy) (void *, Boolean); | |
60 | #endif | |
61 | ||
62 | #define BLOCK_SIZE 4096 | |
63 | ||
64 | struct SecCmsCipherContextStr { | |
65 | #if 1 | |
d8f41ccd | 66 | void * cc; /* CSP CONTEXT */ |
b1ab9ed8 | 67 | Boolean encrypt; /* encrypt / decrypt switch */ |
d8f41ccd | 68 | int block_size; /* block & pad sizes for cipher */ |
b1ab9ed8 A |
69 | #else |
70 | void * cx; /* PK11 cipher context */ | |
71 | nss_cms_cipher_function doit; | |
72 | nss_cms_cipher_destroy destroy; | |
73 | Boolean encrypt; /* encrypt / decrypt switch */ | |
b1ab9ed8 A |
74 | int pad_size; |
75 | int pending_count; /* pending data (not yet en/decrypted */ | |
76 | unsigned char pending_buf[BLOCK_SIZE];/* because of blocking */ | |
77 | #endif | |
78 | }; | |
79 | ||
80 | typedef struct sec_rc2cbcParameterStr { | |
d8f41ccd A |
81 | SecAsn1Item rc2ParameterVersion; |
82 | SecAsn1Item iv; | |
b1ab9ed8 A |
83 | } sec_rc2cbcParameter; |
84 | ||
d8f41ccd | 85 | __unused static const SecAsn1Template sec_rc2cbc_parameter_template[] = { |
b1ab9ed8 A |
86 | { SEC_ASN1_SEQUENCE, |
87 | 0, NULL, sizeof(sec_rc2cbcParameter) }, | |
88 | { SEC_ASN1_INTEGER | SEC_ASN1_SIGNED_INT, | |
89 | offsetof(sec_rc2cbcParameter,rc2ParameterVersion) }, | |
90 | { SEC_ASN1_OCTET_STRING, | |
91 | offsetof(sec_rc2cbcParameter,iv) }, | |
92 | { 0 } | |
93 | }; | |
94 | ||
b1ab9ed8 A |
95 | /* default IV size in bytes */ |
96 | #define DEFAULT_IV_SIZE 8 | |
97 | /* IV/block size for AES */ | |
98 | #define AES_BLOCK_SIZE 16 | |
99 | /* max IV size in bytes */ | |
100 | #define MAX_IV_SIZE AES_BLOCK_SIZE | |
101 | ||
d8f41ccd A |
102 | #ifndef kCCKeySizeMaxRC2 |
103 | #define kCCKeySizeMaxRC2 16 | |
104 | #endif | |
105 | #ifndef kCCBlockSizeRC2 | |
106 | #define kCCBlockSizeRC2 8 | |
107 | #endif | |
d8f41ccd | 108 | |
b1ab9ed8 A |
109 | static SecCmsCipherContextRef |
110 | SecCmsCipherContextStart(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid, Boolean encrypt) | |
111 | { | |
112 | SecCmsCipherContextRef cc; | |
b1ab9ed8 A |
113 | SECOidData *oidData; |
114 | SECOidTag algtag; | |
d8f41ccd A |
115 | OSStatus rv; |
116 | uint8_t ivbuf[MAX_IV_SIZE]; | |
117 | SecAsn1Item initVector = { DEFAULT_IV_SIZE, ivbuf }; | |
d8f41ccd A |
118 | CCCryptorRef ciphercc = NULL; |
119 | CCOptions cipheroptions = kCCOptionPKCS7Padding; | |
120 | int cipher_blocksize = 0; | |
b1ab9ed8 A |
121 | // @@@ Add support for PBE based stuff |
122 | ||
123 | oidData = SECOID_FindOID(&algid->algorithm); | |
124 | if (!oidData) | |
125 | goto loser; | |
126 | algtag = oidData->offset; | |
b1ab9ed8 | 127 | |
d8f41ccd A |
128 | CCAlgorithm alg = -1; |
129 | switch (algtag) { | |
130 | case SEC_OID_DES_CBC: | |
131 | alg = kCCAlgorithmDES; | |
132 | cipher_blocksize = kCCBlockSizeDES; | |
133 | break; | |
134 | case SEC_OID_DES_EDE3_CBC: | |
135 | alg = kCCAlgorithm3DES; | |
136 | cipher_blocksize = kCCBlockSize3DES; | |
137 | break; | |
138 | case SEC_OID_RC2_CBC: | |
139 | alg = kCCAlgorithmRC2; | |
140 | cipher_blocksize = kCCBlockSizeRC2; | |
141 | break; | |
142 | case SEC_OID_AES_128_CBC: | |
143 | case SEC_OID_AES_192_CBC: | |
144 | case SEC_OID_AES_256_CBC: | |
145 | alg = kCCAlgorithmAES128; | |
146 | cipher_blocksize = kCCBlockSizeAES128; | |
147 | initVector.Length = AES_BLOCK_SIZE; | |
148 | break; | |
149 | default: | |
150 | goto loser; | |
151 | } | |
b1ab9ed8 A |
152 | |
153 | if (encrypt) | |
154 | { | |
d8f41ccd A |
155 | if (SecRandomCopyBytes(kSecRandomDefault, |
156 | initVector.Length, initVector.Data)) | |
157 | goto loser; | |
b1ab9ed8 A |
158 | |
159 | // Put IV into algid.parameters | |
160 | switch (algtag) | |
161 | { | |
162 | case SEC_OID_RC4: | |
163 | case SEC_OID_DES_EDE3_CBC: | |
164 | case SEC_OID_DES_EDE: | |
165 | case SEC_OID_DES_CBC: | |
166 | case SEC_OID_AES_128_CBC: | |
167 | case SEC_OID_AES_192_CBC: | |
168 | case SEC_OID_AES_256_CBC: | |
169 | case SEC_OID_FORTEZZA_SKIPJACK: | |
170 | case SEC_OID_DES_ECB: | |
171 | case SEC_OID_AES_128_ECB: | |
172 | case SEC_OID_AES_192_ECB: | |
173 | case SEC_OID_AES_256_ECB: | |
174 | case SEC_OID_DES_OFB: | |
175 | case SEC_OID_DES_CFB: | |
176 | /* Just encode the initVector as an octet string. */ | |
177 | if (!SEC_ASN1EncodeItem(poolp, &algid->parameters, | |
178 | &initVector, kSecAsn1OctetStringTemplate)) | |
179 | goto loser; | |
180 | break; | |
b1ab9ed8 | 181 | case SEC_OID_RC2_CBC: |
b1ab9ed8 A |
182 | case SEC_OID_RC5_CBC_PAD: |
183 | default: | |
184 | // @@@ Implement rc5 params stuff. | |
185 | goto loser; | |
186 | break; | |
187 | } | |
188 | } | |
189 | else | |
190 | { | |
191 | // Extract IV from algid.parameters | |
192 | // Put IV into algid.parameters | |
193 | switch (algtag) | |
194 | { | |
195 | case SEC_OID_RC4: | |
196 | case SEC_OID_DES_EDE3_CBC: | |
197 | case SEC_OID_DES_EDE: | |
198 | case SEC_OID_DES_CBC: | |
199 | case SEC_OID_AES_128_CBC: | |
200 | case SEC_OID_AES_192_CBC: | |
201 | case SEC_OID_AES_256_CBC: | |
202 | case SEC_OID_FORTEZZA_SKIPJACK: | |
203 | case SEC_OID_DES_ECB: | |
204 | case SEC_OID_AES_128_ECB: | |
205 | case SEC_OID_AES_192_ECB: | |
206 | case SEC_OID_AES_256_ECB: | |
207 | case SEC_OID_DES_OFB: | |
208 | case SEC_OID_DES_CFB: | |
209 | { | |
d8f41ccd | 210 | SecAsn1Item iv = {}; |
b1ab9ed8 A |
211 | /* Just decode the initVector from an octet string. */ |
212 | rv = SEC_ASN1DecodeItem(NULL, &iv, kSecAsn1OctetStringTemplate, &(algid->parameters)); | |
213 | if (rv) | |
214 | goto loser; | |
215 | if (initVector.Length != iv.Length) { | |
216 | PORT_Free(iv.Data); | |
217 | goto loser; | |
218 | } | |
219 | memcpy(initVector.Data, iv.Data, initVector.Length); | |
220 | PORT_Free(iv.Data); | |
221 | break; | |
222 | } | |
223 | case SEC_OID_RC2_CBC: | |
b1ab9ed8 A |
224 | case SEC_OID_RC5_CBC_PAD: |
225 | default: | |
226 | // @@@ Implement rc5 params stuff. | |
227 | goto loser; | |
228 | break; | |
229 | } | |
230 | } | |
231 | ||
d8f41ccd A |
232 | if (CCCryptorCreate(encrypt ? kCCEncrypt : kCCDecrypt, |
233 | alg, cipheroptions, CFDataGetBytePtr(key), CFDataGetLength(key), | |
234 | initVector.Data, &ciphercc)) | |
235 | goto loser; | |
b1ab9ed8 A |
236 | |
237 | cc = (SecCmsCipherContextRef)PORT_ZAlloc(sizeof(SecCmsCipherContext)); | |
238 | if (cc == NULL) | |
239 | goto loser; | |
240 | ||
241 | cc->cc = ciphercc; | |
242 | cc->encrypt = encrypt; | |
d8f41ccd | 243 | cc->block_size =cipher_blocksize; |
b1ab9ed8 A |
244 | return cc; |
245 | loser: | |
246 | if (ciphercc) | |
d8f41ccd | 247 | CCCryptorRelease(ciphercc); |
b1ab9ed8 A |
248 | |
249 | return NULL; | |
250 | } | |
251 | ||
252 | /* | |
253 | * SecCmsCipherContextStartDecrypt - create a cipher context to do decryption | |
254 | * based on the given bulk * encryption key and algorithm identifier (which may include an iv). | |
255 | * | |
256 | * XXX Once both are working, it might be nice to combine this and the | |
257 | * function below (for starting up encryption) into one routine, and just | |
258 | * have two simple cover functions which call it. | |
259 | */ | |
260 | SecCmsCipherContextRef | |
261 | SecCmsCipherContextStartDecrypt(SecSymmetricKeyRef key, SECAlgorithmID *algid) | |
262 | { | |
263 | return SecCmsCipherContextStart(NULL, key, algid, PR_FALSE); | |
b1ab9ed8 A |
264 | } |
265 | ||
266 | /* | |
267 | * SecCmsCipherContextStartEncrypt - create a cipher object to do encryption, | |
268 | * based on the given bulk encryption key and algorithm tag. Fill in the algorithm | |
269 | * identifier (which may include an iv) appropriately. | |
270 | * | |
271 | * XXX Once both are working, it might be nice to combine this and the | |
272 | * function above (for starting up decryption) into one routine, and just | |
273 | * have two simple cover functions which call it. | |
274 | */ | |
275 | SecCmsCipherContextRef | |
276 | SecCmsCipherContextStartEncrypt(PRArenaPool *poolp, SecSymmetricKeyRef key, SECAlgorithmID *algid) | |
277 | { | |
278 | return SecCmsCipherContextStart(poolp, key, algid, PR_TRUE); | |
b1ab9ed8 A |
279 | } |
280 | ||
281 | void | |
282 | SecCmsCipherContextDestroy(SecCmsCipherContextRef cc) | |
283 | { | |
284 | PORT_Assert(cc != NULL); | |
285 | if (cc == NULL) | |
286 | return; | |
6b200bc3 | 287 | |
d8f41ccd | 288 | CCCryptorRelease(cc->cc); |
6b200bc3 | 289 | |
b1ab9ed8 A |
290 | PORT_Free(cc); |
291 | } | |
292 | ||
427c49bc | 293 | static unsigned int |
b1ab9ed8 A |
294 | SecCmsCipherContextLength(SecCmsCipherContextRef cc, unsigned int input_len, Boolean final, Boolean encrypt) |
295 | { | |
d8f41ccd | 296 | return ((input_len + cc->block_size - 1) / cc->block_size * cc->block_size) + (final ? cc->block_size : 0); |
b1ab9ed8 A |
297 | } |
298 | ||
299 | /* | |
300 | * SecCmsCipherContextDecryptLength - find the output length of the next call to decrypt. | |
301 | * | |
302 | * cc - the cipher context | |
303 | * input_len - number of bytes used as input | |
304 | * final - true if this is the final chunk of data | |
305 | * | |
306 | * Result can be used to perform memory allocations. Note that the amount | |
307 | * is exactly accurate only when not doing a block cipher or when final | |
308 | * is false, otherwise it is an upper bound on the amount because until | |
309 | * we see the data we do not know how many padding bytes there are | |
310 | * (always between 1 and bsize). | |
311 | * | |
312 | * Note that this can return zero, which does not mean that the decrypt | |
313 | * operation can be skipped! (It simply means that there are not enough | |
314 | * bytes to make up an entire block; the bytes will be reserved until | |
315 | * there are enough to encrypt/decrypt at least one block.) However, | |
316 | * if zero is returned it *does* mean that no output buffer need be | |
317 | * passed in to the subsequent decrypt operation, as no output bytes | |
318 | * will be stored. | |
319 | */ | |
d8f41ccd A |
320 | unsigned int |
321 | SecCmsCipherContextDecryptLength(SecCmsCipherContextRef cc, unsigned int input_len, Boolean final) | |
b1ab9ed8 | 322 | { |
d8f41ccd | 323 | return SecCmsCipherContextLength(cc, input_len, final, PR_FALSE); |
b1ab9ed8 A |
324 | } |
325 | ||
326 | /* | |
327 | * SecCmsCipherContextEncryptLength - find the output length of the next call to encrypt. | |
328 | * | |
329 | * cc - the cipher context | |
330 | * input_len - number of bytes used as input | |
331 | * final - true if this is the final chunk of data | |
332 | * | |
333 | * Result can be used to perform memory allocations. | |
334 | * | |
335 | * Note that this can return zero, which does not mean that the encrypt | |
336 | * operation can be skipped! (It simply means that there are not enough | |
337 | * bytes to make up an entire block; the bytes will be reserved until | |
338 | * there are enough to encrypt/decrypt at least one block.) However, | |
339 | * if zero is returned it *does* mean that no output buffer need be | |
340 | * passed in to the subsequent encrypt operation, as no output bytes | |
341 | * will be stored. | |
342 | */ | |
d8f41ccd A |
343 | unsigned int |
344 | SecCmsCipherContextEncryptLength(SecCmsCipherContextRef cc, unsigned int input_len, Boolean final) | |
b1ab9ed8 | 345 | { |
d8f41ccd | 346 | return SecCmsCipherContextLength(cc, input_len, final, PR_TRUE); |
b1ab9ed8 A |
347 | } |
348 | ||
349 | ||
427c49bc | 350 | static OSStatus |
b1ab9ed8 | 351 | SecCmsCipherContextCrypt(SecCmsCipherContextRef cc, unsigned char *output, |
d8f41ccd A |
352 | unsigned int *output_len_p, unsigned int max_output_len, |
353 | const unsigned char *input, unsigned int input_len, | |
b1ab9ed8 A |
354 | Boolean final, Boolean encrypt) |
355 | { | |
d8f41ccd | 356 | size_t bytes_output = 0; |
b1ab9ed8 A |
357 | OSStatus rv = 0; |
358 | ||
359 | if (input_len) | |
360 | { | |
d8f41ccd | 361 | rv = CCCryptorUpdate(cc->cc, input, input_len, output, max_output_len, &bytes_output); |
b1ab9ed8 A |
362 | } |
363 | ||
364 | if (!rv && final) | |
365 | { | |
d8f41ccd A |
366 | size_t bytes_output_final = 0; |
367 | rv = CCCryptorFinal(cc->cc, output+bytes_output, max_output_len-bytes_output, &bytes_output_final); | |
368 | bytes_output += bytes_output_final; | |
b1ab9ed8 | 369 | } |
6b200bc3 | 370 | |
b1ab9ed8 A |
371 | if (rv) |
372 | PORT_SetError(SEC_ERROR_BAD_DATA); | |
373 | else if (output_len_p) | |
d8f41ccd | 374 | *output_len_p = (unsigned int)bytes_output; /* This cast is safe since bytes_output can't be bigger than max_output_len */ |
b1ab9ed8 A |
375 | |
376 | return rv; | |
377 | } | |
378 | ||
379 | /* | |
380 | * SecCmsCipherContextDecrypt - do the decryption | |
381 | * | |
382 | * cc - the cipher context | |
383 | * output - buffer for decrypted result bytes | |
384 | * output_len_p - number of bytes in output | |
385 | * max_output_len - upper bound on bytes to put into output | |
386 | * input - pointer to input bytes | |
387 | * input_len - number of input bytes | |
388 | * final - true if this is the final chunk of data | |
389 | * | |
390 | * Decrypts a given length of input buffer (starting at "input" and | |
391 | * containing "input_len" bytes), placing the decrypted bytes in | |
392 | * "output" and storing the output length in "*output_len_p". | |
393 | * "cc" is the return value from SecCmsCipherStartDecrypt. | |
394 | * When "final" is true, this is the last of the data to be decrypted. | |
395 | * | |
396 | * This is much more complicated than it sounds when the cipher is | |
397 | * a block-type, meaning that the decryption function will only | |
398 | * operate on whole blocks. But our caller is operating stream-wise, | |
399 | * and can pass in any number of bytes. So we need to keep track | |
400 | * of block boundaries. We save excess bytes between calls in "cc". | |
401 | * We also need to determine which bytes are padding, and remove | |
402 | * them from the output. We can only do this step when we know we | |
403 | * have the final block of data. PKCS #7 specifies that the padding | |
404 | * used for a block cipher is a string of bytes, each of whose value is | |
405 | * the same as the length of the padding, and that all data is padded. | |
406 | * (Even data that starts out with an exact multiple of blocks gets | |
407 | * added to it another block, all of which is padding.) | |
408 | */ | |
409 | OSStatus | |
410 | SecCmsCipherContextDecrypt(SecCmsCipherContextRef cc, unsigned char *output, | |
d8f41ccd A |
411 | unsigned int *output_len_p, unsigned int max_output_len, |
412 | const unsigned char *input, unsigned int input_len, | |
b1ab9ed8 A |
413 | Boolean final) |
414 | { | |
b1ab9ed8 A |
415 | return SecCmsCipherContextCrypt(cc, output, |
416 | output_len_p, max_output_len, | |
417 | input, input_len, | |
418 | final, PR_FALSE); | |
b1ab9ed8 A |
419 | } |
420 | ||
421 | /* | |
422 | * SecCmsCipherContextEncrypt - do the encryption | |
423 | * | |
424 | * cc - the cipher context | |
425 | * output - buffer for decrypted result bytes | |
426 | * output_len_p - number of bytes in output | |
427 | * max_output_len - upper bound on bytes to put into output | |
428 | * input - pointer to input bytes | |
429 | * input_len - number of input bytes | |
430 | * final - true if this is the final chunk of data | |
431 | * | |
432 | * Encrypts a given length of input buffer (starting at "input" and | |
433 | * containing "input_len" bytes), placing the encrypted bytes in | |
434 | * "output" and storing the output length in "*output_len_p". | |
435 | * "cc" is the return value from SecCmsCipherStartEncrypt. | |
436 | * When "final" is true, this is the last of the data to be encrypted. | |
437 | * | |
438 | * This is much more complicated than it sounds when the cipher is | |
439 | * a block-type, meaning that the encryption function will only | |
440 | * operate on whole blocks. But our caller is operating stream-wise, | |
441 | * and can pass in any number of bytes. So we need to keep track | |
442 | * of block boundaries. We save excess bytes between calls in "cc". | |
443 | * We also need to add padding bytes at the end. PKCS #7 specifies | |
444 | * that the padding used for a block cipher is a string of bytes, | |
445 | * each of whose value is the same as the length of the padding, | |
446 | * and that all data is padded. (Even data that starts out with | |
447 | * an exact multiple of blocks gets added to it another block, | |
448 | * all of which is padding.) | |
449 | * | |
450 | * XXX I would kind of like to combine this with the function above | |
451 | * which does decryption, since they have a lot in common. But the | |
452 | * tricky parts about padding and filling blocks would be much | |
453 | * harder to read that way, so I left them separate. At least for | |
454 | * now until it is clear that they are right. | |
455 | */ | |
456 | OSStatus | |
457 | SecCmsCipherContextEncrypt(SecCmsCipherContextRef cc, unsigned char *output, | |
d8f41ccd A |
458 | unsigned int *output_len_p, unsigned int max_output_len, |
459 | const unsigned char *input, unsigned int input_len, | |
b1ab9ed8 A |
460 | Boolean final) |
461 | { | |
b1ab9ed8 A |
462 | return SecCmsCipherContextCrypt(cc, output, |
463 | output_len_p, max_output_len, | |
464 | input, input_len, | |
465 | final, PR_TRUE); | |
b1ab9ed8 | 466 | } |