Chromium Code Reviews| Index: content/renderer/webcrypto/webcrypto_impl_unittest.cc |
| diff --git a/content/renderer/webcrypto/webcrypto_impl_unittest.cc b/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
| index ffe2377a2b6b8ab2b87327c45dbcc31678969466..54b71850b8a896902e8317ce76a23b556ddd95aa 100644 |
| --- a/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
| +++ b/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
| @@ -4,6 +4,7 @@ |
| #include "content/renderer/webcrypto/webcrypto_impl.h" |
| +#include <algorithm> |
| #include <string> |
| #include <vector> |
| @@ -80,8 +81,7 @@ blink::WebCryptoAlgorithm CreateAesCbcAlgorithm( |
| new blink::WebCryptoAesKeyGenParams(key_length_bits)); |
| } |
| -#if !defined(USE_OPENSSL) |
| -blink::WebCryptoAlgorithm CreateRsaAlgorithm( |
| +blink::WebCryptoAlgorithm CreateRsaKeyGenAlgorithm( |
| blink::WebCryptoAlgorithmId algorithm_id, |
| unsigned modulus_length, |
| const std::vector<uint8>& public_exponent) { |
| @@ -93,7 +93,6 @@ blink::WebCryptoAlgorithm CreateRsaAlgorithm( |
| new blink::WebCryptoRsaKeyGenParams( |
| modulus_length, Start(public_exponent), public_exponent.size())); |
| } |
| -#endif // !defined(USE_OPENSSL) |
| } // namespace |
| @@ -697,9 +696,9 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
| const unsigned modulus_length = 256; |
| const std::vector<uint8> public_exponent = HexStringToBytes("010001"); |
| blink::WebCryptoAlgorithm algorithm = |
| - CreateRsaAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| - modulus_length, |
| - public_exponent); |
| + CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| + modulus_length, |
| + public_exponent); |
| bool extractable = false; |
| const blink::WebCryptoKeyUsageMask usage_mask = 0; |
| blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
| @@ -716,7 +715,7 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
| EXPECT_EQ(usage_mask, private_key.usages()); |
| // Fail with bad modulus. |
| - algorithm = CreateRsaAlgorithm( |
| + algorithm = CreateRsaKeyGenAlgorithm( |
| blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, 0, public_exponent); |
| EXPECT_FALSE(GenerateKeyPairInternal( |
| algorithm, extractable, usage_mask, &public_key, &private_key)); |
| @@ -724,25 +723,26 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
| // Fail with bad exponent: larger than unsigned long. |
| unsigned exponent_length = sizeof(unsigned long) + 1; // NOLINT |
| const std::vector<uint8> long_exponent(exponent_length, 0x01); |
| - algorithm = CreateRsaAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| - modulus_length, |
| - long_exponent); |
| + algorithm = CreateRsaKeyGenAlgorithm( |
| + blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, modulus_length, long_exponent); |
| EXPECT_FALSE(GenerateKeyPairInternal( |
| algorithm, extractable, usage_mask, &public_key, &private_key)); |
| // Fail with bad exponent: empty. |
| const std::vector<uint8> empty_exponent; |
| - algorithm = CreateRsaAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| - modulus_length, |
| - empty_exponent); |
| + algorithm = |
| + CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| + modulus_length, |
| + empty_exponent); |
| EXPECT_FALSE(GenerateKeyPairInternal( |
| algorithm, extractable, usage_mask, &public_key, &private_key)); |
| // Fail with bad exponent: all zeros. |
| std::vector<uint8> exponent_with_leading_zeros(15, 0x00); |
| - algorithm = CreateRsaAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| - modulus_length, |
| - exponent_with_leading_zeros); |
| + algorithm = |
| + CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| + modulus_length, |
| + exponent_with_leading_zeros); |
| EXPECT_FALSE(GenerateKeyPairInternal( |
| algorithm, extractable, usage_mask, &public_key, &private_key)); |
| @@ -750,9 +750,10 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
| exponent_with_leading_zeros.insert(exponent_with_leading_zeros.end(), |
| public_exponent.begin(), |
| public_exponent.end()); |
| - algorithm = CreateRsaAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| - modulus_length, |
| - exponent_with_leading_zeros); |
| + algorithm = |
| + CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| + modulus_length, |
| + exponent_with_leading_zeros); |
| EXPECT_TRUE(GenerateKeyPairInternal( |
| algorithm, extractable, usage_mask, &public_key, &private_key)); |
| EXPECT_FALSE(public_key.isNull()); |
| @@ -765,7 +766,7 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
| EXPECT_EQ(usage_mask, private_key.usages()); |
| // Successful WebCryptoAlgorithmIdRsaOaep key generation. |
| - algorithm = CreateRsaAlgorithm( |
| + algorithm = CreateRsaKeyGenAlgorithm( |
| blink::WebCryptoAlgorithmIdRsaOaep, modulus_length, public_exponent); |
| EXPECT_TRUE(GenerateKeyPairInternal( |
| algorithm, extractable, usage_mask, &public_key, &private_key)); |
| @@ -779,9 +780,10 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
| EXPECT_EQ(usage_mask, private_key.usages()); |
| // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation. |
| - algorithm = CreateRsaAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| - modulus_length, |
| - public_exponent); |
| + algorithm = |
| + CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| + modulus_length, |
| + public_exponent); |
| EXPECT_TRUE(GenerateKeyPairInternal( |
| algorithm, extractable, usage_mask, &public_key, &private_key)); |
| EXPECT_FALSE(public_key.isNull()); |
| @@ -794,6 +796,137 @@ TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
| EXPECT_EQ(usage_mask, private_key.usages()); |
| } |
| +// TODO(padolph): It is not clear whether we can check RSAES encryption against |
| +// NIST vectors, because the random data in PKCS1.5 padding makes the encryption |
|
eroman
2013/11/21 02:07:01
@rsleevi: Any ideas?
Ryan Sleevi
2013/11/21 02:17:02
Yeah, there's no good way here. The NSS unittests
padolph
2013/11/27 20:13:08
Done.
|
| +// output non-deterministic unless we can force-seed NSS's PRNG. |
| + |
| +TEST_F(WebCryptoImplTest, RsaEsRoundTrip) { |
| + // Note: using unrealistic short key length here to avoid bogging down tests. |
| + |
| + // Create a key pair. |
| + const unsigned kModulusLength = 256; |
| + blink::WebCryptoAlgorithm algorithm = |
| + CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| + kModulusLength, |
| + HexStringToBytes("010001")); |
| + const blink::WebCryptoKeyUsageMask usage_mask = |
| + blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt; |
| + blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
| + blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); |
| + EXPECT_TRUE(GenerateKeyPairInternal( |
| + algorithm, false, usage_mask, &public_key, &private_key)); |
| + EXPECT_FALSE(public_key.isNull()); |
| + EXPECT_FALSE(private_key.isNull()); |
| + |
| + // Make a maximum-length data message. RSAES can operate on messages up to |
| + // length of k - 11 bytes, where k is the octet length of the RSA modulus. |
| + const unsigned kMaxMsgSizeBytes = kModulusLength / 8 - 11; |
| + // There are two hex chars for each byte. |
| + const unsigned kMsgHexSize = kMaxMsgSizeBytes * 2; |
| + char max_data_hex[kMsgHexSize]; |
| + std::fill(&max_data_hex[0], &max_data_hex[0] + kMsgHexSize, 'a'); |
| + max_data_hex[kMsgHexSize] = '\0'; |
| + |
| + // Verify encrypt / decrypt round trip on a few messages. Note that RSA |
| + // encryption does not support empty input. |
| + algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); |
| + const char* const kTestDataHex[] = { |
| + "ff", |
| + "0102030405060708090a0b0c0d0e0f", |
| + max_data_hex |
| + }; |
| + blink::WebArrayBuffer encrypted_data; |
| + blink::WebArrayBuffer decrypted_data; |
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestDataHex); ++i) { |
| + SCOPED_TRACE(i); |
| + ASSERT_TRUE(EncryptInternal( |
| + algorithm, |
| + public_key, |
| + HexStringToBytes(kTestDataHex[i]), |
| + &encrypted_data)); |
| + EXPECT_EQ(kModulusLength/8, encrypted_data.byteLength()); |
| + ASSERT_TRUE(DecryptInternal( |
| + algorithm, |
| + private_key, |
| + reinterpret_cast<const unsigned char*>(encrypted_data.data()), |
| + encrypted_data.byteLength(), |
| + &decrypted_data)); |
| + ExpectArrayBufferMatchesHex(kTestDataHex[i], decrypted_data); |
| + } |
| +} |
| + |
| +TEST_F(WebCryptoImplTest, RsaEsFailures) { |
| + // Note: using unrealistic short key length here to avoid bogging down tests. |
| + |
| + // Create a key pair. |
| + const unsigned kModulusLength = 256; |
| + blink::WebCryptoAlgorithm algorithm = |
| + CreateRsaKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
| + kModulusLength, |
| + HexStringToBytes("010001")); |
| + const blink::WebCryptoKeyUsageMask usage_mask = |
| + blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt; |
| + blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
| + blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); |
| + EXPECT_TRUE(GenerateKeyPairInternal( |
| + algorithm, false, usage_mask, &public_key, &private_key)); |
| + EXPECT_FALSE(public_key.isNull()); |
| + EXPECT_FALSE(private_key.isNull()); |
| + |
| + // Fail encrypt with a private key. |
| + algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); |
| + blink::WebArrayBuffer encrypted_data; |
| + const std::string message_hex_str("0102030405060708090a0b0c0d0e0f"); |
| + const std::vector<uint8> message_hex(HexStringToBytes(message_hex_str)); |
| + EXPECT_FALSE( |
| + EncryptInternal(algorithm, private_key, message_hex, &encrypted_data)); |
| + |
| + // Fail encrypt with empty message. |
| + EXPECT_FALSE(EncryptInternal( |
| + algorithm, public_key, std::vector<uint8>(), &encrypted_data)); |
| + |
| + // Fail encrypt with message too large. RSAES can operate on messages up to |
| + // length of k - 11 bytes, where k is the octet length of the RSA modulus. |
| + const unsigned kMaxMsgSizeBytes = kModulusLength / 8 - 11; |
| + EXPECT_FALSE(EncryptInternal(algorithm, |
| + public_key, |
| + std::vector<uint8>(kMaxMsgSizeBytes + 1, '0'), |
| + &encrypted_data)); |
| + |
| + // Generate encrypted data. |
| + EXPECT_TRUE( |
| + EncryptInternal(algorithm, public_key, message_hex, &encrypted_data)); |
| + |
| + // Fail decrypt with a public key. |
| + blink::WebArrayBuffer decrypted_data; |
| + EXPECT_FALSE(DecryptInternal( |
| + algorithm, |
| + public_key, |
| + reinterpret_cast<const unsigned char*>(encrypted_data.data()), |
| + encrypted_data.byteLength(), |
| + &decrypted_data)); |
| + |
| + // Corrupt encrypted data; ensure decrypt fails because padding was disrupted. |
| + std::vector<uint8> corrupted_data( |
| + static_cast<uint8*>(encrypted_data.data()), |
| + static_cast<uint8*>(encrypted_data.data()) + encrypted_data.byteLength()); |
| + corrupted_data[corrupted_data.size() / 2] ^= 0x01; |
| + EXPECT_FALSE( |
| + DecryptInternal(algorithm, private_key, corrupted_data, &decrypted_data)); |
| + |
| + // TODO(padolph): Are there other specific data corruption scenarios to |
| + // consider? |
| + |
| + // Do a successful decrypt with good data just for confirmation. |
| + EXPECT_TRUE(DecryptInternal( |
| + algorithm, |
| + private_key, |
| + reinterpret_cast<const unsigned char*>(encrypted_data.data()), |
| + encrypted_data.byteLength(), |
| + &decrypted_data)); |
| + ExpectArrayBufferMatchesHex(message_hex_str, decrypted_data); |
| +} |
| + |
| #endif // #if !defined(USE_OPENSSL) |
| } // namespace content |