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..e1522e8d205d51b0a3f7c7df9c4e7591b5218dd3 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 |
+// 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)); |
+ |
+ // Do a passing encrypt to generate data for decrypt. |
eroman
2013/11/21 00:18:26
Not sure what a "passing encrypt" means
padolph
2013/11/21 01:56:11
Done.
|
+ 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? |
+ |
+ // Pass 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 |