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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
87 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | 87 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
88 algorithm_id, | 88 algorithm_id, |
89 new blink::WebCryptoRsaKeyGenParams( | 89 new blink::WebCryptoRsaKeyGenParams( |
90 modulus_length, | 90 modulus_length, |
91 webcrypto::Uint8VectorStart(public_exponent), | 91 webcrypto::Uint8VectorStart(public_exponent), |
92 public_exponent.size())); | 92 public_exponent.size())); |
93 } | 93 } |
94 | 94 |
95 #endif // #if !defined(USE_OPENSSL) | 95 #endif // #if !defined(USE_OPENSSL) |
96 | 96 |
97 // Determines if two ArrayBuffers have identical content. | |
98 bool ArrayBuffersEqual( | |
99 const blink::WebArrayBuffer& a, | |
100 const blink::WebArrayBuffer& b) { | |
101 if (a.byteLength() != b.byteLength()) | |
102 return false; | |
103 const uint8* a_begin = static_cast<uint8*>(a.data()); | |
104 const uint8* const a_end = a_begin + a.byteLength(); | |
105 const uint8* b_begin = static_cast<uint8*>(b.data()); | |
106 return std::equal(a_begin, a_end, b_begin); | |
eroman
2013/12/05 01:47:53
[no change necessary] My inclination would have be
padolph
2013/12/05 02:45:57
I'm sure std::equal optimizes down to memcmp in th
| |
107 } | |
108 | |
109 // Adapts ArrayBufferEqual() into a unary predicate for use with std::count_if | |
110 // in CopiesExist(). | |
111 class ArrayBufferEqualTo { | |
112 public: | |
113 ArrayBufferEqualTo(const blink::WebArrayBuffer& b) : b_(b) {} | |
114 bool operator()(const blink::WebArrayBuffer& a) const { | |
115 return ArrayBuffersEqual(a, b_); | |
116 } | |
117 | |
118 private: | |
119 const blink::WebArrayBuffer& b_; | |
120 }; | |
121 | |
122 // Given a vector of WebArrayBuffers, determines if there are any copies. Not | |
123 // the most efficient implementation, but the vector is expected to be small. | |
124 bool CopiesExist(std::vector<blink::WebArrayBuffer> bufs) { | |
125 for (std::vector<blink::WebArrayBuffer>::const_iterator it = bufs.begin(); | |
eroman
2013/12/05 01:47:53
I much prefer the old-fashioned double-for-loop he
padolph
2013/12/05 02:45:57
I can't argue with that. 1/3 the lines and faster.
| |
126 it != bufs.end(); | |
127 ++it) { | |
128 if (std::count_if(bufs.begin(), bufs.end(), ArrayBufferEqualTo(*it)) != 1) | |
129 return true; | |
130 } | |
131 return false; | |
132 } | |
133 | |
97 } // namespace | 134 } // namespace |
98 | 135 |
99 class WebCryptoImplTest : public testing::Test { | 136 class WebCryptoImplTest : public testing::Test { |
100 protected: | 137 protected: |
101 blink::WebCryptoKey ImportSecretKeyFromRawHexString( | 138 blink::WebCryptoKey ImportSecretKeyFromRawHexString( |
102 const std::string& key_hex, | 139 const std::string& key_hex, |
103 const blink::WebCryptoAlgorithm& algorithm, | 140 const blink::WebCryptoAlgorithm& algorithm, |
104 blink::WebCryptoKeyUsageMask usage) { | 141 blink::WebCryptoKeyUsageMask usage) { |
105 std::vector<uint8> key_raw = HexStringToBytes(key_hex); | 142 std::vector<uint8> key_raw = HexStringToBytes(key_hex); |
106 | 143 |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
425 ++test_index) { | 462 ++test_index) { |
426 SCOPED_TRACE(test_index); | 463 SCOPED_TRACE(test_index); |
427 const TestCase& test = kTests[test_index]; | 464 const TestCase& test = kTests[test_index]; |
428 | 465 |
429 blink::WebCryptoAlgorithm algorithm = | 466 blink::WebCryptoAlgorithm algorithm = |
430 webcrypto::CreateHmacAlgorithmByHashId(test.algorithm); | 467 webcrypto::CreateHmacAlgorithmByHashId(test.algorithm); |
431 | 468 |
432 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 469 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
433 test.key, algorithm, blink::WebCryptoKeyUsageSign); | 470 test.key, algorithm, blink::WebCryptoKeyUsageSign); |
434 | 471 |
472 // Verify exported raw key is identical to the imported data | |
473 blink::WebArrayBuffer raw_key; | |
474 EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); | |
475 ExpectArrayBufferMatchesHex(test.key, raw_key); | |
476 | |
435 std::vector<uint8> message_raw = HexStringToBytes(test.message); | 477 std::vector<uint8> message_raw = HexStringToBytes(test.message); |
436 | 478 |
437 blink::WebArrayBuffer output; | 479 blink::WebArrayBuffer output; |
438 | 480 |
439 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); | 481 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); |
440 | 482 |
441 ExpectArrayBufferMatchesHex(test.mac, output); | 483 ExpectArrayBufferMatchesHex(test.mac, output); |
442 | 484 |
443 bool signature_match = false; | 485 bool signature_match = false; |
444 EXPECT_TRUE(VerifySignatureInternal( | 486 EXPECT_TRUE(VerifySignatureInternal( |
(...skipping 24 matching lines...) Expand all Loading... | |
469 sizeof(kLongSignature), | 511 sizeof(kLongSignature), |
470 message_raw, | 512 message_raw, |
471 &signature_match)); | 513 &signature_match)); |
472 EXPECT_FALSE(signature_match); | 514 EXPECT_FALSE(signature_match); |
473 } | 515 } |
474 } | 516 } |
475 | 517 |
476 #if !defined(USE_OPENSSL) | 518 #if !defined(USE_OPENSSL) |
477 | 519 |
478 TEST_F(WebCryptoImplTest, AesCbcFailures) { | 520 TEST_F(WebCryptoImplTest, AesCbcFailures) { |
521 const std::string key_hex = "2b7e151628aed2a6abf7158809cf4f3c"; | |
479 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 522 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
480 "2b7e151628aed2a6abf7158809cf4f3c", | 523 key_hex, |
481 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), | 524 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
482 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); | 525 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
483 | 526 |
527 // Verify exported raw key is identical to the imported data | |
528 blink::WebArrayBuffer raw_key; | |
529 EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); | |
530 ExpectArrayBufferMatchesHex(key_hex, raw_key); | |
531 | |
484 blink::WebArrayBuffer output; | 532 blink::WebArrayBuffer output; |
485 | 533 |
486 // Use an invalid |iv| (fewer than 16 bytes) | 534 // Use an invalid |iv| (fewer than 16 bytes) |
487 { | 535 { |
488 std::vector<uint8> input(32); | 536 std::vector<uint8> input(32); |
489 std::vector<uint8> iv; | 537 std::vector<uint8> iv; |
490 EXPECT_FALSE(EncryptInternal( | 538 EXPECT_FALSE(EncryptInternal( |
491 webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); | 539 webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); |
492 EXPECT_FALSE(DecryptInternal( | 540 EXPECT_FALSE(DecryptInternal( |
493 webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); | 541 webcrypto::CreateAesCbcAlgorithm(iv), key, input, &output)); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
527 | 575 |
528 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 576 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
529 EXPECT_FALSE(ImportKeyInternal(blink::WebCryptoKeyFormatRaw, | 577 EXPECT_FALSE(ImportKeyInternal(blink::WebCryptoKeyFormatRaw, |
530 key_raw, | 578 key_raw, |
531 webcrypto::CreateAesCbcAlgorithm(iv), | 579 webcrypto::CreateAesCbcAlgorithm(iv), |
532 true, | 580 true, |
533 blink::WebCryptoKeyUsageEncrypt, | 581 blink::WebCryptoKeyUsageEncrypt, |
534 &key)); | 582 &key)); |
535 } | 583 } |
536 | 584 |
537 // Fail exporting the key in SPKI format (SPKI export not allowed for secret | 585 // Fail exporting the key in SPKI and PKCS#8 formats (not allowed for secret |
538 // keys) | 586 // keys). |
539 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); | 587 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); |
588 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatPkcs8, key, &output)); | |
540 } | 589 } |
541 | 590 |
542 TEST_F(WebCryptoImplTest, AesCbcSampleSets) { | 591 TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
543 struct TestCase { | 592 struct TestCase { |
544 const char* key; | 593 const char* key; |
545 const char* iv; | 594 const char* iv; |
546 const char* plain_text; | 595 const char* plain_text; |
547 const char* cipher_text; | 596 const char* cipher_text; |
548 }; | 597 }; |
549 | 598 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
619 | 668 |
620 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(kTests); index++) { | 669 for (size_t index = 0; index < ARRAYSIZE_UNSAFE(kTests); index++) { |
621 SCOPED_TRACE(index); | 670 SCOPED_TRACE(index); |
622 const TestCase& test = kTests[index]; | 671 const TestCase& test = kTests[index]; |
623 | 672 |
624 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 673 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
625 test.key, | 674 test.key, |
626 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), | 675 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
627 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); | 676 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
628 | 677 |
678 // Verify exported raw key is identical to the imported data | |
679 blink::WebArrayBuffer raw_key; | |
680 EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); | |
681 ExpectArrayBufferMatchesHex(test.key, raw_key); | |
682 | |
629 std::vector<uint8> plain_text = HexStringToBytes(test.plain_text); | 683 std::vector<uint8> plain_text = HexStringToBytes(test.plain_text); |
630 std::vector<uint8> iv = HexStringToBytes(test.iv); | 684 std::vector<uint8> iv = HexStringToBytes(test.iv); |
631 | 685 |
632 blink::WebArrayBuffer output; | 686 blink::WebArrayBuffer output; |
633 | 687 |
634 // Test encryption. | 688 // Test encryption. |
635 EXPECT_TRUE(EncryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), | 689 EXPECT_TRUE(EncryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), |
636 key, | 690 key, |
637 plain_text, | 691 plain_text, |
638 &output)); | 692 &output)); |
(...skipping 24 matching lines...) Expand all Loading... | |
663 if (cipher_text.size() > 3) { | 717 if (cipher_text.size() > 3) { |
664 EXPECT_FALSE(DecryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), | 718 EXPECT_FALSE(DecryptInternal(webcrypto::CreateAesCbcAlgorithm(iv), |
665 key, | 719 key, |
666 &cipher_text[0], | 720 &cipher_text[0], |
667 cipher_text.size() - 3, | 721 cipher_text.size() - 3, |
668 &output)); | 722 &output)); |
669 } | 723 } |
670 } | 724 } |
671 } | 725 } |
672 | 726 |
673 // TODO(padolph): Add test to verify generated symmetric keys appear random. | |
674 | |
675 TEST_F(WebCryptoImplTest, GenerateKeyAes) { | 727 TEST_F(WebCryptoImplTest, GenerateKeyAes) { |
676 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 728 // Generate a small sample of AES keys. |
677 ASSERT_TRUE( | 729 std::vector<blink::WebArrayBuffer> keys; |
678 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(128), &key)); | 730 blink::WebArrayBuffer key_bytes; |
679 EXPECT_TRUE(key.handle()); | 731 for (int i = 0; i < 16; ++i) { |
680 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 732 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
733 ASSERT_TRUE( | |
734 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(128), &key)); | |
735 EXPECT_TRUE(key.handle()); | |
736 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
737 ASSERT_TRUE( | |
738 ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &key_bytes)); | |
739 keys.push_back(key_bytes); | |
740 } | |
741 // Ensure all entries in the key sample set are unique. This is a simplistic | |
742 // estimate of whether the generated keys appear random. | |
743 EXPECT_FALSE(CopiesExist(keys)); | |
681 } | 744 } |
682 | 745 |
683 TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { | 746 TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { |
684 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 747 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
685 EXPECT_FALSE( | 748 EXPECT_FALSE( |
686 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key)); | 749 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key)); |
687 EXPECT_FALSE( | 750 EXPECT_FALSE( |
688 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key)); | 751 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(0), &key)); |
689 EXPECT_FALSE( | 752 EXPECT_FALSE( |
690 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(129), &key)); | 753 GenerateKeyInternal(webcrypto::CreateAesCbcKeyGenAlgorithm(129), &key)); |
691 } | 754 } |
692 | 755 |
693 TEST_F(WebCryptoImplTest, GenerateKeyHmac) { | 756 TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
694 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 757 // Generate a small sample of HMAC keys. |
695 blink::WebCryptoAlgorithm algorithm = webcrypto::CreateHmacKeyGenAlgorithm( | 758 std::vector<blink::WebArrayBuffer> keys; |
696 blink::WebCryptoAlgorithmIdSha1, 128); | 759 for (int i = 0; i < 16; ++i) { |
697 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | 760 blink::WebArrayBuffer key_bytes; |
698 EXPECT_FALSE(key.isNull()); | 761 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
699 EXPECT_TRUE(key.handle()); | 762 blink::WebCryptoAlgorithm algorithm = webcrypto::CreateHmacKeyGenAlgorithm( |
700 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 763 blink::WebCryptoAlgorithmIdSha1, 128); |
764 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | |
765 EXPECT_FALSE(key.isNull()); | |
766 EXPECT_TRUE(key.handle()); | |
767 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
768 } | |
769 // Ensure all entries in the key sample set are unique. This is a simplistic | |
770 // estimate of whether the generated keys appear random. | |
771 EXPECT_FALSE(CopiesExist(keys)); | |
701 } | 772 } |
702 | 773 |
703 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { | 774 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { |
704 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 775 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
705 blink::WebCryptoAlgorithm algorithm = | 776 blink::WebCryptoAlgorithm algorithm = |
706 webcrypto::CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); | 777 webcrypto::CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); |
707 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | 778 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
708 EXPECT_TRUE(key.handle()); | 779 EXPECT_TRUE(key.handle()); |
709 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 780 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
710 } | 781 } |
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1112 true, | 1183 true, |
1113 blink::WebCryptoKeyUsageEncrypt, | 1184 blink::WebCryptoKeyUsageEncrypt, |
1114 &key)); | 1185 &key)); |
1115 | 1186 |
1116 // Passing case: Export a previously imported RSA public key in SPKI format | 1187 // Passing case: Export a previously imported RSA public key in SPKI format |
1117 // and compare to original data. | 1188 // and compare to original data. |
1118 blink::WebArrayBuffer output; | 1189 blink::WebArrayBuffer output; |
1119 ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); | 1190 ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); |
1120 ExpectArrayBufferMatchesHex(hex_rsa_spki_der, output); | 1191 ExpectArrayBufferMatchesHex(hex_rsa_spki_der, output); |
1121 | 1192 |
1193 // Failing case: Try to export a previously imported RSA public key in raw | |
1194 // format (not allowed for a public key). | |
1195 EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &output)); | |
1196 | |
1122 // Failing case: Try to export a non-extractable key | 1197 // Failing case: Try to export a non-extractable key |
1123 ASSERT_TRUE(ImportKeyInternal( | 1198 ASSERT_TRUE(ImportKeyInternal( |
1124 blink::WebCryptoKeyFormatSpki, | 1199 blink::WebCryptoKeyFormatSpki, |
1125 HexStringToBytes(hex_rsa_spki_der), | 1200 HexStringToBytes(hex_rsa_spki_der), |
1126 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), | 1201 webcrypto::CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5), |
1127 false, | 1202 false, |
1128 blink::WebCryptoKeyUsageEncrypt, | 1203 blink::WebCryptoKeyUsageEncrypt, |
1129 &key)); | 1204 &key)); |
1130 EXPECT_TRUE(key.handle()); | 1205 EXPECT_TRUE(key.handle()); |
1131 EXPECT_FALSE(key.extractable()); | 1206 EXPECT_FALSE(key.extractable()); |
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1575 private_key, | 1650 private_key, |
1576 reinterpret_cast<const unsigned char*>(encrypted_data.data()), | 1651 reinterpret_cast<const unsigned char*>(encrypted_data.data()), |
1577 encrypted_data.byteLength(), | 1652 encrypted_data.byteLength(), |
1578 &decrypted_data)); | 1653 &decrypted_data)); |
1579 ExpectArrayBufferMatchesHex(message_hex_str, decrypted_data); | 1654 ExpectArrayBufferMatchesHex(message_hex_str, decrypted_data); |
1580 } | 1655 } |
1581 | 1656 |
1582 #endif // #if !defined(USE_OPENSSL) | 1657 #endif // #if !defined(USE_OPENSSL) |
1583 | 1658 |
1584 } // namespace content | 1659 } // namespace content |
OLD | NEW |