]>
Commit | Line | Data |
---|---|---|
bd940221 | 1 | /* R_ENHANC.C - cryptographic enhancements for RSAREF |
2 | */ | |
3 | ||
4 | /* Copyright (C) RSA Laboratories, a division of RSA Data Security, | |
5 | Inc., created 1991. All rights reserved. | |
6 | */ | |
7 | ||
8 | #include "global.h" | |
9 | #include "rsaref.h" | |
10 | #include "r_random.h" | |
11 | #include "rsa.h" | |
12 | ||
13 | /* DigestInfo encoding is DIGEST_INFO_A, then 2 or 5 (for MD2/MD5), | |
14 | then DIGEST_INFO_B, then 16-byte message digest. | |
15 | */ | |
16 | ||
17 | static unsigned char DIGEST_INFO_A[] = { | |
18 | 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, | |
19 | 0x0d, 0x02 | |
20 | }; | |
21 | #define DIGEST_INFO_A_LEN sizeof (DIGEST_INFO_A) | |
22 | ||
23 | static unsigned char DIGEST_INFO_B[] = { 0x05, 0x00, 0x04, 0x10 }; | |
24 | #define DIGEST_INFO_B_LEN sizeof (DIGEST_INFO_B) | |
25 | ||
26 | #define DIGEST_INFO_LEN (DIGEST_INFO_A_LEN + 1 + DIGEST_INFO_B_LEN + 16) | |
27 | ||
28 | static unsigned char *PADDING[] = { | |
29 | (unsigned char *)"", (unsigned char *)"\001", (unsigned char *)"\002\002", | |
30 | (unsigned char *)"\003\003\003", (unsigned char *)"\004\004\004\004", | |
31 | (unsigned char *)"\005\005\005\005\005", | |
32 | (unsigned char *)"\006\006\006\006\006\006", | |
33 | (unsigned char *)"\007\007\007\007\007\007\007", | |
34 | (unsigned char *)"\010\010\010\010\010\010\010\010" | |
35 | }; | |
36 | ||
37 | #define MAX_ENCRYPTED_KEY_LEN MAX_RSA_MODULUS_LEN | |
38 | ||
39 | static void R_EncodeDigestInfo PROTO_LIST | |
40 | ((unsigned char *, int, unsigned char *)); | |
41 | static void EncryptPEMUpdateFinal PROTO_LIST | |
42 | ((R_ENVELOPE_CTX *, unsigned char *, unsigned int *, unsigned char *, | |
43 | unsigned int)); | |
44 | static int DecryptPEMUpdateFinal PROTO_LIST | |
45 | ((R_ENVELOPE_CTX *, unsigned char *, unsigned int *, unsigned char *, | |
46 | unsigned int)); | |
47 | static int CipherInit PROTO_LIST | |
48 | ((R_ENVELOPE_CTX *, int, unsigned char *, unsigned char *, int)); | |
49 | static void CipherUpdate PROTO_LIST | |
50 | ((R_ENVELOPE_CTX *, unsigned char *, unsigned char *, unsigned int)); | |
51 | static void CipherRestart PROTO_LIST ((R_ENVELOPE_CTX *)); | |
52 | ||
53 | int R_DigestInit (context, digestAlgorithm) | |
54 | R_DIGEST_CTX *context; /* new context */ | |
55 | int digestAlgorithm; /* message-digest algorithm */ | |
56 | { | |
57 | context->digestAlgorithm = digestAlgorithm; | |
58 | ||
59 | switch (digestAlgorithm) { | |
60 | case DA_MD2: | |
61 | MD2Init (&context->context.md2); | |
62 | break; | |
63 | ||
64 | case DA_MD5: | |
65 | MD5Init (&context->context.md5); | |
66 | break; | |
67 | ||
68 | default: | |
69 | return (RE_DIGEST_ALGORITHM); | |
70 | } | |
71 | ||
72 | return (0); | |
73 | } | |
74 | ||
75 | int R_DigestUpdate (context, partIn, partInLen) | |
76 | R_DIGEST_CTX *context; /* context */ | |
77 | unsigned char *partIn; /* next data part */ | |
78 | unsigned int partInLen; /* length of next data part */ | |
79 | { | |
80 | if (context->digestAlgorithm == DA_MD2) | |
81 | MD2Update (&context->context.md2, partIn, partInLen); | |
82 | else | |
83 | MD5Update (&context->context.md5, partIn, partInLen); | |
84 | return (0); | |
85 | } | |
86 | ||
87 | int R_DigestFinal (context, digest, digestLen) | |
88 | R_DIGEST_CTX *context; /* context */ | |
89 | unsigned char *digest; /* message digest */ | |
90 | unsigned int *digestLen; /* length of message digest */ | |
91 | { | |
92 | *digestLen = 16; | |
93 | if (context->digestAlgorithm == DA_MD2) | |
94 | MD2Final (digest, &context->context.md2); | |
95 | else | |
96 | MD5Final (digest, &context->context.md5); | |
97 | ||
98 | return (0); | |
99 | } | |
100 | ||
101 | int R_SignInit (context, digestAlgorithm) | |
102 | R_SIGNATURE_CTX *context; /* new context */ | |
103 | int digestAlgorithm; /* message-digest algorithm */ | |
104 | { | |
105 | return (R_DigestInit (&context->digestContext, digestAlgorithm)); | |
106 | } | |
107 | ||
108 | int R_SignUpdate (context, partIn, partInLen) | |
109 | R_SIGNATURE_CTX *context; /* context */ | |
110 | unsigned char *partIn; /* next data part */ | |
111 | unsigned int partInLen; /* length of next data part */ | |
112 | { | |
113 | return (R_DigestUpdate (&context->digestContext, partIn, partInLen)); | |
114 | } | |
115 | ||
116 | int R_SignFinal (context, signature, signatureLen, privateKey) | |
117 | R_SIGNATURE_CTX *context; /* context */ | |
118 | unsigned char *signature; /* signature */ | |
119 | unsigned int *signatureLen; /* length of signature */ | |
120 | R_RSA_PRIVATE_KEY *privateKey; /* signer's RSA private key */ | |
121 | { | |
122 | int status; | |
123 | unsigned char digest[MAX_DIGEST_LEN], digestInfo[DIGEST_INFO_LEN]; | |
124 | unsigned int digestLen; | |
125 | ||
126 | do { | |
127 | if ((status = R_DigestFinal (&context->digestContext, digest, &digestLen)) | |
128 | != 0) | |
129 | break; | |
130 | ||
131 | R_EncodeDigestInfo | |
132 | (digestInfo, context->digestContext.digestAlgorithm, digest); | |
133 | ||
134 | if (RSAPrivateEncrypt | |
135 | (signature, signatureLen, digestInfo, DIGEST_INFO_LEN, privateKey) | |
136 | != 0) { | |
137 | status = RE_PRIVATE_KEY; | |
138 | break; | |
139 | } | |
140 | ||
141 | /* Reset for another verification. Assume Init won't fail */ | |
142 | R_DigestInit | |
143 | (&context->digestContext, context->digestContext.digestAlgorithm); | |
144 | } while (0); | |
145 | ||
146 | /* Zeroize potentially sensitive information. | |
147 | */ | |
148 | R_memset ((POINTER)digest, 0, sizeof (digest)); | |
149 | R_memset ((POINTER)digestInfo, 0, sizeof (digestInfo)); | |
150 | ||
151 | return (status); | |
152 | } | |
153 | ||
154 | int R_VerifyInit (context, digestAlgorithm) | |
155 | R_SIGNATURE_CTX *context; /* new context */ | |
156 | int digestAlgorithm; /* message-digest algorithm */ | |
157 | { | |
158 | return (R_DigestInit (&context->digestContext, digestAlgorithm)); | |
159 | } | |
160 | ||
161 | int R_VerifyUpdate (context, partIn, partInLen) | |
162 | R_SIGNATURE_CTX *context; /* context */ | |
163 | unsigned char *partIn; /* next data part */ | |
164 | unsigned int partInLen; /* length of next data part */ | |
165 | { | |
166 | return (R_DigestUpdate (&context->digestContext, partIn, partInLen)); | |
167 | } | |
168 | ||
169 | int R_VerifyFinal (context, signature, signatureLen, publicKey) | |
170 | R_SIGNATURE_CTX *context; /* context */ | |
171 | unsigned char *signature; /* signature */ | |
172 | unsigned int signatureLen; /* length of signature */ | |
173 | R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ | |
174 | { | |
175 | int status; | |
176 | unsigned char digest[MAX_DIGEST_LEN], digestInfo[DIGEST_INFO_LEN], | |
177 | originalDigestInfo[MAX_SIGNATURE_LEN]; | |
178 | unsigned int originalDigestInfoLen, digestLen; | |
179 | ||
180 | if (signatureLen > MAX_SIGNATURE_LEN) | |
181 | return (RE_LEN); | |
182 | ||
183 | status = 0; | |
184 | do { | |
185 | if ((status = R_DigestFinal (&context->digestContext, digest, &digestLen)) | |
186 | != 0) | |
187 | break; | |
188 | ||
189 | R_EncodeDigestInfo | |
190 | (digestInfo, context->digestContext.digestAlgorithm, digest); | |
191 | ||
192 | if (RSAPublicDecrypt | |
193 | (originalDigestInfo, &originalDigestInfoLen, signature, signatureLen, | |
194 | publicKey) != 0) { | |
195 | status = RE_PUBLIC_KEY; | |
196 | break; | |
197 | } | |
198 | ||
199 | if ((originalDigestInfoLen != DIGEST_INFO_LEN) || | |
200 | (R_memcmp | |
201 | ((POINTER)originalDigestInfo, (POINTER)digestInfo, | |
202 | DIGEST_INFO_LEN))) { | |
203 | status = RE_SIGNATURE; | |
204 | break; | |
205 | } | |
206 | ||
207 | /* Reset for another verification. Assume Init won't fail */ | |
208 | R_DigestInit | |
209 | (&context->digestContext, context->digestContext.digestAlgorithm); | |
210 | } while (0); | |
211 | ||
212 | /* Zeroize potentially sensitive information. | |
213 | */ | |
214 | R_memset ((POINTER)digest, 0, sizeof (digest)); | |
215 | R_memset ((POINTER)digestInfo, 0, sizeof (digestInfo)); | |
216 | R_memset ((POINTER)originalDigestInfo, 0, sizeof (originalDigestInfo)); | |
217 | ||
218 | return (status); | |
219 | } | |
220 | ||
221 | /* Caller must ASCII recode the encrypted keys if desired. | |
222 | */ | |
223 | int R_SealInit | |
224 | (context, encryptedKeys, encryptedKeyLens, iv, publicKeyCount, publicKeys, | |
225 | encryptionAlgorithm, randomStruct) | |
226 | R_ENVELOPE_CTX *context; /* new context */ | |
227 | unsigned char **encryptedKeys; /* encrypted keys */ | |
228 | unsigned int *encryptedKeyLens; /* lengths of encrypted keys */ | |
229 | unsigned char iv[8]; /* initialization vector */ | |
230 | unsigned int publicKeyCount; /* number of public keys */ | |
231 | R_RSA_PUBLIC_KEY **publicKeys; /* public keys */ | |
232 | int encryptionAlgorithm; /* data encryption algorithm */ | |
233 | R_RANDOM_STRUCT *randomStruct; /* random structure */ | |
234 | { | |
235 | int status; | |
236 | unsigned char key[24]; | |
237 | unsigned int keyLen, i; | |
238 | ||
239 | do { | |
240 | context->encryptionAlgorithm = encryptionAlgorithm; | |
241 | ||
242 | keyLen = (encryptionAlgorithm == EA_DES_CBC) ? 8 : 24; | |
243 | if ((status = R_GenerateBytes (key, keyLen, randomStruct)) != 0) | |
244 | break; | |
245 | if ((status = R_GenerateBytes (iv, 8, randomStruct)) != 0) | |
246 | break; | |
247 | ||
248 | if (encryptionAlgorithm == EA_DES_EDE2_CBC) | |
249 | /* Make both E keys the same */ | |
250 | R_memcpy ((POINTER)(key + 16), (POINTER)key, 8); | |
251 | ||
252 | if ((status = CipherInit (context, encryptionAlgorithm, key, iv, 1)) != 0) | |
253 | break; | |
254 | ||
255 | for (i = 0; i < publicKeyCount; ++i) { | |
256 | if (RSAPublicEncrypt | |
257 | (encryptedKeys[i], &encryptedKeyLens[i], key, keyLen, | |
258 | publicKeys[i], randomStruct)) { | |
259 | status = RE_PUBLIC_KEY; | |
260 | break; | |
261 | } | |
262 | } | |
263 | if (status != 0) | |
264 | break; | |
265 | ||
266 | context->bufferLen = 0; | |
267 | } while (0); | |
268 | ||
269 | /* Zeroize sensitive information. | |
270 | */ | |
271 | R_memset ((POINTER)key, 0, sizeof (key)); | |
272 | ||
273 | return (status); | |
274 | } | |
275 | ||
276 | /* Assume partOut buffer is at least partInLen + 7, since this may flush | |
277 | buffered input. | |
278 | */ | |
279 | int R_SealUpdate (context, partOut, partOutLen, partIn, partInLen) | |
280 | R_ENVELOPE_CTX *context; /* context */ | |
281 | unsigned char *partOut; /* next encrypted data part */ | |
282 | unsigned int *partOutLen; /* length of next encrypted data part */ | |
283 | unsigned char *partIn; /* next data part */ | |
284 | unsigned int partInLen; /* length of next data part */ | |
285 | { | |
286 | unsigned int tempLen; | |
287 | ||
288 | tempLen = 8 - context->bufferLen; | |
289 | if (partInLen < tempLen) { | |
290 | /* Just accumulate into buffer. | |
291 | */ | |
292 | R_memcpy | |
293 | ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn, | |
294 | partInLen); | |
295 | context->bufferLen += partInLen; | |
296 | *partOutLen = 0; | |
297 | return (0); | |
298 | } | |
299 | ||
300 | /* Fill the buffer and encrypt. | |
301 | */ | |
302 | R_memcpy | |
303 | ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn, | |
304 | tempLen); | |
305 | CipherUpdate (context, partOut, context->buffer, 8); | |
306 | partIn += tempLen; | |
307 | partInLen -= tempLen; | |
308 | partOut += 8; | |
309 | *partOutLen = 8; | |
310 | ||
311 | /* Encrypt as many 8-byte blocks as possible. | |
312 | */ | |
313 | tempLen = 8 * (partInLen / 8); | |
314 | CipherUpdate (context, partOut, partIn, tempLen); | |
315 | partIn += tempLen; | |
316 | partInLen -= tempLen; | |
317 | *partOutLen += tempLen; | |
318 | ||
319 | /* Length is now less than 8, so copy remainder to buffer. | |
320 | */ | |
321 | R_memcpy | |
322 | ((POINTER)context->buffer, (POINTER)partIn, | |
323 | context->bufferLen = partInLen); | |
324 | ||
325 | return (0); | |
326 | } | |
327 | ||
328 | /* Assume partOut buffer is at least 8 bytes. | |
329 | */ | |
330 | int R_SealFinal (context, partOut, partOutLen) | |
331 | R_ENVELOPE_CTX *context; /* context */ | |
332 | unsigned char *partOut; /* last encrypted data part */ | |
333 | unsigned int *partOutLen; /* length of last encrypted data part */ | |
334 | { | |
335 | unsigned int padLen; | |
336 | ||
337 | /* Pad and encrypt final block. | |
338 | */ | |
339 | padLen = 8 - context->bufferLen; | |
340 | R_memset | |
341 | ((POINTER)(context->buffer + context->bufferLen), (int)padLen, padLen); | |
342 | CipherUpdate (context, partOut, context->buffer, 8); | |
343 | *partOutLen = 8; | |
344 | ||
345 | /* Restart the context. | |
346 | */ | |
347 | CipherRestart (context); | |
348 | context->bufferLen = 0; | |
349 | ||
350 | return (0); | |
351 | } | |
352 | ||
353 | /* Assume caller has already ASCII decoded the encryptedKey if necessary. | |
354 | */ | |
355 | int R_OpenInit | |
356 | (context, encryptionAlgorithm, encryptedKey, encryptedKeyLen, iv, privateKey) | |
357 | R_ENVELOPE_CTX *context; /* new context */ | |
358 | int encryptionAlgorithm; /* data encryption algorithm */ | |
359 | unsigned char *encryptedKey; /* encrypted data encryption key */ | |
360 | unsigned int encryptedKeyLen; /* length of encrypted key */ | |
361 | unsigned char iv[8]; /* initialization vector */ | |
362 | R_RSA_PRIVATE_KEY *privateKey; /* recipient's RSA private key */ | |
363 | { | |
364 | int status; | |
365 | unsigned char key[MAX_ENCRYPTED_KEY_LEN]; | |
366 | unsigned int keyLen; | |
367 | ||
368 | if (encryptedKeyLen > MAX_ENCRYPTED_KEY_LEN) | |
369 | return (RE_LEN); | |
370 | ||
371 | do { | |
372 | context->encryptionAlgorithm = encryptionAlgorithm; | |
373 | ||
374 | if (RSAPrivateDecrypt | |
375 | (key, &keyLen, encryptedKey, encryptedKeyLen, privateKey)) { | |
376 | status = RE_PRIVATE_KEY; | |
377 | break; | |
378 | } | |
379 | ||
380 | if (encryptionAlgorithm == EA_DES_CBC) { | |
381 | if (keyLen != 8) { | |
382 | status = RE_PRIVATE_KEY; | |
383 | break; | |
384 | } | |
385 | } | |
386 | else { | |
387 | if (keyLen != 24) { | |
388 | status = RE_PRIVATE_KEY; | |
389 | break; | |
390 | } | |
391 | } | |
392 | ||
393 | if ((status = CipherInit (context, encryptionAlgorithm, key, iv, 0)) != 0) | |
394 | break; | |
395 | ||
396 | context->bufferLen = 0; | |
397 | } while (0); | |
398 | ||
399 | /* Zeroize sensitive information. | |
400 | */ | |
401 | R_memset ((POINTER)key, 0, sizeof (key)); | |
402 | ||
403 | return (status); | |
404 | } | |
405 | ||
406 | /* Assume partOut buffer is at least partInLen + 7, since this may flush | |
407 | buffered input. Always leaves at least one byte in buffer. | |
408 | */ | |
409 | int R_OpenUpdate (context, partOut, partOutLen, partIn, partInLen) | |
410 | R_ENVELOPE_CTX *context; /* context */ | |
411 | unsigned char *partOut; /* next recovered data part */ | |
412 | unsigned int *partOutLen; /* length of next recovered data part */ | |
413 | unsigned char *partIn; /* next encrypted data part */ | |
414 | unsigned int partInLen; /* length of next encrypted data part */ | |
415 | { | |
416 | unsigned int tempLen; | |
417 | ||
418 | tempLen = 8 - context->bufferLen; | |
419 | if (partInLen <= tempLen) { | |
420 | /* Just accumulate into buffer. | |
421 | */ | |
422 | R_memcpy | |
423 | ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn, | |
424 | partInLen); | |
425 | context->bufferLen += partInLen; | |
426 | *partOutLen = 0; | |
427 | return (0); | |
428 | } | |
429 | ||
430 | /* Fill the buffer and decrypt. We know that there will be more left | |
431 | in partIn after decrypting the buffer. | |
432 | */ | |
433 | R_memcpy | |
434 | ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn, | |
435 | tempLen); | |
436 | CipherUpdate (context, partOut, context->buffer, 8); | |
437 | partIn += tempLen; | |
438 | partInLen -= tempLen; | |
439 | partOut += 8; | |
440 | *partOutLen = 8; | |
441 | ||
442 | /* Decrypt as many 8 byte blocks as possible, leaving at least one byte | |
443 | in partIn. | |
444 | */ | |
445 | tempLen = 8 * ((partInLen - 1) / 8); | |
446 | CipherUpdate (context, partOut, partIn, tempLen); | |
447 | partIn += tempLen; | |
448 | partInLen -= tempLen; | |
449 | *partOutLen += tempLen; | |
450 | ||
451 | /* Length is between 1 and 8, so copy into buffer. | |
452 | */ | |
453 | R_memcpy | |
454 | ((POINTER)context->buffer, (POINTER)partIn, | |
455 | context->bufferLen = partInLen); | |
456 | ||
457 | return (0); | |
458 | } | |
459 | ||
460 | /* Assume partOut buffer is at least 7 bytes. | |
461 | */ | |
462 | int R_OpenFinal (context, partOut, partOutLen) | |
463 | R_ENVELOPE_CTX *context; /* context */ | |
464 | unsigned char *partOut; /* last recovered data part */ | |
465 | unsigned int *partOutLen; /* length of last recovered data part */ | |
466 | { | |
467 | int status; | |
468 | unsigned char lastPart[8]; | |
469 | unsigned int padLen; | |
470 | ||
471 | status = 0; | |
472 | do { | |
473 | if (context->bufferLen == 0) | |
474 | /* There was no input data to decrypt */ | |
475 | *partOutLen = 0; | |
476 | else { | |
477 | if (context->bufferLen != 8) { | |
478 | status = RE_KEY; | |
479 | break; | |
480 | } | |
481 | ||
482 | /* Decrypt and strip padding from final block which is in buffer. | |
483 | */ | |
484 | CipherUpdate (context, lastPart, context->buffer, 8); | |
485 | ||
486 | padLen = lastPart[7]; | |
487 | if (padLen == 0 || padLen > 8) { | |
488 | status = RE_KEY; | |
489 | break; | |
490 | } | |
491 | if (R_memcmp | |
492 | ((POINTER)&lastPart[8 - padLen], PADDING[padLen], padLen) != 0) { | |
493 | status = RE_KEY; | |
494 | break; | |
495 | } | |
496 | ||
497 | R_memcpy ((POINTER)partOut, (POINTER)lastPart, *partOutLen = 8 - padLen); | |
498 | } | |
499 | ||
500 | /* Restart the context. | |
501 | */ | |
502 | CipherRestart (context); | |
503 | context->bufferLen = 0; | |
504 | } while (0); | |
505 | ||
506 | /* Zeroize sensitive information. | |
507 | */ | |
508 | R_memset ((POINTER)lastPart, 0, sizeof (lastPart)); | |
509 | ||
510 | return (status); | |
511 | } | |
512 | ||
513 | int R_SignPEMBlock | |
514 | (encodedContent, encodedContentLen, encodedSignature, encodedSignatureLen, | |
515 | content, contentLen, recode, digestAlgorithm, privateKey) | |
516 | unsigned char *encodedContent; /* encoded content */ | |
517 | unsigned int *encodedContentLen; /* length of encoded content */ | |
518 | unsigned char *encodedSignature; /* encoded signature */ | |
519 | unsigned int *encodedSignatureLen; /* length of encoded signature */ | |
520 | unsigned char *content; /* content */ | |
521 | unsigned int contentLen; /* length of content */ | |
522 | int recode; /* recoding flag */ | |
523 | int digestAlgorithm; /* message-digest algorithm */ | |
524 | R_RSA_PRIVATE_KEY *privateKey; /* signer's RSA private key */ | |
525 | { | |
526 | int status; | |
527 | unsigned char signature[MAX_SIGNATURE_LEN]; | |
528 | unsigned int signatureLen; | |
529 | ||
530 | if ((status = R_SignBlock | |
531 | (signature, &signatureLen, content, contentLen, digestAlgorithm, | |
532 | privateKey)) != 0) | |
533 | return (status); | |
534 | ||
535 | R_EncodePEMBlock | |
536 | (encodedSignature, encodedSignatureLen, signature, signatureLen); | |
537 | ||
538 | if (recode) | |
539 | R_EncodePEMBlock | |
540 | (encodedContent, encodedContentLen, content, contentLen); | |
541 | ||
542 | return (0); | |
543 | } | |
544 | ||
545 | int R_SignBlock | |
546 | (signature, signatureLen, block, blockLen, digestAlgorithm, privateKey) | |
547 | unsigned char *signature; /* signature */ | |
548 | unsigned int *signatureLen; /* length of signature */ | |
549 | unsigned char *block; /* block */ | |
550 | unsigned int blockLen; /* length of block */ | |
551 | int digestAlgorithm; /* message-digest algorithm */ | |
552 | R_RSA_PRIVATE_KEY *privateKey; /* signer's RSA private key */ | |
553 | { | |
554 | R_SIGNATURE_CTX context; | |
555 | int status; | |
556 | ||
557 | do { | |
558 | if ((status = R_SignInit (&context, digestAlgorithm)) != 0) | |
559 | break; | |
560 | if ((status = R_SignUpdate (&context, block, blockLen)) != 0) | |
561 | break; | |
562 | if ((status = R_SignFinal (&context, signature, signatureLen, privateKey)) | |
563 | != 0) | |
564 | break; | |
565 | } while (0); | |
566 | ||
567 | /* Zeroize sensitive information. */ | |
568 | R_memset ((POINTER)&context, 0, sizeof (context)); | |
569 | ||
570 | return (status); | |
571 | } | |
572 | ||
573 | int R_VerifyPEMSignature | |
574 | (content, contentLen, encodedContent, encodedContentLen, encodedSignature, | |
575 | encodedSignatureLen, recode, digestAlgorithm, publicKey) | |
576 | unsigned char *content; /* content */ | |
577 | unsigned int *contentLen; /* length of content */ | |
578 | unsigned char *encodedContent; /* (possibly) encoded content */ | |
579 | unsigned int encodedContentLen; /* length of encoded content */ | |
580 | unsigned char *encodedSignature; /* encoded signature */ | |
581 | unsigned int encodedSignatureLen; /* length of encoded signature */ | |
582 | int recode; /* recoding flag */ | |
583 | int digestAlgorithm; /* message-digest algorithm */ | |
584 | R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ | |
585 | { | |
586 | unsigned char signature[MAX_SIGNATURE_LEN]; | |
587 | unsigned int signatureLen; | |
588 | ||
589 | if (encodedSignatureLen > MAX_PEM_SIGNATURE_LEN) | |
590 | return (RE_SIGNATURE_ENCODING); | |
591 | ||
592 | if (recode) { | |
593 | if (R_DecodePEMBlock | |
594 | (content, contentLen, encodedContent, encodedContentLen)) | |
595 | return (RE_CONTENT_ENCODING); | |
596 | } | |
597 | else { | |
598 | content = encodedContent; | |
599 | *contentLen = encodedContentLen; | |
600 | } | |
601 | ||
602 | if (R_DecodePEMBlock | |
603 | (signature, &signatureLen, encodedSignature, encodedSignatureLen)) | |
604 | return (RE_SIGNATURE_ENCODING); | |
605 | ||
606 | return (R_VerifyBlockSignature | |
607 | (content, *contentLen, signature, signatureLen, digestAlgorithm, | |
608 | publicKey)); | |
609 | } | |
610 | ||
611 | int R_VerifyBlockSignature | |
612 | (block, blockLen, signature, signatureLen, digestAlgorithm, publicKey) | |
613 | unsigned char *block; /* block */ | |
614 | unsigned int blockLen; /* length of block */ | |
615 | unsigned char *signature; /* signature */ | |
616 | unsigned int signatureLen; /* length of signature */ | |
617 | int digestAlgorithm; /* message-digest algorithm */ | |
618 | R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ | |
619 | { | |
620 | R_SIGNATURE_CTX context; | |
621 | int status; | |
622 | ||
623 | do { | |
624 | if ((status = R_VerifyInit (&context, digestAlgorithm)) != 0) | |
625 | break; | |
626 | if ((status = R_VerifyUpdate (&context, block, blockLen)) != 0) | |
627 | break; | |
628 | if ((status = R_VerifyFinal (&context, signature, signatureLen, publicKey)) | |
629 | != 0) | |
630 | break; | |
631 | } while (0); | |
632 | ||
633 | /* Zeroize sensitive information. */ | |
634 | R_memset ((POINTER)&context, 0, sizeof (context)); | |
635 | ||
636 | return (status); | |
637 | } | |
638 | ||
639 | int R_SealPEMBlock | |
640 | (encryptedContent, encryptedContentLen, encryptedKey, encryptedKeyLen, | |
641 | encryptedSignature, encryptedSignatureLen, iv, content, contentLen, | |
642 | digestAlgorithm, publicKey, privateKey, randomStruct) | |
643 | unsigned char *encryptedContent; /* encoded, encrypted content */ | |
644 | unsigned int *encryptedContentLen; /* length */ | |
645 | unsigned char *encryptedKey; /* encoded, encrypted key */ | |
646 | unsigned int *encryptedKeyLen; /* length */ | |
647 | unsigned char *encryptedSignature; /* encoded, encrypted signature */ | |
648 | unsigned int *encryptedSignatureLen; /* length */ | |
649 | unsigned char iv[8]; /* DES initialization vector */ | |
650 | unsigned char *content; /* content */ | |
651 | unsigned int contentLen; /* length of content */ | |
652 | int digestAlgorithm; /* message-digest algorithms */ | |
653 | R_RSA_PUBLIC_KEY *publicKey; /* recipient's RSA public key */ | |
654 | R_RSA_PRIVATE_KEY *privateKey; /* signer's RSA private key */ | |
655 | R_RANDOM_STRUCT *randomStruct; /* random structure */ | |
656 | { | |
657 | R_ENVELOPE_CTX context; | |
658 | R_RSA_PUBLIC_KEY *publicKeys[1]; | |
659 | int status; | |
660 | unsigned char encryptedKeyBlock[MAX_ENCRYPTED_KEY_LEN], | |
661 | signature[MAX_SIGNATURE_LEN], *encryptedKeys[1]; | |
662 | unsigned int signatureLen, encryptedKeyBlockLen; | |
663 | ||
664 | do { | |
665 | if ((status = R_SignBlock | |
666 | (signature, &signatureLen, content, contentLen, digestAlgorithm, | |
667 | privateKey)) != 0) | |
668 | break; | |
669 | ||
670 | publicKeys[0] = publicKey; | |
671 | encryptedKeys[0] = encryptedKeyBlock; | |
672 | if ((status = R_SealInit | |
673 | (&context, encryptedKeys, &encryptedKeyBlockLen, iv, 1, publicKeys, | |
674 | EA_DES_CBC, randomStruct)) != 0) | |
675 | break; | |
676 | ||
677 | R_EncodePEMBlock | |
678 | (encryptedKey, encryptedKeyLen, encryptedKeyBlock, | |
679 | encryptedKeyBlockLen); | |
680 | ||
681 | EncryptPEMUpdateFinal | |
682 | (&context, encryptedContent, encryptedContentLen, content, | |
683 | contentLen); | |
684 | ||
685 | EncryptPEMUpdateFinal | |
686 | (&context, encryptedSignature, encryptedSignatureLen, signature, | |
687 | signatureLen); | |
688 | } while (0); | |
689 | ||
690 | /* Zeroize sensitive information. | |
691 | */ | |
692 | R_memset ((POINTER)&context, 0, sizeof (context)); | |
693 | R_memset ((POINTER)signature, 0, sizeof (signature)); | |
694 | ||
695 | return (status); | |
696 | } | |
697 | ||
698 | int R_OpenPEMBlock | |
699 | (content, contentLen, encryptedContent, encryptedContentLen, encryptedKey, | |
700 | encryptedKeyLen, encryptedSignature, encryptedSignatureLen, | |
701 | iv, digestAlgorithm, privateKey, publicKey) | |
702 | unsigned char *content; /* content */ | |
703 | unsigned int *contentLen; /* length of content */ | |
704 | unsigned char *encryptedContent; /* encoded, encrypted content */ | |
705 | unsigned int encryptedContentLen; /* length */ | |
706 | unsigned char *encryptedKey; /* encoded, encrypted key */ | |
707 | unsigned int encryptedKeyLen; /* length */ | |
708 | unsigned char *encryptedSignature; /* encoded, encrypted signature */ | |
709 | unsigned int encryptedSignatureLen; /* length */ | |
710 | unsigned char iv[8]; /* DES initialization vector */ | |
711 | int digestAlgorithm; /* message-digest algorithms */ | |
712 | R_RSA_PRIVATE_KEY *privateKey; /* recipient's RSA private key */ | |
713 | R_RSA_PUBLIC_KEY *publicKey; /* signer's RSA public key */ | |
714 | { | |
715 | R_ENVELOPE_CTX context; | |
716 | int status; | |
717 | unsigned char encryptedKeyBlock[MAX_ENCRYPTED_KEY_LEN], | |
718 | signature[MAX_SIGNATURE_LEN]; | |
719 | unsigned int encryptedKeyBlockLen, signatureLen; | |
720 | ||
721 | if (encryptedKeyLen > MAX_PEM_ENCRYPTED_KEY_LEN) | |
722 | return (RE_KEY_ENCODING); | |
723 | ||
724 | if (encryptedSignatureLen > MAX_PEM_ENCRYPTED_SIGNATURE_LEN) | |
725 | return (RE_SIGNATURE_ENCODING); | |
726 | ||
727 | do { | |
728 | if (R_DecodePEMBlock | |
729 | (encryptedKeyBlock, &encryptedKeyBlockLen, encryptedKey, | |
730 | encryptedKeyLen) != 0) { | |
731 | status = RE_KEY_ENCODING; | |
732 | break; | |
733 | } | |
734 | ||
735 | if ((status = R_OpenInit | |
736 | (&context, EA_DES_CBC, encryptedKeyBlock, encryptedKeyBlockLen, | |
737 | iv, privateKey)) != 0) | |
738 | break; | |
739 | ||
740 | if ((status = DecryptPEMUpdateFinal | |
741 | (&context, content, contentLen, encryptedContent, | |
742 | encryptedContentLen)) != 0) { | |
743 | if ((status == RE_LEN || status == RE_ENCODING)) | |
744 | status = RE_CONTENT_ENCODING; | |
745 | else | |
746 | status = RE_KEY; | |
747 | break; | |
748 | } | |
749 | ||
750 | if (status = DecryptPEMUpdateFinal | |
751 | (&context, signature, &signatureLen, encryptedSignature, | |
752 | encryptedSignatureLen)) { | |
753 | if ((status == RE_LEN || status == RE_ENCODING)) | |
754 | status = RE_SIGNATURE_ENCODING; | |
755 | else | |
756 | status = RE_KEY; | |
757 | break; | |
758 | } | |
759 | ||
760 | if ((status = R_VerifyBlockSignature | |
761 | (content, *contentLen, signature, signatureLen, digestAlgorithm, | |
762 | publicKey)) != 0) | |
763 | break; | |
764 | } while (0); | |
765 | ||
766 | /* Zeroize sensitive information. | |
767 | */ | |
768 | R_memset ((POINTER)&context, 0, sizeof (context)); | |
769 | R_memset ((POINTER)signature, 0, sizeof (signature)); | |
770 | ||
771 | return (status); | |
772 | } | |
773 | ||
774 | int R_DigestBlock (digest, digestLen, block, blockLen, digestAlgorithm) | |
775 | unsigned char *digest; /* message digest */ | |
776 | unsigned int *digestLen; /* length of message digest */ | |
777 | unsigned char *block; /* block */ | |
778 | unsigned int blockLen; /* length of block */ | |
779 | int digestAlgorithm; /* message-digest algorithm */ | |
780 | { | |
781 | R_DIGEST_CTX context; | |
782 | int status; | |
783 | ||
784 | do { | |
785 | if ((status = R_DigestInit (&context, digestAlgorithm)) != 0) | |
786 | break; | |
787 | if ((status = R_DigestUpdate (&context, block, blockLen)) != 0) | |
788 | break; | |
789 | if ((status = R_DigestFinal (&context, digest, digestLen)) != 0) | |
790 | break; | |
791 | } while (0); | |
792 | ||
793 | /* Zeroize sensitive information. */ | |
794 | R_memset ((POINTER)&context, 0, sizeof (context)); | |
795 | ||
796 | return (status); | |
797 | } | |
798 | ||
799 | /* Assumes digestAlgorithm is DA_MD2 or DA_MD5 and digest length is 16. | |
800 | */ | |
801 | static void R_EncodeDigestInfo (digestInfo, digestAlgorithm, digest) | |
802 | unsigned char *digestInfo; /* DigestInfo encoding */ | |
803 | int digestAlgorithm; /* message-digest algorithm */ | |
804 | unsigned char *digest; /* message digest */ | |
805 | { | |
806 | R_memcpy | |
807 | ((POINTER)digestInfo, (POINTER)DIGEST_INFO_A, DIGEST_INFO_A_LEN); | |
808 | ||
809 | digestInfo[DIGEST_INFO_A_LEN] = | |
810 | (digestAlgorithm == DA_MD2) ? (unsigned char)2 : (unsigned char)5; | |
811 | ||
812 | R_memcpy | |
813 | ((POINTER)&digestInfo[DIGEST_INFO_A_LEN + 1], (POINTER)DIGEST_INFO_B, | |
814 | DIGEST_INFO_B_LEN); | |
815 | ||
816 | R_memcpy | |
817 | ((POINTER)&digestInfo[DIGEST_INFO_A_LEN + 1 + DIGEST_INFO_B_LEN], | |
818 | (POINTER)digest, 16); | |
819 | } | |
820 | ||
821 | /* Call SealUpdate and SealFinal on the input and ASCII recode. | |
822 | */ | |
823 | static void EncryptPEMUpdateFinal | |
824 | (context, output, outputLen, input, inputLen) | |
825 | R_ENVELOPE_CTX *context; | |
826 | unsigned char *output; /* encrypted, encoded block */ | |
827 | unsigned int *outputLen; /* length of output */ | |
828 | unsigned char *input; /* block to encrypt */ | |
829 | unsigned int inputLen; /* length */ | |
830 | { | |
831 | unsigned char encryptedPart[24]; | |
832 | unsigned int i, lastPartLen, tempLen, len; | |
833 | ||
834 | /* Choose a buffer size of 24 bytes to hold the temporary encrypted output | |
835 | which will be encoded. | |
836 | Encrypt and encode as many 24-byte blocks as possible. | |
837 | */ | |
838 | for (i = 0; i < inputLen / 24; ++i) { | |
839 | /* Assume part out length will equal part in length since it is | |
840 | a multiple of 8. Also assume no error output. */ | |
841 | R_SealUpdate (context, encryptedPart, &tempLen, &input[24*i], 24); | |
842 | ||
843 | /* len is always 32 */ | |
844 | R_EncodePEMBlock (&output[32*i], &tempLen, encryptedPart, 24); | |
845 | } | |
846 | ||
847 | /* Encrypt the last part into encryptedPart. | |
848 | */ | |
849 | R_SealUpdate | |
850 | (context, encryptedPart, &lastPartLen, &input[24*i], inputLen - 24*i); | |
851 | R_SealFinal (context, encryptedPart + lastPartLen, &len); | |
852 | lastPartLen += len; | |
853 | ||
854 | R_EncodePEMBlock (&output[32*i], &len, encryptedPart, lastPartLen); | |
855 | *outputLen = 32*i + len; | |
856 | ||
857 | /* Zeroize sensitive information. | |
858 | */ | |
859 | R_memset ((POINTER)encryptedPart, 0, sizeof (encryptedPart)); | |
860 | } | |
861 | ||
862 | static int DecryptPEMUpdateFinal (context, output, outputLen, input, inputLen) | |
863 | R_ENVELOPE_CTX *context; | |
864 | unsigned char *output; /* decoded, decrypted block */ | |
865 | unsigned int *outputLen; /* length of output */ | |
866 | unsigned char *input; /* encrypted, encoded block */ | |
867 | unsigned int inputLen; /* length */ | |
868 | { | |
869 | int status; | |
870 | unsigned char encryptedPart[24]; | |
871 | unsigned int i, len; | |
872 | ||
873 | do { | |
874 | /* Choose a buffer size of 24 bytes to hold the temporary decoded output | |
875 | which will be decrypted. | |
876 | Decode and decrypt as many 32-byte input blocks as possible. | |
877 | */ | |
878 | *outputLen = 0; | |
879 | for (i = 0; i < inputLen/32; i++) { | |
880 | /* len is always 24 */ | |
881 | if ((status = R_DecodePEMBlock | |
882 | (encryptedPart, &len, &input[32*i], 32)) != 0) | |
883 | break; | |
884 | ||
885 | /* Excpect no error return */ | |
886 | R_OpenUpdate (context, output, &len, encryptedPart, 24); | |
887 | output += len; | |
888 | *outputLen += len; | |
889 | } | |
890 | if (status) | |
891 | break; | |
892 | ||
893 | /* Decode the last part */ | |
894 | if ((status = R_DecodePEMBlock | |
895 | (encryptedPart, &len, &input[32*i], inputLen - 32*i)) != 0) | |
896 | break; | |
897 | ||
898 | /* Decrypt the last part. | |
899 | */ | |
900 | R_OpenUpdate (context, output, &len, encryptedPart, len); | |
901 | output += len; | |
902 | *outputLen += len; | |
903 | if ((status = R_OpenFinal (context, output, &len)) != 0) | |
904 | break; | |
905 | *outputLen += len; | |
906 | } while (0); | |
907 | ||
908 | /* Zeroize sensitive information. | |
909 | */ | |
910 | R_memset ((POINTER)&context, 0, sizeof (context)); | |
911 | R_memset ((POINTER)encryptedPart, 0, sizeof (encryptedPart)); | |
912 | ||
913 | return (status); | |
914 | } | |
915 | ||
916 | static int CipherInit (context, encryptionAlgorithm, key, iv, encrypt) | |
917 | R_ENVELOPE_CTX *context; | |
918 | int encryptionAlgorithm; | |
919 | unsigned char *key; /* DES key */ | |
920 | unsigned char *iv; /* DES initialization vector */ | |
921 | int encrypt; /* encrypt flag (1 = encrypt, 0 = decrypt) */ | |
922 | { | |
923 | switch (encryptionAlgorithm) { | |
924 | case EA_DES_CBC: | |
925 | DES_CBCInit (&context->cipherContext.des, key, iv, encrypt); | |
926 | return (0); | |
927 | case EA_DESX_CBC: | |
928 | DESX_CBCInit (&context->cipherContext.desx, key, iv, encrypt); | |
929 | return (0); | |
930 | case EA_DES_EDE2_CBC: | |
931 | case EA_DES_EDE3_CBC: | |
932 | DES3_CBCInit (&context->cipherContext.des3, key, iv, encrypt); | |
933 | return (0); | |
934 | ||
935 | default: | |
936 | return (RE_ENCRYPTION_ALGORITHM); | |
937 | } | |
938 | } | |
939 | ||
940 | /* Assume len is a multiple of 8. | |
941 | */ | |
942 | static void CipherUpdate (context, output, input, len) | |
943 | R_ENVELOPE_CTX *context; | |
944 | unsigned char *output; /* output block */ | |
945 | unsigned char *input; /* input block */ | |
946 | unsigned int len; /* length of input and output blocks */ | |
947 | { | |
948 | if (context->encryptionAlgorithm == EA_DES_CBC) | |
949 | DES_CBCUpdate (&context->cipherContext.des, output, input, len); | |
950 | else if (context->encryptionAlgorithm == EA_DESX_CBC) | |
951 | DESX_CBCUpdate (&context->cipherContext.desx, output, input, len); | |
952 | else | |
953 | DES3_CBCUpdate (&context->cipherContext.des3, output, input, len); | |
954 | } | |
955 | ||
956 | static void CipherRestart (context) | |
957 | R_ENVELOPE_CTX *context; | |
958 | { | |
959 | if (context->encryptionAlgorithm == EA_DES_CBC) | |
960 | DES_CBCRestart (&context->cipherContext.des); | |
961 | else if (context->encryptionAlgorithm == EA_DESX_CBC) | |
962 | DESX_CBCRestart (&context->cipherContext.desx); | |
963 | else | |
964 | DES3_CBCRestart (&context->cipherContext.des3); | |
965 | } |