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 f9ff0d67f232b6d36e1fa38689175c289d2fa9f5..350fc84f2fb835e8f38a573c0ffcdd5d71777817 100644 |
--- a/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
+++ b/content/renderer/webcrypto/webcrypto_impl_unittest.cc |
@@ -98,6 +98,34 @@ blink::WebCryptoAlgorithm CreateRsaKeyGenAlgorithm( |
#endif // #if !defined(USE_OPENSSL) |
+// MIT HAKMEM Bit Count for 8-bit Unsigned Char |
+int BitCount8(unsigned char b) { |
+ b = (b & 0x55u) + ((b >> 1) & 0x55u); |
+ b = (b & 0x33u) + ((b >> 2) & 0x33u); |
+ b = (b & 0x0fu) + ((b >> 4) & 0x0fu); |
+ return (b); |
+} |
+ |
+// Use a binary entropy calculation to check whether the input data appears |
+// random. See http://en.wikipedia.org/wiki/Binary_entropy. |
+void ExpectDataAppearsRandom(const blink::WebArrayBuffer& key_bytes) { |
+ DCHECK(key_bytes.data()); |
+ DCHECK(key_bytes.byteLength()); |
+ int n_set_bits = 0; |
+ unsigned char* data_ptr = static_cast<unsigned char*>(key_bytes.data()); |
+ unsigned char* const data_ptr_end = data_ptr + key_bytes.byteLength(); |
+ while (data_ptr < data_ptr_end) { |
+ n_set_bits += BitCount8(*data_ptr++); |
+ } |
+ // Binary entropy is calculated as -p * log2(p) - (1 - p) * log2(1 - p), where |
+ // p is the percentage of set bits in the input data. This function has a |
+ // maximum of 1.0 at p = 0.5. Arbitrarily say the input data is random if the |
+ // 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
|
+ double p = static_cast<double>(n_set_bits) / (key_bytes.byteLength() * 8); |
+ EXPECT_GT(p, 0.2145); |
+ EXPECT_LT(p, 0.7855); |
+} |
+ |
} // namespace |
namespace content { |
@@ -421,6 +449,11 @@ TEST_F(WebCryptoImplTest, HMACSampleSets) { |
blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
test.key, algorithm, blink::WebCryptoKeyUsageSign); |
+ // Verify exported raw key is identical to the imported data |
+ blink::WebArrayBuffer raw_key; |
+ EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); |
+ ExpectArrayBufferMatchesHex(test.key, raw_key); |
+ |
std::vector<uint8> message_raw = HexStringToBytes(test.message); |
blink::WebArrayBuffer output; |
@@ -463,11 +496,17 @@ TEST_F(WebCryptoImplTest, HMACSampleSets) { |
} |
TEST_F(WebCryptoImplTest, AesCbcFailures) { |
+ const std::string key_hex = "2b7e151628aed2a6abf7158809cf4f3c"; |
blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
- "2b7e151628aed2a6abf7158809cf4f3c", |
+ key_hex, |
CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
+ // Verify exported raw key is identical to the imported data |
+ blink::WebArrayBuffer raw_key; |
+ EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); |
+ ExpectArrayBufferMatchesHex(key_hex, raw_key); |
+ |
blink::WebArrayBuffer output; |
// Use an invalid |iv| (fewer than 16 bytes) |
@@ -521,9 +560,10 @@ TEST_F(WebCryptoImplTest, AesCbcFailures) { |
&key)); |
} |
- // Fail exporting the key in SPKI format (SPKI export not allowed for secret |
- // keys) |
+ // Fail exporting the key in SPKI and PKCS#8 formats (not allowed for secret |
+ // keys). |
EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); |
+ EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatPkcs8, key, &output)); |
} |
TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
@@ -613,6 +653,11 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
+ // Verify exported raw key is identical to the imported data |
+ blink::WebArrayBuffer raw_key; |
+ EXPECT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &raw_key)); |
+ ExpectArrayBufferMatchesHex(test.key, raw_key); |
+ |
std::vector<uint8> plain_text = HexStringToBytes(test.plain_text); |
std::vector<uint8> iv = HexStringToBytes(test.iv); |
@@ -657,13 +702,14 @@ TEST_F(WebCryptoImplTest, AesCbcSampleSets) { |
} |
} |
-// TODO(padolph): Add test to verify generated symmetric keys appear random. |
- |
TEST_F(WebCryptoImplTest, GenerateKeyAes) { |
blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcAlgorithm(128), &key)); |
EXPECT_TRUE(key.handle()); |
EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
+ blink::WebArrayBuffer key_bytes; |
+ ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &key_bytes)); |
+ ExpectDataAppearsRandom(key_bytes); |
} |
TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { |
@@ -680,6 +726,9 @@ TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
EXPECT_FALSE(key.isNull()); |
EXPECT_TRUE(key.handle()); |
EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
+ blink::WebArrayBuffer key_bytes; |
+ ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &key_bytes)); |
+ ExpectDataAppearsRandom(key_bytes); |
} |
TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { |
@@ -780,6 +829,10 @@ TEST_F(WebCryptoImplTest, ImportExportSpki) { |
ASSERT_TRUE(ExportKeyInternal(blink::WebCryptoKeyFormatSpki, key, &output)); |
ExpectArrayBufferMatchesHex(hex_rsa_spki_der, output); |
+ // Failing case: Try to export a previously imported RSA public key in raw |
+ // format (not allowed for a public key). |
+ EXPECT_FALSE(ExportKeyInternal(blink::WebCryptoKeyFormatRaw, key, &output)); |
+ |
// Failing case: Try to export a non-extractable key |
ASSERT_TRUE(ImportKeyInternal( |
blink::WebCryptoKeyFormatSpki, |