OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/webcrypto_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || | 91 algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || |
92 algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep); | 92 algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep); |
93 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | 93 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
94 algorithm_id, | 94 algorithm_id, |
95 new blink::WebCryptoRsaKeyGenParams( | 95 new blink::WebCryptoRsaKeyGenParams( |
96 modulus_length, Start(public_exponent), public_exponent.size())); | 96 modulus_length, Start(public_exponent), public_exponent.size())); |
97 } | 97 } |
98 | 98 |
99 #endif // #if !defined(USE_OPENSSL) | 99 #endif // #if !defined(USE_OPENSSL) |
100 | 100 |
101 // MIT HAKMEM Bit Count for 8-bit Unsigned Char | |
102 int BitCount8(unsigned char b) { | |
103 b = (b & 0x55u) + ((b >> 1) & 0x55u); | |
104 b = (b & 0x33u) + ((b >> 2) & 0x33u); | |
105 b = (b & 0x0fu) + ((b >> 4) & 0x0fu); | |
106 return (b); | |
107 } | |
108 | |
109 // Use a binary entropy calculation to check whether the input data appears | |
110 // random. See http://en.wikipedia.org/wiki/Binary_entropy. | |
111 void ExpectDataAppearsRandom(const blink::WebArrayBuffer& key_bytes) { | |
112 DCHECK(key_bytes.data()); | |
113 DCHECK(key_bytes.byteLength()); | |
114 int n_set_bits = 0; | |
115 unsigned char* data_ptr = static_cast<unsigned char*>(key_bytes.data()); | |
116 unsigned char* const data_ptr_end = data_ptr + key_bytes.byteLength(); | |
117 while (data_ptr < data_ptr_end) { | |
118 n_set_bits += BitCount8(*data_ptr++); | |
119 } | |
120 // Binary entropy is calculated as -p * log2(p) - (1 - p) * log2(1 - p), where | |
121 // p is the percentage of set bits in the input data. This function has a | |
122 // maximum of 1.0 at p = 0.5. Arbitrarily say the input data is random if the | |
123 // calculated entropy is > 0.75, which solves to 0.2145 ~< p ~< 0.7855. | |
eroman
2013/12/04 19:04:00
Doesn't this mean that truly random buffers will f
padolph
2013/12/04 22:22:13
No, the math does not work that way. However, I re
| |
124 double p = static_cast<double>(n_set_bits) / (key_bytes.byteLength() * 8); | |
125 EXPECT_GT(p, 0.2145); | |
126 EXPECT_LT(p, 0.7855); | |
127 } | |
128 | |
101 } // namespace | 129 } // namespace |
102 | 130 |
103 namespace content { | 131 namespace content { |
104 | 132 |
105 class WebCryptoImplTest : public testing::Test { | 133 class WebCryptoImplTest : public testing::Test { |
106 protected: | 134 protected: |
107 blink::WebCryptoKey ImportSecretKeyFromRawHexString( | 135 blink::WebCryptoKey ImportSecretKeyFromRawHexString( |
108 const std::string& key_hex, | 136 const std::string& key_hex, |
109 const blink::WebCryptoAlgorithm& algorithm, | 137 const blink::WebCryptoAlgorithm& algorithm, |
110 blink::WebCryptoKeyUsageMask usage) { | 138 blink::WebCryptoKeyUsageMask usage) { |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
414 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests); | 442 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests); |
415 ++test_index) { | 443 ++test_index) { |
416 SCOPED_TRACE(test_index); | 444 SCOPED_TRACE(test_index); |
417 const TestCase& test = kTests[test_index]; | 445 const TestCase& test = kTests[test_index]; |
418 | 446 |
419 blink::WebCryptoAlgorithm algorithm = CreateHmacAlgorithm(test.algorithm); | 447 blink::WebCryptoAlgorithm algorithm = CreateHmacAlgorithm(test.algorithm); |
420 | 448 |
421 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 449 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
422 test.key, algorithm, blink::WebCryptoKeyUsageSign); | 450 test.key, algorithm, blink::WebCryptoKeyUsageSign); |
423 | 451 |
452 // Verify exported raw key is identical to the imported data | |
453 blink::WebArrayBuffer raw_key; | |
454 EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); | |
455 ExpectArrayBufferMatchesHex(test.key, raw_key); | |
456 | |
424 std::vector<uint8> message_raw = HexStringToBytes(test.message); | 457 std::vector<uint8> message_raw = HexStringToBytes(test.message); |
425 | 458 |
426 blink::WebArrayBuffer output; | 459 blink::WebArrayBuffer output; |
427 | 460 |
428 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); | 461 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); |
429 | 462 |
430 ExpectArrayBufferMatchesHex(test.mac, output); | 463 ExpectArrayBufferMatchesHex(test.mac, output); |
431 | 464 |
432 bool signature_match = false; | 465 bool signature_match = false; |
433 EXPECT_TRUE(VerifySignatureInternal( | 466 EXPECT_TRUE(VerifySignatureInternal( |
(...skipping 22 matching lines...) Expand all Loading... | |
456 key, | 489 key, |
457 kLongSignature, | 490 kLongSignature, |
458 sizeof(kLongSignature), | 491 sizeof(kLongSignature), |
459 message_raw, | 492 message_raw, |
460 &signature_match)); | 493 &signature_match)); |
461 EXPECT_FALSE(signature_match); | 494 EXPECT_FALSE(signature_match); |
462 } | 495 } |
463 } | 496 } |
464 | 497 |
465 TEST_F(WebCryptoImplTest, AesCbcFailures) { | 498 TEST_F(WebCryptoImplTest, AesCbcFailures) { |
499 const std::string key_hex = "2b7e151628aed2a6abf7158809cf4f3c"; | |
466 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 500 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
467 "2b7e151628aed2a6abf7158809cf4f3c", | 501 key_hex, |
468 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), | 502 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
469 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); | 503 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
470 | 504 |
505 // Verify exported raw key is identical to the imported data | |
506 blink::WebArrayBuffer raw_key; | |
507 EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); | |
508 ExpectArrayBufferMatchesHex(key_hex, raw_key); | |
509 | |
471 blink::WebArrayBuffer output; | 510 blink::WebArrayBuffer output; |
472 | 511 |
473 // Use an invalid |iv| (fewer than 16 bytes) | 512 // Use an invalid |iv| (fewer than 16 bytes) |
474 { | 513 { |
475 std::vector<uint8> input(32); | 514 std::vector<uint8> input(32); |
476 std::vector<uint8> iv; | 515 std::vector<uint8> iv; |
477 EXPECT_FALSE( | 516 EXPECT_FALSE( |
478 EncryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output)); | 517 EncryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output)); |
479 EXPECT_FALSE( | 518 EXPECT_FALSE( |
480 DecryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output)); | 519 DecryptInternal(CreateAesCbcAlgorithm(iv), key, input, &output)); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
514 | 553 |
515 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 554 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
516 EXPECT_FALSE(ImportKeyInternal(blink::WebCryptoKeyFormatRaw, | 555 EXPECT_FALSE(ImportKeyInternal(blink::WebCryptoKeyFormatRaw, |
517 key_raw, | 556 key_raw, |
518 CreateAesCbcAlgorithm(iv), | 557 CreateAesCbcAlgorithm(iv), |
519 true, | 558 true, |
520 blink::WebCryptoKeyUsageEncrypt, | 559 blink::WebCryptoKeyUsageEncrypt, |
521 &key)); | 560 &key)); |
522 } | 561 } |
523 | 562 |
524 // Fail exporting the key in SPKI format (SPKI export not allowed for secret | 563 // Fail exporting the key in SPKI and PKCS#8 formats (not allowed for secret |
525 // keys) | 564 // keys). |
526 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); | 565 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); |
566 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatPkcs8, key, &output)); | |
527 } | 567 } |
528 | 568 |
529 TEST_F(WebCryptoImplTest, AesCbcSampleSets) { | 569 TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
530 struct TestCase { | 570 struct TestCase { |
531 const char* key; | 571 const char* key; |
532 const char* iv; | 572 const char* iv; |
533 const char* plain_text; | 573 const char* plain_text; |
534 const char* cipher_text; | 574 const char* cipher_text; |
535 }; | 575 }; |
536 | 576 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
606 | 646 |
607 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(kTests); index++) { | 647 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(kTests); index++) { |
608 SCOPED_TRACE(index); | 648 SCOPED_TRACE(index); |
609 const TestCase& test = kTests[index]; | 649 const TestCase& test = kTests[index]; |
610 | 650 |
611 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 651 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
612 test.key, | 652 test.key, |
613 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), | 653 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
614 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); | 654 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
615 | 655 |
656 // Verify exported raw key is identical to the imported data | |
657 blink::WebArrayBuffer raw_key; | |
658 EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); | |
659 ExpectArrayBufferMatchesHex(test.key, raw_key); | |
660 | |
616 std::vector<uint8> plain_text = HexStringToBytes(test.plain_text); | 661 std::vector<uint8> plain_text = HexStringToBytes(test.plain_text); |
617 std::vector<uint8> iv = HexStringToBytes(test.iv); | 662 std::vector<uint8> iv = HexStringToBytes(test.iv); |
618 | 663 |
619 blink::WebArrayBuffer output; | 664 blink::WebArrayBuffer output; |
620 | 665 |
621 // Test encryption. | 666 // Test encryption. |
622 EXPECT_TRUE(EncryptInternal(CreateAesCbcAlgorithm(iv), | 667 EXPECT_TRUE(EncryptInternal(CreateAesCbcAlgorithm(iv), |
623 key, | 668 key, |
624 plain_text, | 669 plain_text, |
625 &output)); | 670 &output)); |
(...skipping 24 matching lines...) Expand all Loading... | |
650 if (cipher_text.size() > 3) { | 695 if (cipher_text.size() > 3) { |
651 EXPECT_FALSE(DecryptInternal(CreateAesCbcAlgorithm(iv), | 696 EXPECT_FALSE(DecryptInternal(CreateAesCbcAlgorithm(iv), |
652 key, | 697 key, |
653 &cipher_text[0], | 698 &cipher_text[0], |
654 cipher_text.size() - 3, | 699 cipher_text.size() - 3, |
655 &output)); | 700 &output)); |
656 } | 701 } |
657 } | 702 } |
658 } | 703 } |
659 | 704 |
660 // TODO(padolph): Add test to verify generated symmetric keys appear random. | |
661 | |
662 TEST_F(WebCryptoImplTest, GenerateKeyAes) { | 705 TEST_F(WebCryptoImplTest, GenerateKeyAes) { |
663 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 706 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
664 ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcAlgorithm(128), &key)); | 707 ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcAlgorithm(128), &key)); |
665 EXPECT_TRUE(key.handle()); | 708 EXPECT_TRUE(key.handle()); |
666 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 709 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
710 blink::WebArrayBuffer key_bytes; | |
711 ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &key_bytes)); | |
712 ExpectDataAppearsRandom(key_bytes); | |
667 } | 713 } |
668 | 714 |
669 TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { | 715 TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { |
670 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 716 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
671 EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(0), &key)); | 717 EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(0), &key)); |
672 EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(129), &key)); | 718 EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(129), &key)); |
673 } | 719 } |
674 | 720 |
675 TEST_F(WebCryptoImplTest, GenerateKeyHmac) { | 721 TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
676 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 722 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
677 blink::WebCryptoAlgorithm algorithm = | 723 blink::WebCryptoAlgorithm algorithm = |
678 CreateHmacKeyAlgorithm(blink::WebCryptoAlgorithmIdSha1, 128); | 724 CreateHmacKeyAlgorithm(blink::WebCryptoAlgorithmIdSha1, 128); |
679 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | 725 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
680 EXPECT_FALSE(key.isNull()); | 726 EXPECT_FALSE(key.isNull()); |
681 EXPECT_TRUE(key.handle()); | 727 EXPECT_TRUE(key.handle()); |
682 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 728 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
729 blink::WebArrayBuffer key_bytes; | |
730 ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &key_bytes)); | |
731 ExpectDataAppearsRandom(key_bytes); | |
683 } | 732 } |
684 | 733 |
685 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { | 734 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { |
686 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 735 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
687 blink::WebCryptoAlgorithm algorithm = | 736 blink::WebCryptoAlgorithm algorithm = |
688 CreateHmacKeyAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); | 737 CreateHmacKeyAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); |
689 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | 738 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
690 EXPECT_TRUE(key.handle()); | 739 EXPECT_TRUE(key.handle()); |
691 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 740 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
692 } | 741 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
773 true, | 822 true, |
774 blink::WebCryptoKeyUsageEncrypt, | 823 blink::WebCryptoKeyUsageEncrypt, |
775 &key)); | 824 &key)); |
776 | 825 |
777 // Passing case: Export a previously imported RSA public key in SPKI format | 826 // Passing case: Export a previously imported RSA public key in SPKI format |
778 // and compare to original data. | 827 // and compare to original data. |
779 blink::WebArrayBuffer output; | 828 blink::WebArrayBuffer output; |
780 ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); | 829 ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); |
781 ExpectArrayBufferMatchesHex(hex_rsa_spki_der, output); | 830 ExpectArrayBufferMatchesHex(hex_rsa_spki_der, output); |
782 | 831 |
832 // Failing case: Try to export a previously imported RSA public key in raw | |
833 // format (not allowed for a public key). | |
834 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &output)); | |
835 | |
783 // Failing case: Try to export a non-extractable key | 836 // Failing case: Try to export a non-extractable key |
784 ASSERT_TRUE(ImportKeyInternal( | 837 ASSERT_TRUE(ImportKeyInternal( |
785 blink::WebCryptoKeyFormatSpki, | 838 blink::WebCryptoKeyFormatSpki, |
786 HexStringToBytes(hex_rsa_spki_der), | 839 HexStringToBytes(hex_rsa_spki_der), |
787 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), | 840 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), |
788 false, | 841 false, |
789 blink::WebCryptoKeyUsageEncrypt, | 842 blink::WebCryptoKeyUsageEncrypt, |
790 &key)); | 843 &key)); |
791 EXPECT_TRUE(key.handle()); | 844 EXPECT_TRUE(key.handle()); |
792 EXPECT_FALSE(key.extractable()); | 845 EXPECT_FALSE(key.extractable()); |
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1238 private_key, | 1291 private_key, |
1239 reinterpret_cast<const unsigned char*>(encrypted_data.data()), | 1292 reinterpret_cast<const unsigned char*>(encrypted_data.data()), |
1240 encrypted_data.byteLength(), | 1293 encrypted_data.byteLength(), |
1241 &decrypted_data)); | 1294 &decrypted_data)); |
1242 ExpectArrayBufferMatchesHex(message_hex_str, decrypted_data); | 1295 ExpectArrayBufferMatchesHex(message_hex_str, decrypted_data); |
1243 } | 1296 } |
1244 | 1297 |
1245 #endif // #if !defined(USE_OPENSSL) | 1298 #endif // #if !defined(USE_OPENSSL) |
1246 | 1299 |
1247 } // namespace content | 1300 } // namespace content |
OLD | NEW |