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 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, |