Index: content/child/webcrypto/shared_crypto_unittest.cc |
diff --git a/content/child/webcrypto/shared_crypto_unittest.cc b/content/child/webcrypto/shared_crypto_unittest.cc |
index a117f2266b6e0dbc4b6968759153c69ecb3a0e2f..5eb62d793a2eb524af36512b44a43860a0a3c71c 100644 |
--- a/content/child/webcrypto/shared_crypto_unittest.cc |
+++ b/content/child/webcrypto/shared_crypto_unittest.cc |
@@ -122,6 +122,14 @@ bool SupportsRsaOaep() { |
#endif |
} |
+bool SupportsAesCtr() { |
+#if defined(USE_OPENSSL) |
+ return true; |
+#else |
+ return false; |
+#endif |
+} |
+ |
bool SupportsRsaKeyImport() { |
// TODO(eroman): Exclude version test for OS_CHROMEOS |
#if defined(USE_NSS) |
@@ -169,6 +177,16 @@ blink::WebCryptoAlgorithm CreateAesCbcAlgorithm( |
new blink::WebCryptoAesCbcParams(vector_as_array(&iv), iv.size())); |
} |
+// Creates an AES-CTR algorithm for encryption/decryption. |
+blink::WebCryptoAlgorithm CreateAesCtrAlgorithm( |
+ const std::vector<uint8_t>& counter, |
+ uint8_t length_bits) { |
+ return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
+ blink::WebCryptoAlgorithmIdAesCtr, |
+ new blink::WebCryptoAesCtrParams( |
+ length_bits, vector_as_array(&counter), counter.size())); |
+} |
+ |
// Creates an AES-GCM algorithm. |
blink::WebCryptoAlgorithm CreateAesGcmAlgorithm( |
const std::vector<uint8_t>& iv, |
@@ -4860,6 +4878,182 @@ TEST(WebCryptoAesCbcTest, WrapUnwrapRoundtripSpkiPkcs8) { |
EXPECT_NE(private_key_pkcs8, wrapped_private_key); |
} |
+TEST(WebCryptoAesCtrTest, EncryptDecryptKnownAnswer) { |
+ if (!SupportsAesCtr()) { |
+ LOG(WARNING) << "Skipping test because AES-CTR is not supported"; |
+ return; |
+ } |
+ |
+ scoped_ptr<base::ListValue> tests; |
+ ASSERT_TRUE(ReadJsonTestFileToList("aes_ctr.json", &tests)); |
+ |
+ for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) { |
+ SCOPED_TRACE(test_index); |
+ base::DictionaryValue* test; |
+ ASSERT_TRUE(tests->GetDictionary(test_index, &test)); |
+ |
+ std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key"); |
+ std::vector<uint8_t> test_counter = GetBytesFromHexString(test, "counter"); |
+ int counter_length_bits = 0; |
+ ASSERT_TRUE(test->GetInteger("length", &counter_length_bits)); |
+ |
+ std::vector<uint8_t> test_plain_text = |
+ GetBytesFromHexString(test, "plain_text"); |
+ std::vector<uint8_t> test_cipher_text = |
+ GetBytesFromHexString(test, "cipher_text"); |
+ |
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw( |
+ test_key, |
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), |
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
+ |
+ EXPECT_EQ(test_key.size() * 8, key.algorithm().aesParams()->lengthBits()); |
+ |
+ std::vector<uint8_t> output; |
+ |
+ // Test encryption. |
+ EXPECT_EQ(Status::Success(), |
+ Encrypt(CreateAesCtrAlgorithm(test_counter, counter_length_bits), |
+ key, |
+ CryptoData(test_plain_text), |
+ &output)); |
+ EXPECT_BYTES_EQ(test_cipher_text, output); |
+ |
+ // Test decryption. |
+ EXPECT_EQ(Status::Success(), |
+ Decrypt(CreateAesCtrAlgorithm(test_counter, counter_length_bits), |
+ key, |
+ CryptoData(test_cipher_text), |
+ &output)); |
+ EXPECT_BYTES_EQ(test_plain_text, output); |
+ } |
+} |
+ |
+// The counter block must be exactly 16 bytes. |
+TEST(WebCryptoAesCtrTest, InvalidCounterBlockLength) { |
+ if (!SupportsAesCtr()) { |
+ LOG(WARNING) << "Skipping test because AES-CTR is not supported"; |
+ return; |
+ } |
+ |
+ const unsigned int kBadCounterBlockLengthBytes[] = {0, 15, 17}; |
+ |
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw( |
+ std::vector<uint8>(16), // 128-bit key of all zeros. |
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), |
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
+ |
+ std::vector<uint8_t> input(32); |
+ std::vector<uint8_t> output; |
+ |
+ for (size_t i = 0; i < arraysize(kBadCounterBlockLengthBytes); ++i) { |
+ std::vector<uint8_t> bad_counter(kBadCounterBlockLengthBytes[i]); |
+ |
+ EXPECT_EQ(Status::ErrorIncorrectSizeAesCtrCounter(), |
+ Encrypt(CreateAesCtrAlgorithm(bad_counter, 128), |
+ key, |
+ CryptoData(input), |
+ &output)); |
+ |
+ EXPECT_EQ(Status::ErrorIncorrectSizeAesCtrCounter(), |
+ Decrypt(CreateAesCtrAlgorithm(bad_counter, 128), |
+ key, |
+ CryptoData(input), |
+ &output)); |
+ } |
+} |
+ |
+// The counter length cannot be less than 1 or greater than 128. |
+TEST(WebCryptoAesCtrTest, InvalidCounterLength) { |
+ if (!SupportsAesCtr()) { |
+ LOG(WARNING) << "Skipping test because AES-CTR is not supported"; |
+ return; |
+ } |
+ |
+ const uint8_t kBadCounterLengthBits[] = {0, 129}; |
+ |
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw( |
+ std::vector<uint8>(16), // 128-bit key of all zeros. |
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), |
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
+ |
+ std::vector<uint8_t> counter(16); |
+ std::vector<uint8_t> input(32); |
+ std::vector<uint8_t> output; |
+ |
+ for (size_t i = 0; i < arraysize(kBadCounterLengthBits); ++i) { |
+ uint8_t bad_counter_length_bits = kBadCounterLengthBits[i]; |
+ |
+ EXPECT_EQ(Status::ErrorInvalidAesCtrCounterLength(), |
+ Encrypt(CreateAesCtrAlgorithm(counter, bad_counter_length_bits), |
+ key, |
+ CryptoData(input), |
+ &output)); |
+ |
+ EXPECT_EQ(Status::ErrorInvalidAesCtrCounterLength(), |
+ Decrypt(CreateAesCtrAlgorithm(counter, bad_counter_length_bits), |
+ key, |
+ CryptoData(input), |
+ &output)); |
+ } |
+} |
+ |
+// Tests wrap-around using a 4-bit counter. |
+// |
+// Wrap-around is allowed, however if the counter repeats itself an error should |
+// be thrown. |
+// |
+// Using a 4-bit counter it is possible to encrypt 16 blocks. However the 17th |
+// block would end up wrapping back to the starting value. |
+TEST(WebCryptoAesCtrTest, OverflowAndRepeatCounter) { |
+ if (!SupportsAesCtr()) { |
+ LOG(WARNING) << "Skipping test because AES-CTR is not supported"; |
+ return; |
+ } |
+ |
+ const uint8_t kCounterLengthBits = 4; |
+ const uint8_t kStartCounter[] = {0, 1, 15}; |
+ |
+ blink::WebCryptoKey key = ImportSecretKeyFromRaw( |
+ std::vector<uint8>(16), // 128-bit key of all zeros. |
+ CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), |
+ blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
+ |
+ std::vector<uint8_t> buffer(272); |
+ |
+ // 16 and 17 AES blocks worth of data respectively (AES blocks are 16 bytes |
+ // long). |
+ CryptoData input_16(vector_as_array(&buffer), 256); |
+ CryptoData input_17(vector_as_array(&buffer), 272); |
+ |
+ std::vector<uint8_t> output; |
+ |
+ for (size_t i = 0; i < arraysize(kStartCounter); ++i) { |
+ std::vector<uint8_t> counter(16); |
+ counter[15] = kStartCounter[i]; |
+ |
+ // Baseline test: Encrypting 16 blocks should work (don't bother to check |
+ // output, the known answer tests already do that). |
+ EXPECT_EQ(Status::Success(), |
+ Encrypt(CreateAesCtrAlgorithm(counter, kCounterLengthBits), |
+ key, |
+ input_16, |
+ &output)); |
+ |
+ // Encrypting/Decrypting 17 however should fail. |
+ EXPECT_EQ(Status::ErrorAesCtrInputTooLongCounterRepeated(), |
+ Encrypt(CreateAesCtrAlgorithm(counter, kCounterLengthBits), |
+ key, |
+ input_17, |
+ &output)); |
+ EXPECT_EQ(Status::ErrorAesCtrInputTooLongCounterRepeated(), |
+ Decrypt(CreateAesCtrAlgorithm(counter, kCounterLengthBits), |
+ key, |
+ input_17, |
+ &output)); |
+ } |
+} |
+ |
} // namespace |
} // namespace webcrypto |