Chromium Code Reviews| 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 |