// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "base/macros.h" #include "base/values.h" #include "components/webcrypto/algorithm_dispatch.h" #include "components/webcrypto/algorithms/test_helpers.h" #include "components/webcrypto/crypto_data.h" #include "components/webcrypto/status.h" #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" namespace webcrypto { namespace { // Creates an AES-CTR algorithm for encryption/decryption. blink::WebCryptoAlgorithm CreateAesCtrAlgorithm( const std::vector& counter, uint8_t length_bits) { return blink::WebCryptoAlgorithm::adoptParamsAndCreate( blink::WebCryptoAlgorithmIdAesCtr, new blink::WebCryptoAesCtrParams( length_bits, counter.data(), static_cast(counter.size()))); } class WebCryptoAesCtrTest : public WebCryptoTestBase {}; TEST_F(WebCryptoAesCtrTest, EncryptDecryptKnownAnswer) { scoped_ptr 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 test_key = GetBytesFromHexString(test, "key"); std::vector test_counter = GetBytesFromHexString(test, "counter"); int counter_length_bits = 0; ASSERT_TRUE(test->GetInteger("length", &counter_length_bits)); std::vector test_plain_text = GetBytesFromHexString(test, "plain_text"); std::vector 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 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_F(WebCryptoAesCtrTest, InvalidCounterBlockLength) { const unsigned int kBadCounterBlockLengthBytes[] = {0, 15, 17}; blink::WebCryptoKey key = ImportSecretKeyFromRaw( std::vector(16), // 128-bit key of all zeros. CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); std::vector input(32); std::vector output; for (size_t i = 0; i < arraysize(kBadCounterBlockLengthBytes); ++i) { std::vector 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_F(WebCryptoAesCtrTest, InvalidCounterLength) { const uint8_t kBadCounterLengthBits[] = {0, 129}; blink::WebCryptoKey key = ImportSecretKeyFromRaw( std::vector(16), // 128-bit key of all zeros. CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); std::vector counter(16); std::vector input(32); std::vector 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_F(WebCryptoAesCtrTest, OverflowAndRepeatCounter) { const uint8_t kCounterLengthBits = 4; const uint8_t kStartCounter[] = {0, 1, 15}; blink::WebCryptoKey key = ImportSecretKeyFromRaw( std::vector(16), // 128-bit key of all zeros. CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); std::vector buffer(272); // 16 and 17 AES blocks worth of data respectively (AES blocks are 16 bytes // long). CryptoData input_16(buffer.data(), 256); CryptoData input_17(buffer.data(), 272); std::vector output; for (size_t i = 0; i < arraysize(kStartCounter); ++i) { std::vector 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