Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: nss/lib/freebl/rsapkcs.c

Issue 105893015: Update third_party/nss to NSS 3.15.4. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Remove SVN property on new file nss/lib/freebl/rsapkcs.c Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « nss/lib/freebl/rijndael.c ('k') | nss/lib/freebl/unix_rand.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /*
6 * RSA PKCS#1 v2.1 (RFC 3447) operations
7 */
8
9 #ifdef FREEBL_NO_DEPEND
10 #include "stubs.h"
11 #endif
12
13 #include "secerr.h"
14
15 #include "blapi.h"
16 #include "secitem.h"
17 #include "blapii.h"
18
19 #define RSA_BLOCK_MIN_PAD_LEN 8
20 #define RSA_BLOCK_FIRST_OCTET 0x00
21 #define RSA_BLOCK_PRIVATE_PAD_OCTET 0xff
22 #define RSA_BLOCK_AFTER_PAD_OCTET 0x00
23
24 /*
25 * RSA block types
26 *
27 * The actual values are important -- they are fixed, *not* arbitrary.
28 * The explicit value assignments are not needed (because C would give
29 * us those same values anyway) but are included as a reminder...
30 */
31 typedef enum {
32 RSA_BlockUnused = 0, /* unused */
33 RSA_BlockPrivate = 1, /* pad for a private-key operation */
34 RSA_BlockPublic = 2, /* pad for a public-key operation */
35 RSA_BlockRaw = 4, /* simply justify the block appropriately */
36 RSA_BlockTotal
37 } RSA_BlockType;
38
39 /* Needed for RSA-PSS functions */
40 static const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
41
42 /* Constant time comparison of a single byte.
43 * Returns 1 iff a == b, otherwise returns 0.
44 * Note: For ranges of bytes, use constantTimeCompare.
45 */
46 static unsigned char constantTimeEQ8(unsigned char a, unsigned char b) {
47 unsigned char c = ~((a - b) | (b - a));
48 c >>= 7;
49 return c;
50 }
51
52 /* Constant time comparison of a range of bytes.
53 * Returns 1 iff len bytes of a are identical to len bytes of b, otherwise
54 * returns 0.
55 */
56 static unsigned char constantTimeCompare(const unsigned char *a,
57 const unsigned char *b,
58 unsigned int len) {
59 unsigned char tmp = 0;
60 unsigned int i;
61 for (i = 0; i < len; ++i, ++a, ++b)
62 tmp |= *a ^ *b;
63 return constantTimeEQ8(0x00, tmp);
64 }
65
66 /* Constant time conditional.
67 * Returns a if c is 1, or b if c is 0. The result is undefined if c is
68 * not 0 or 1.
69 */
70 static unsigned int constantTimeCondition(unsigned int c,
71 unsigned int a,
72 unsigned int b)
73 {
74 return (~(c - 1) & a) | ((c - 1) & b);
75 }
76
77 static unsigned int
78 rsa_modulusLen(SECItem * modulus)
79 {
80 unsigned char byteZero = modulus->data[0];
81 unsigned int modLen = modulus->len - !byteZero;
82 return modLen;
83 }
84
85 /*
86 * Format one block of data for public/private key encryption using
87 * the rules defined in PKCS #1.
88 */
89 static unsigned char *
90 rsa_FormatOneBlock(unsigned modulusLen,
91 RSA_BlockType blockType,
92 SECItem * data)
93 {
94 unsigned char *block;
95 unsigned char *bp;
96 int padLen;
97 int i, j;
98 SECStatus rv;
99
100 block = (unsigned char *) PORT_Alloc(modulusLen);
101 if (block == NULL)
102 return NULL;
103
104 bp = block;
105
106 /*
107 * All RSA blocks start with two octets:
108 * 0x00 || BlockType
109 */
110 *bp++ = RSA_BLOCK_FIRST_OCTET;
111 *bp++ = (unsigned char) blockType;
112
113 switch (blockType) {
114
115 /*
116 * Blocks intended for private-key operation.
117 */
118 case RSA_BlockPrivate: /* preferred method */
119 /*
120 * 0x00 || BT || Pad || 0x00 || ActualData
121 * 1 1 padLen 1 data->len
122 * Pad is either all 0x00 or all 0xff bytes, depending on blockType.
123 */
124 padLen = modulusLen - data->len - 3;
125 PORT_Assert(padLen >= RSA_BLOCK_MIN_PAD_LEN);
126 if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
127 PORT_Free(block);
128 return NULL;
129 }
130 PORT_Memset(bp, RSA_BLOCK_PRIVATE_PAD_OCTET, padLen);
131 bp += padLen;
132 *bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
133 PORT_Memcpy(bp, data->data, data->len);
134 break;
135
136 /*
137 * Blocks intended for public-key operation.
138 */
139 case RSA_BlockPublic:
140 /*
141 * 0x00 || BT || Pad || 0x00 || ActualData
142 * 1 1 padLen 1 data->len
143 * Pad is all non-zero random bytes.
144 *
145 * Build the block left to right.
146 * Fill the entire block from Pad to the end with random bytes.
147 * Use the bytes after Pad as a supply of extra random bytes from
148 * which to find replacements for the zero bytes in Pad.
149 * If we need more than that, refill the bytes after Pad with
150 * new random bytes as necessary.
151 */
152 padLen = modulusLen - (data->len + 3);
153 PORT_Assert(padLen >= RSA_BLOCK_MIN_PAD_LEN);
154 if (padLen < RSA_BLOCK_MIN_PAD_LEN) {
155 PORT_Free(block);
156 return NULL;
157 }
158 j = modulusLen - 2;
159 rv = RNG_GenerateGlobalRandomBytes(bp, j);
160 if (rv == SECSuccess) {
161 for (i = 0; i < padLen; ) {
162 unsigned char repl;
163 /* Pad with non-zero random data. */
164 if (bp[i] != RSA_BLOCK_AFTER_PAD_OCTET) {
165 ++i;
166 continue;
167 }
168 if (j <= padLen) {
169 rv = RNG_GenerateGlobalRandomBytes(bp + padLen,
170 modulusLen - (2 + padLen));
171 if (rv != SECSuccess)
172 break;
173 j = modulusLen - 2;
174 }
175 do {
176 repl = bp[--j];
177 } while (repl == RSA_BLOCK_AFTER_PAD_OCTET && j > padLen);
178 if (repl != RSA_BLOCK_AFTER_PAD_OCTET) {
179 bp[i++] = repl;
180 }
181 }
182 }
183 if (rv != SECSuccess) {
184 PORT_Free(block);
185 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
186 return NULL;
187 }
188 bp += padLen;
189 *bp++ = RSA_BLOCK_AFTER_PAD_OCTET;
190 PORT_Memcpy(bp, data->data, data->len);
191 break;
192
193 default:
194 PORT_Assert(0);
195 PORT_Free(block);
196 return NULL;
197 }
198
199 return block;
200 }
201
202 static SECStatus
203 rsa_FormatBlock(SECItem * result,
204 unsigned modulusLen,
205 RSA_BlockType blockType,
206 SECItem * data)
207 {
208 switch (blockType) {
209 case RSA_BlockPrivate:
210 case RSA_BlockPublic:
211 /*
212 * 0x00 || BT || Pad || 0x00 || ActualData
213 *
214 * The "3" below is the first octet + the second octet + the 0x00
215 * octet that always comes just before the ActualData.
216 */
217 PORT_Assert(data->len <= (modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN)));
218
219 result->data = rsa_FormatOneBlock(modulusLen, blockType, data);
220 if (result->data == NULL) {
221 result->len = 0;
222 return SECFailure;
223 }
224 result->len = modulusLen;
225
226 break;
227
228 case RSA_BlockRaw:
229 /*
230 * Pad || ActualData
231 * Pad is zeros. The application is responsible for recovering
232 * the actual data.
233 */
234 if (data->len > modulusLen ) {
235 return SECFailure;
236 }
237 result->data = (unsigned char*)PORT_ZAlloc(modulusLen);
238 result->len = modulusLen;
239 PORT_Memcpy(result->data + (modulusLen - data->len),
240 data->data, data->len);
241 break;
242
243 default:
244 PORT_Assert(0);
245 result->data = NULL;
246 result->len = 0;
247 return SECFailure;
248 }
249
250 return SECSuccess;
251 }
252
253 /*
254 * Mask generation function MGF1 as defined in PKCS #1 v2.1 / RFC 3447.
255 */
256 static SECStatus
257 MGF1(HASH_HashType hashAlg,
258 unsigned char * mask,
259 unsigned int maskLen,
260 const unsigned char * mgfSeed,
261 unsigned int mgfSeedLen)
262 {
263 unsigned int digestLen;
264 PRUint32 counter;
265 PRUint32 rounds;
266 unsigned char * tempHash;
267 unsigned char * temp;
268 const SECHashObject * hash;
269 void * hashContext;
270 unsigned char C[4];
271
272 hash = HASH_GetRawHashObject(hashAlg);
273 if (hash == NULL)
274 return SECFailure;
275
276 hashContext = (*hash->create)();
277 rounds = (maskLen + hash->length - 1) / hash->length;
278 for (counter = 0; counter < rounds; counter++) {
279 C[0] = (unsigned char)((counter >> 24) & 0xff);
280 C[1] = (unsigned char)((counter >> 16) & 0xff);
281 C[2] = (unsigned char)((counter >> 8) & 0xff);
282 C[3] = (unsigned char)(counter & 0xff);
283
284 /* This could be optimized when the clone functions in
285 * rawhash.c are implemented. */
286 (*hash->begin)(hashContext);
287 (*hash->update)(hashContext, mgfSeed, mgfSeedLen);
288 (*hash->update)(hashContext, C, sizeof C);
289
290 tempHash = mask + counter * hash->length;
291 if (counter != (rounds - 1)) {
292 (*hash->end)(hashContext, tempHash, &digestLen, hash->length);
293 } else { /* we're in the last round and need to cut the hash */
294 temp = (unsigned char *)PORT_Alloc(hash->length);
295 (*hash->end)(hashContext, temp, &digestLen, hash->length);
296 PORT_Memcpy(tempHash, temp, maskLen - counter * hash->length);
297 PORT_Free(temp);
298 }
299 }
300 (*hash->destroy)(hashContext, PR_TRUE);
301
302 return SECSuccess;
303 }
304
305 /* XXX Doesn't set error code */
306 SECStatus
307 RSA_SignRaw(RSAPrivateKey * key,
308 unsigned char * output,
309 unsigned int * outputLen,
310 unsigned int maxOutputLen,
311 const unsigned char * data,
312 unsigned int dataLen)
313 {
314 SECStatus rv = SECSuccess;
315 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
316 SECItem formatted;
317 SECItem unformatted;
318
319 if (maxOutputLen < modulusLen)
320 return SECFailure;
321
322 unformatted.len = dataLen;
323 unformatted.data = (unsigned char*)data;
324 formatted.data = NULL;
325 rv = rsa_FormatBlock(&formatted, modulusLen, RSA_BlockRaw, &unformatted);
326 if (rv != SECSuccess)
327 goto done;
328
329 rv = RSA_PrivateKeyOpDoubleChecked(key, output, formatted.data);
330 *outputLen = modulusLen;
331
332 done:
333 if (formatted.data != NULL)
334 PORT_ZFree(formatted.data, modulusLen);
335 return rv;
336 }
337
338 /* XXX Doesn't set error code */
339 SECStatus
340 RSA_CheckSignRaw(RSAPublicKey * key,
341 const unsigned char * sig,
342 unsigned int sigLen,
343 const unsigned char * hash,
344 unsigned int hashLen)
345 {
346 SECStatus rv;
347 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
348 unsigned char * buffer;
349
350 if (sigLen != modulusLen)
351 goto failure;
352 if (hashLen > modulusLen)
353 goto failure;
354
355 buffer = (unsigned char *)PORT_Alloc(modulusLen + 1);
356 if (!buffer)
357 goto failure;
358
359 rv = RSA_PublicKeyOp(key, buffer, sig);
360 if (rv != SECSuccess)
361 goto loser;
362
363 /*
364 * make sure we get the same results
365 */
366 /* XXX(rsleevi): Constant time */
367 /* NOTE: should we verify the leading zeros? */
368 if (PORT_Memcmp(buffer + (modulusLen - hashLen), hash, hashLen) != 0)
369 goto loser;
370
371 PORT_Free(buffer);
372 return SECSuccess;
373
374 loser:
375 PORT_Free(buffer);
376 failure:
377 return SECFailure;
378 }
379
380 /* XXX Doesn't set error code */
381 SECStatus
382 RSA_CheckSignRecoverRaw(RSAPublicKey * key,
383 unsigned char * data,
384 unsigned int * dataLen,
385 unsigned int maxDataLen,
386 const unsigned char * sig,
387 unsigned int sigLen)
388 {
389 SECStatus rv;
390 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
391
392 if (sigLen != modulusLen)
393 goto failure;
394 if (maxDataLen < modulusLen)
395 goto failure;
396
397 rv = RSA_PublicKeyOp(key, data, sig);
398 if (rv != SECSuccess)
399 goto failure;
400
401 *dataLen = modulusLen;
402 return SECSuccess;
403
404 failure:
405 return SECFailure;
406 }
407
408 /* XXX Doesn't set error code */
409 SECStatus
410 RSA_EncryptRaw(RSAPublicKey * key,
411 unsigned char * output,
412 unsigned int * outputLen,
413 unsigned int maxOutputLen,
414 const unsigned char * input,
415 unsigned int inputLen)
416 {
417 SECStatus rv;
418 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
419 SECItem formatted;
420 SECItem unformatted;
421
422 formatted.data = NULL;
423 if (maxOutputLen < modulusLen)
424 goto failure;
425
426 unformatted.len = inputLen;
427 unformatted.data = (unsigned char*)input;
428 formatted.data = NULL;
429 rv = rsa_FormatBlock(&formatted, modulusLen, RSA_BlockRaw, &unformatted);
430 if (rv != SECSuccess)
431 goto failure;
432
433 rv = RSA_PublicKeyOp(key, output, formatted.data);
434 if (rv != SECSuccess)
435 goto failure;
436
437 PORT_ZFree(formatted.data, modulusLen);
438 *outputLen = modulusLen;
439 return SECSuccess;
440
441 failure:
442 if (formatted.data != NULL)
443 PORT_ZFree(formatted.data, modulusLen);
444 return SECFailure;
445 }
446
447 /* XXX Doesn't set error code */
448 SECStatus
449 RSA_DecryptRaw(RSAPrivateKey * key,
450 unsigned char * output,
451 unsigned int * outputLen,
452 unsigned int maxOutputLen,
453 const unsigned char * input,
454 unsigned int inputLen)
455 {
456 SECStatus rv;
457 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
458
459 if (modulusLen > maxOutputLen)
460 goto failure;
461 if (inputLen != modulusLen)
462 goto failure;
463
464 rv = RSA_PrivateKeyOp(key, output, input);
465 if (rv != SECSuccess)
466 goto failure;
467
468 *outputLen = modulusLen;
469 return SECSuccess;
470
471 failure:
472 return SECFailure;
473 }
474
475 /*
476 * Decodes an EME-OAEP encoded block, validating the encoding in constant
477 * time.
478 * Described in RFC 3447, section 7.1.2.
479 * input contains the encoded block, after decryption.
480 * label is the optional value L that was associated with the message.
481 * On success, the original message and message length will be stored in
482 * output and outputLen.
483 */
484 static SECStatus
485 eme_oaep_decode(unsigned char * output,
486 unsigned int * outputLen,
487 unsigned int maxOutputLen,
488 const unsigned char * input,
489 unsigned int inputLen,
490 HASH_HashType hashAlg,
491 HASH_HashType maskHashAlg,
492 const unsigned char * label,
493 unsigned int labelLen)
494 {
495 const SECHashObject * hash;
496 void * hashContext;
497 SECStatus rv = SECFailure;
498 unsigned char labelHash[HASH_LENGTH_MAX];
499 unsigned int i;
500 unsigned int maskLen;
501 unsigned int paddingOffset;
502 unsigned char * mask = NULL;
503 unsigned char * tmpOutput = NULL;
504 unsigned char isGood;
505 unsigned char foundPaddingEnd;
506
507 hash = HASH_GetRawHashObject(hashAlg);
508
509 /* 1.c */
510 if (inputLen < (hash->length * 2) + 2) {
511 PORT_SetError(SEC_ERROR_INPUT_LEN);
512 return SECFailure;
513 }
514
515 /* Step 3.a - Generate lHash */
516 hashContext = (*hash->create)();
517 if (hashContext == NULL) {
518 PORT_SetError(SEC_ERROR_NO_MEMORY);
519 return SECFailure;
520 }
521 (*hash->begin)(hashContext);
522 if (labelLen > 0)
523 (*hash->update)(hashContext, label, labelLen);
524 (*hash->end)(hashContext, labelHash, &i, sizeof(labelHash));
525 (*hash->destroy)(hashContext, PR_TRUE);
526
527 tmpOutput = (unsigned char*)PORT_Alloc(inputLen);
528 if (tmpOutput == NULL) {
529 PORT_SetError(SEC_ERROR_NO_MEMORY);
530 goto done;
531 }
532
533 maskLen = inputLen - hash->length - 1;
534 mask = (unsigned char*)PORT_Alloc(maskLen);
535 if (mask == NULL) {
536 PORT_SetError(SEC_ERROR_NO_MEMORY);
537 goto done;
538 }
539
540 PORT_Memcpy(tmpOutput, input, inputLen);
541
542 /* 3.c - Generate seedMask */
543 MGF1(maskHashAlg, mask, hash->length, &tmpOutput[1 + hash->length],
544 inputLen - hash->length - 1);
545 /* 3.d - Unmask seed */
546 for (i = 0; i < hash->length; ++i)
547 tmpOutput[1 + i] ^= mask[i];
548
549 /* 3.e - Generate dbMask */
550 MGF1(maskHashAlg, mask, maskLen, &tmpOutput[1], hash->length);
551 /* 3.f - Unmask DB */
552 for (i = 0; i < maskLen; ++i)
553 tmpOutput[1 + hash->length + i] ^= mask[i];
554
555 /* 3.g - Compare Y, lHash, and PS in constant time
556 * Warning: This code is timing dependent and must not disclose which of
557 * these were invalid.
558 */
559 paddingOffset = 0;
560 isGood = 1;
561 foundPaddingEnd = 0;
562
563 /* Compare Y */
564 isGood &= constantTimeEQ8(0x00, tmpOutput[0]);
565
566 /* Compare lHash and lHash' */
567 isGood &= constantTimeCompare(&labelHash[0],
568 &tmpOutput[1 + hash->length],
569 hash->length);
570
571 /* Compare that the padding is zero or more zero octets, followed by a
572 * 0x01 octet */
573 for (i = 1 + (hash->length * 2); i < inputLen; ++i) {
574 unsigned char isZero = constantTimeEQ8(0x00, tmpOutput[i]);
575 unsigned char isOne = constantTimeEQ8(0x01, tmpOutput[i]);
576 /* non-constant time equivalent:
577 * if (tmpOutput[i] == 0x01 && !foundPaddingEnd)
578 * paddingOffset = i;
579 */
580 paddingOffset = constantTimeCondition(isOne & ~foundPaddingEnd, i,
581 paddingOffset);
582 /* non-constant time equivalent:
583 * if (tmpOutput[i] == 0x01)
584 * foundPaddingEnd = true;
585 *
586 * Note: This may yield false positives, as it will be set whenever
587 * a 0x01 byte is encountered. If there was bad padding (eg:
588 * 0x03 0x02 0x01), foundPaddingEnd will still be set to true, and
589 * paddingOffset will still be set to 2.
590 */
591 foundPaddingEnd = constantTimeCondition(isOne, 1, foundPaddingEnd);
592 /* non-constant time equivalent:
593 * if (tmpOutput[i] != 0x00 && tmpOutput[i] != 0x01 &&
594 * !foundPaddingEnd) {
595 * isGood = false;
596 * }
597 *
598 * Note: This may yield false positives, as a message (and padding)
599 * that is entirely zeros will result in isGood still being true. Thus
600 * it's necessary to check foundPaddingEnd is positive below.
601 */
602 isGood = constantTimeCondition(~foundPaddingEnd & ~isZero, 0, isGood);
603 }
604
605 /* While both isGood and foundPaddingEnd may have false positives, they
606 * cannot BOTH have false positives. If both are not true, then an invalid
607 * message was received. Note, this comparison must still be done in constan t
608 * time so as not to leak either condition.
609 */
610 if (!(isGood & foundPaddingEnd)) {
611 PORT_SetError(SEC_ERROR_BAD_DATA);
612 goto done;
613 }
614
615 /* End timing dependent code */
616
617 ++paddingOffset; /* Skip the 0x01 following the end of PS */
618
619 *outputLen = inputLen - paddingOffset;
620 if (*outputLen > maxOutputLen) {
621 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
622 goto done;
623 }
624
625 if (*outputLen)
626 PORT_Memcpy(output, &tmpOutput[paddingOffset], *outputLen);
627 rv = SECSuccess;
628
629 done:
630 if (mask)
631 PORT_ZFree(mask, maskLen);
632 if (tmpOutput)
633 PORT_ZFree(tmpOutput, inputLen);
634 return rv;
635 }
636
637 /*
638 * Generate an EME-OAEP encoded block for encryption
639 * Described in RFC 3447, section 7.1.1
640 * We use input instead of M for the message to be encrypted
641 * label is the optional value L to be associated with the message.
642 */
643 static SECStatus
644 eme_oaep_encode(unsigned char * em,
645 unsigned int emLen,
646 const unsigned char * input,
647 unsigned int inputLen,
648 HASH_HashType hashAlg,
649 HASH_HashType maskHashAlg,
650 const unsigned char * label,
651 unsigned int labelLen,
652 const unsigned char * seed,
653 unsigned int seedLen)
654 {
655 const SECHashObject * hash;
656 void * hashContext;
657 SECStatus rv;
658 unsigned char * mask;
659 unsigned int reservedLen;
660 unsigned int dbMaskLen;
661 unsigned int i;
662
663 hash = HASH_GetRawHashObject(hashAlg);
664 PORT_Assert(seed == NULL || seedLen == hash->length);
665
666 /* Step 1.b */
667 reservedLen = (2 * hash->length) + 2;
668 if (emLen < reservedLen || inputLen > (emLen - reservedLen)) {
669 PORT_SetError(SEC_ERROR_INPUT_LEN);
670 return SECFailure;
671 }
672
673 /*
674 * From RFC 3447, Section 7.1
675 * +----------+---------+-------+
676 * DB = | lHash | PS | M |
677 * +----------+---------+-------+
678 * |
679 * +----------+ V
680 * | seed |--> MGF ---> xor
681 * +----------+ |
682 * | |
683 * +--+ V |
684 * |00| xor <----- MGF <-----|
685 * +--+ | |
686 * | | |
687 * V V V
688 * +--+----------+----------------------------+
689 * EM = |00|maskedSeed| maskedDB |
690 * +--+----------+----------------------------+
691 *
692 * We use mask to hold the result of the MGF functions, and all other
693 * values are generated in their final resting place.
694 */
695 *em = 0x00;
696
697 /* Step 2.a - Generate lHash */
698 hashContext = (*hash->create)();
699 if (hashContext == NULL) {
700 PORT_SetError(SEC_ERROR_NO_MEMORY);
701 return SECFailure;
702 }
703 (*hash->begin)(hashContext);
704 if (labelLen > 0)
705 (*hash->update)(hashContext, label, labelLen);
706 (*hash->end)(hashContext, &em[1 + hash->length], &i, hash->length);
707 (*hash->destroy)(hashContext, PR_TRUE);
708
709 /* Step 2.b - Generate PS */
710 if (emLen - reservedLen - inputLen > 0) {
711 PORT_Memset(em + 1 + (hash->length * 2), 0x00,
712 emLen - reservedLen - inputLen);
713 }
714
715 /* Step 2.c. - Generate DB
716 * DB = lHash || PS || 0x01 || M
717 * Note that PS and lHash have already been placed into em at their
718 * appropriate offsets. This just copies M into place
719 */
720 em[emLen - inputLen - 1] = 0x01;
721 if (inputLen)
722 PORT_Memcpy(em + emLen - inputLen, input, inputLen);
723
724 if (seed == NULL) {
725 /* Step 2.d - Generate seed */
726 rv = RNG_GenerateGlobalRandomBytes(em + 1, hash->length);
727 if (rv != SECSuccess) {
728 return rv;
729 }
730 } else {
731 /* For Known Answer Tests, copy the supplied seed. */
732 PORT_Memcpy(em + 1, seed, seedLen);
733 }
734
735 /* Step 2.e - Generate dbMask*/
736 dbMaskLen = emLen - hash->length - 1;
737 mask = (unsigned char*)PORT_Alloc(dbMaskLen);
738 if (mask == NULL) {
739 PORT_SetError(SEC_ERROR_NO_MEMORY);
740 return SECFailure;
741 }
742 MGF1(maskHashAlg, mask, dbMaskLen, em + 1, hash->length);
743 /* Step 2.f - Compute maskedDB*/
744 for (i = 0; i < dbMaskLen; ++i)
745 em[1 + hash->length + i] ^= mask[i];
746
747 /* Step 2.g - Generate seedMask */
748 MGF1(maskHashAlg, mask, hash->length, &em[1 + hash->length], dbMaskLen);
749 /* Step 2.h - Compute maskedSeed */
750 for (i = 0; i < hash->length; ++i)
751 em[1 + i] ^= mask[i];
752
753 PORT_ZFree(mask, dbMaskLen);
754 return SECSuccess;
755 }
756
757 SECStatus
758 RSA_EncryptOAEP(RSAPublicKey * key,
759 HASH_HashType hashAlg,
760 HASH_HashType maskHashAlg,
761 const unsigned char * label,
762 unsigned int labelLen,
763 const unsigned char * seed,
764 unsigned int seedLen,
765 unsigned char * output,
766 unsigned int * outputLen,
767 unsigned int maxOutputLen,
768 const unsigned char * input,
769 unsigned int inputLen)
770 {
771 SECStatus rv = SECFailure;
772 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
773 unsigned char * oaepEncoded = NULL;
774
775 if (maxOutputLen < modulusLen) {
776 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
777 return SECFailure;
778 }
779
780 if ((hashAlg == HASH_AlgNULL) || (maskHashAlg == HASH_AlgNULL)) {
781 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
782 return SECFailure;
783 }
784
785 if ((labelLen == 0 && label != NULL) ||
786 (labelLen > 0 && label == NULL)) {
787 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
788 return SECFailure;
789 }
790
791 oaepEncoded = (unsigned char *)PORT_Alloc(modulusLen);
792 if (oaepEncoded == NULL) {
793 PORT_SetError(SEC_ERROR_NO_MEMORY);
794 return SECFailure;
795 }
796 rv = eme_oaep_encode(oaepEncoded, modulusLen, input, inputLen,
797 hashAlg, maskHashAlg, label, labelLen, seed, seedLen);
798 if (rv != SECSuccess)
799 goto done;
800
801 rv = RSA_PublicKeyOp(key, output, oaepEncoded);
802 if (rv != SECSuccess)
803 goto done;
804 *outputLen = modulusLen;
805
806 done:
807 PORT_Free(oaepEncoded);
808 return rv;
809 }
810
811 SECStatus
812 RSA_DecryptOAEP(RSAPrivateKey * key,
813 HASH_HashType hashAlg,
814 HASH_HashType maskHashAlg,
815 const unsigned char * label,
816 unsigned int labelLen,
817 unsigned char * output,
818 unsigned int * outputLen,
819 unsigned int maxOutputLen,
820 const unsigned char * input,
821 unsigned int inputLen)
822 {
823 SECStatus rv = SECFailure;
824 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
825 unsigned char * oaepEncoded = NULL;
826
827 if ((hashAlg == HASH_AlgNULL) || (maskHashAlg == HASH_AlgNULL)) {
828 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
829 return SECFailure;
830 }
831
832 if (inputLen != modulusLen) {
833 PORT_SetError(SEC_ERROR_INPUT_LEN);
834 return SECFailure;
835 }
836
837 if ((labelLen == 0 && label != NULL) ||
838 (labelLen > 0 && label == NULL)) {
839 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
840 return SECFailure;
841 }
842
843 oaepEncoded = (unsigned char *)PORT_Alloc(modulusLen);
844 if (oaepEncoded == NULL) {
845 PORT_SetError(SEC_ERROR_NO_MEMORY);
846 return SECFailure;
847 }
848
849 rv = RSA_PrivateKeyOpDoubleChecked(key, oaepEncoded, input);
850 if (rv != SECSuccess) {
851 goto done;
852 }
853 rv = eme_oaep_decode(output, outputLen, maxOutputLen, oaepEncoded,
854 modulusLen, hashAlg, maskHashAlg, label,
855 labelLen);
856
857 done:
858 if (oaepEncoded)
859 PORT_ZFree(oaepEncoded, modulusLen);
860 return rv;
861 }
862
863 /* XXX Doesn't set error code */
864 SECStatus
865 RSA_EncryptBlock(RSAPublicKey * key,
866 unsigned char * output,
867 unsigned int * outputLen,
868 unsigned int maxOutputLen,
869 const unsigned char * input,
870 unsigned int inputLen)
871 {
872 SECStatus rv;
873 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
874 SECItem formatted;
875 SECItem unformatted;
876
877 formatted.data = NULL;
878 if (maxOutputLen < modulusLen)
879 goto failure;
880
881 unformatted.len = inputLen;
882 unformatted.data = (unsigned char*)input;
883 formatted.data = NULL;
884 rv = rsa_FormatBlock(&formatted, modulusLen, RSA_BlockPublic,
885 &unformatted);
886 if (rv != SECSuccess)
887 goto failure;
888
889 rv = RSA_PublicKeyOp(key, output, formatted.data);
890 if (rv != SECSuccess)
891 goto failure;
892
893 PORT_ZFree(formatted.data, modulusLen);
894 *outputLen = modulusLen;
895 return SECSuccess;
896
897 failure:
898 if (formatted.data != NULL)
899 PORT_ZFree(formatted.data, modulusLen);
900 return SECFailure;
901 }
902
903 /* XXX Doesn't set error code */
904 SECStatus
905 RSA_DecryptBlock(RSAPrivateKey * key,
906 unsigned char * output,
907 unsigned int * outputLen,
908 unsigned int maxOutputLen,
909 const unsigned char * input,
910 unsigned int inputLen)
911 {
912 SECStatus rv;
913 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
914 unsigned int i;
915 unsigned char * buffer;
916
917 if (inputLen != modulusLen)
918 goto failure;
919
920 buffer = (unsigned char *)PORT_Alloc(modulusLen + 1);
921 if (!buffer)
922 goto failure;
923
924 rv = RSA_PrivateKeyOp(key, buffer, input);
925 if (rv != SECSuccess)
926 goto loser;
927
928 /* XXX(rsleevi): Constant time */
929 if (buffer[0] != RSA_BLOCK_FIRST_OCTET ||
930 buffer[1] != (unsigned char)RSA_BlockPublic) {
931 goto loser;
932 }
933 *outputLen = 0;
934 for (i = 2; i < modulusLen; i++) {
935 if (buffer[i] == RSA_BLOCK_AFTER_PAD_OCTET) {
936 *outputLen = modulusLen - i - 1;
937 break;
938 }
939 }
940 if (*outputLen == 0)
941 goto loser;
942 if (*outputLen > maxOutputLen)
943 goto loser;
944
945 PORT_Memcpy(output, buffer + modulusLen - *outputLen, *outputLen);
946
947 PORT_Free(buffer);
948 return SECSuccess;
949
950 loser:
951 PORT_Free(buffer);
952 failure:
953 return SECFailure;
954 }
955
956 /*
957 * Encode a RSA-PSS signature.
958 * Described in RFC 3447, section 9.1.1.
959 * We use mHash instead of M as input.
960 * emBits from the RFC is just modBits - 1, see section 8.1.1.
961 * We only support MGF1 as the MGF.
962 *
963 * NOTE: this code assumes modBits is a multiple of 8.
964 */
965 static SECStatus
966 emsa_pss_encode(unsigned char * em,
967 unsigned int emLen,
968 const unsigned char * mHash,
969 HASH_HashType hashAlg,
970 HASH_HashType maskHashAlg,
971 const unsigned char * salt,
972 unsigned int saltLen)
973 {
974 const SECHashObject * hash;
975 void * hash_context;
976 unsigned char * dbMask;
977 unsigned int dbMaskLen;
978 unsigned int i;
979 SECStatus rv;
980
981 hash = HASH_GetRawHashObject(hashAlg);
982 dbMaskLen = emLen - hash->length - 1;
983
984 /* Step 3 */
985 if (emLen < hash->length + saltLen + 2) {
986 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
987 return SECFailure;
988 }
989
990 /* Step 4 */
991 if (salt == NULL) {
992 rv = RNG_GenerateGlobalRandomBytes(&em[dbMaskLen - saltLen], saltLen);
993 if (rv != SECSuccess) {
994 return rv;
995 }
996 } else {
997 PORT_Memcpy(&em[dbMaskLen - saltLen], salt, saltLen);
998 }
999
1000 /* Step 5 + 6 */
1001 /* Compute H and store it at its final location &em[dbMaskLen]. */
1002 hash_context = (*hash->create)();
1003 if (hash_context == NULL) {
1004 PORT_SetError(SEC_ERROR_NO_MEMORY);
1005 return SECFailure;
1006 }
1007 (*hash->begin)(hash_context);
1008 (*hash->update)(hash_context, eightZeros, 8);
1009 (*hash->update)(hash_context, mHash, hash->length);
1010 (*hash->update)(hash_context, &em[dbMaskLen - saltLen], saltLen);
1011 (*hash->end)(hash_context, &em[dbMaskLen], &i, hash->length);
1012 (*hash->destroy)(hash_context, PR_TRUE);
1013
1014 /* Step 7 + 8 */
1015 PORT_Memset(em, 0, dbMaskLen - saltLen - 1);
1016 em[dbMaskLen - saltLen - 1] = 0x01;
1017
1018 /* Step 9 */
1019 dbMask = (unsigned char *)PORT_Alloc(dbMaskLen);
1020 if (dbMask == NULL) {
1021 PORT_SetError(SEC_ERROR_NO_MEMORY);
1022 return SECFailure;
1023 }
1024 MGF1(maskHashAlg, dbMask, dbMaskLen, &em[dbMaskLen], hash->length);
1025
1026 /* Step 10 */
1027 for (i = 0; i < dbMaskLen; i++)
1028 em[i] ^= dbMask[i];
1029 PORT_Free(dbMask);
1030
1031 /* Step 11 */
1032 em[0] &= 0x7f;
1033
1034 /* Step 12 */
1035 em[emLen - 1] = 0xbc;
1036
1037 return SECSuccess;
1038 }
1039
1040 /*
1041 * Verify a RSA-PSS signature.
1042 * Described in RFC 3447, section 9.1.2.
1043 * We use mHash instead of M as input.
1044 * emBits from the RFC is just modBits - 1, see section 8.1.2.
1045 * We only support MGF1 as the MGF.
1046 *
1047 * NOTE: this code assumes modBits is a multiple of 8.
1048 */
1049 static SECStatus
1050 emsa_pss_verify(const unsigned char * mHash,
1051 const unsigned char * em,
1052 unsigned int emLen,
1053 HASH_HashType hashAlg,
1054 HASH_HashType maskHashAlg,
1055 unsigned int saltLen)
1056 {
1057 const SECHashObject * hash;
1058 void * hash_context;
1059 unsigned char * db;
1060 unsigned char * H_; /* H' from the RFC */
1061 unsigned int i;
1062 unsigned int dbMaskLen;
1063 SECStatus rv;
1064
1065 hash = HASH_GetRawHashObject(hashAlg);
1066 dbMaskLen = emLen - hash->length - 1;
1067
1068 /* Step 3 + 4 + 6 */
1069 if ((emLen < (hash->length + saltLen + 2)) ||
1070 (em[emLen - 1] != 0xbc) ||
1071 ((em[0] & 0x80) != 0)) {
1072 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1073 return SECFailure;
1074 }
1075
1076 /* Step 7 */
1077 db = (unsigned char *)PORT_Alloc(dbMaskLen);
1078 if (db == NULL) {
1079 PORT_SetError(SEC_ERROR_NO_MEMORY);
1080 return SECFailure;
1081 }
1082 /* &em[dbMaskLen] points to H, used as mgfSeed */
1083 MGF1(maskHashAlg, db, dbMaskLen, &em[dbMaskLen], hash->length);
1084
1085 /* Step 8 */
1086 for (i = 0; i < dbMaskLen; i++) {
1087 db[i] ^= em[i];
1088 }
1089
1090 /* Step 9 */
1091 db[0] &= 0x7f;
1092
1093 /* Step 10 */
1094 for (i = 0; i < (dbMaskLen - saltLen - 1); i++) {
1095 if (db[i] != 0) {
1096 PORT_Free(db);
1097 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1098 return SECFailure;
1099 }
1100 }
1101 if (db[dbMaskLen - saltLen - 1] != 0x01) {
1102 PORT_Free(db);
1103 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1104 return SECFailure;
1105 }
1106
1107 /* Step 12 + 13 */
1108 H_ = (unsigned char *)PORT_Alloc(hash->length);
1109 if (H_ == NULL) {
1110 PORT_Free(db);
1111 PORT_SetError(SEC_ERROR_NO_MEMORY);
1112 return SECFailure;
1113 }
1114 hash_context = (*hash->create)();
1115 if (hash_context == NULL) {
1116 PORT_Free(db);
1117 PORT_Free(H_);
1118 PORT_SetError(SEC_ERROR_NO_MEMORY);
1119 return SECFailure;
1120 }
1121 (*hash->begin)(hash_context);
1122 (*hash->update)(hash_context, eightZeros, 8);
1123 (*hash->update)(hash_context, mHash, hash->length);
1124 (*hash->update)(hash_context, &db[dbMaskLen - saltLen], saltLen);
1125 (*hash->end)(hash_context, H_, &i, hash->length);
1126 (*hash->destroy)(hash_context, PR_TRUE);
1127
1128 PORT_Free(db);
1129
1130 /* Step 14 */
1131 if (PORT_Memcmp(H_, &em[dbMaskLen], hash->length) != 0) {
1132 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1133 rv = SECFailure;
1134 } else {
1135 rv = SECSuccess;
1136 }
1137
1138 PORT_Free(H_);
1139 return rv;
1140 }
1141
1142 SECStatus
1143 RSA_SignPSS(RSAPrivateKey * key,
1144 HASH_HashType hashAlg,
1145 HASH_HashType maskHashAlg,
1146 const unsigned char * salt,
1147 unsigned int saltLength,
1148 unsigned char * output,
1149 unsigned int * outputLen,
1150 unsigned int maxOutputLen,
1151 const unsigned char * input,
1152 unsigned int inputLen)
1153 {
1154 SECStatus rv = SECSuccess;
1155 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
1156 unsigned char *pssEncoded = NULL;
1157
1158 if (maxOutputLen < modulusLen) {
1159 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
1160 return SECFailure;
1161 }
1162
1163 if ((hashAlg == HASH_AlgNULL) || (maskHashAlg == HASH_AlgNULL)) {
1164 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
1165 return SECFailure;
1166 }
1167
1168 pssEncoded = (unsigned char *)PORT_Alloc(modulusLen);
1169 if (pssEncoded == NULL) {
1170 PORT_SetError(SEC_ERROR_NO_MEMORY);
1171 return SECFailure;
1172 }
1173 rv = emsa_pss_encode(pssEncoded, modulusLen, input, hashAlg,
1174 maskHashAlg, salt, saltLength);
1175 if (rv != SECSuccess)
1176 goto done;
1177
1178 rv = RSA_PrivateKeyOpDoubleChecked(key, output, pssEncoded);
1179 *outputLen = modulusLen;
1180
1181 done:
1182 PORT_Free(pssEncoded);
1183 return rv;
1184 }
1185
1186 SECStatus
1187 RSA_CheckSignPSS(RSAPublicKey * key,
1188 HASH_HashType hashAlg,
1189 HASH_HashType maskHashAlg,
1190 unsigned int saltLength,
1191 const unsigned char * sig,
1192 unsigned int sigLen,
1193 const unsigned char * hash,
1194 unsigned int hashLen)
1195 {
1196 SECStatus rv;
1197 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
1198 unsigned char * buffer;
1199
1200 if (sigLen != modulusLen) {
1201 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1202 return SECFailure;
1203 }
1204
1205 if ((hashAlg == HASH_AlgNULL) || (maskHashAlg == HASH_AlgNULL)) {
1206 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
1207 return SECFailure;
1208 }
1209
1210 buffer = (unsigned char *)PORT_Alloc(modulusLen);
1211 if (!buffer) {
1212 PORT_SetError(SEC_ERROR_NO_MEMORY);
1213 return SECFailure;
1214 }
1215
1216 rv = RSA_PublicKeyOp(key, buffer, sig);
1217 if (rv != SECSuccess) {
1218 PORT_Free(buffer);
1219 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
1220 return SECFailure;
1221 }
1222
1223 rv = emsa_pss_verify(hash, buffer, modulusLen, hashAlg,
1224 maskHashAlg, saltLength);
1225 PORT_Free(buffer);
1226
1227 return rv;
1228 }
1229
1230 /* XXX Doesn't set error code */
1231 SECStatus
1232 RSA_Sign(RSAPrivateKey * key,
1233 unsigned char * output,
1234 unsigned int * outputLen,
1235 unsigned int maxOutputLen,
1236 const unsigned char * input,
1237 unsigned int inputLen)
1238 {
1239 SECStatus rv = SECSuccess;
1240 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
1241 SECItem formatted;
1242 SECItem unformatted;
1243
1244 if (maxOutputLen < modulusLen)
1245 return SECFailure;
1246
1247 unformatted.len = inputLen;
1248 unformatted.data = (unsigned char*)input;
1249 formatted.data = NULL;
1250 rv = rsa_FormatBlock(&formatted, modulusLen, RSA_BlockPrivate,
1251 &unformatted);
1252 if (rv != SECSuccess)
1253 goto done;
1254
1255 rv = RSA_PrivateKeyOpDoubleChecked(key, output, formatted.data);
1256 *outputLen = modulusLen;
1257
1258 goto done;
1259
1260 done:
1261 if (formatted.data != NULL)
1262 PORT_ZFree(formatted.data, modulusLen);
1263 return rv;
1264 }
1265
1266 /* XXX Doesn't set error code */
1267 SECStatus
1268 RSA_CheckSign(RSAPublicKey * key,
1269 const unsigned char * sig,
1270 unsigned int sigLen,
1271 const unsigned char * data,
1272 unsigned int dataLen)
1273 {
1274 SECStatus rv;
1275 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
1276 unsigned int i;
1277 unsigned char * buffer;
1278
1279 if (sigLen != modulusLen)
1280 goto failure;
1281 /*
1282 * 0x00 || BT || Pad || 0x00 || ActualData
1283 *
1284 * The "3" below is the first octet + the second octet + the 0x00
1285 * octet that always comes just before the ActualData.
1286 */
1287 if (dataLen > modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN))
1288 goto failure;
1289
1290 buffer = (unsigned char *)PORT_Alloc(modulusLen + 1);
1291 if (!buffer)
1292 goto failure;
1293
1294 rv = RSA_PublicKeyOp(key, buffer, sig);
1295 if (rv != SECSuccess)
1296 goto loser;
1297
1298 /*
1299 * check the padding that was used
1300 */
1301 if (buffer[0] != RSA_BLOCK_FIRST_OCTET ||
1302 buffer[1] != (unsigned char)RSA_BlockPrivate) {
1303 goto loser;
1304 }
1305 for (i = 2; i < modulusLen - dataLen - 1; i++) {
1306 if (buffer[i] != RSA_BLOCK_PRIVATE_PAD_OCTET)
1307 goto loser;
1308 }
1309 if (buffer[i] != RSA_BLOCK_AFTER_PAD_OCTET)
1310 goto loser;
1311
1312 /*
1313 * make sure we get the same results
1314 */
1315 if (PORT_Memcmp(buffer + modulusLen - dataLen, data, dataLen) != 0)
1316 goto loser;
1317
1318 PORT_Free(buffer);
1319 return SECSuccess;
1320
1321 loser:
1322 PORT_Free(buffer);
1323 failure:
1324 return SECFailure;
1325 }
1326
1327 /* XXX Doesn't set error code */
1328 SECStatus
1329 RSA_CheckSignRecover(RSAPublicKey * key,
1330 unsigned char * output,
1331 unsigned int * outputLen,
1332 unsigned int maxOutputLen,
1333 const unsigned char * sig,
1334 unsigned int sigLen)
1335 {
1336 SECStatus rv;
1337 unsigned int modulusLen = rsa_modulusLen(&key->modulus);
1338 unsigned int i;
1339 unsigned char * buffer;
1340
1341 if (sigLen != modulusLen)
1342 goto failure;
1343
1344 buffer = (unsigned char *)PORT_Alloc(modulusLen + 1);
1345 if (!buffer)
1346 goto failure;
1347
1348 rv = RSA_PublicKeyOp(key, buffer, sig);
1349 if (rv != SECSuccess)
1350 goto loser;
1351 *outputLen = 0;
1352
1353 /*
1354 * check the padding that was used
1355 */
1356 if (buffer[0] != RSA_BLOCK_FIRST_OCTET ||
1357 buffer[1] != (unsigned char)RSA_BlockPrivate) {
1358 goto loser;
1359 }
1360 for (i = 2; i < modulusLen; i++) {
1361 if (buffer[i] == RSA_BLOCK_AFTER_PAD_OCTET) {
1362 *outputLen = modulusLen - i - 1;
1363 break;
1364 }
1365 if (buffer[i] != RSA_BLOCK_PRIVATE_PAD_OCTET)
1366 goto loser;
1367 }
1368 if (*outputLen == 0)
1369 goto loser;
1370 if (*outputLen > maxOutputLen)
1371 goto loser;
1372
1373 PORT_Memcpy(output, buffer + modulusLen - *outputLen, *outputLen);
1374
1375 PORT_Free(buffer);
1376 return SECSuccess;
1377
1378 loser:
1379 PORT_Free(buffer);
1380 failure:
1381 return SECFailure;
1382 }
OLDNEW
« no previous file with comments | « nss/lib/freebl/rijndael.c ('k') | nss/lib/freebl/unix_rand.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698