1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/stl_util.h" 6#include "content/child/webcrypto/algorithm_dispatch.h" 7#include "content/child/webcrypto/crypto_data.h" 8#include "content/child/webcrypto/status.h" 9#include "content/child/webcrypto/test/test_helpers.h" 10#include "content/child/webcrypto/webcrypto_util.h" 11#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" 12#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" 13 14namespace content { 15 16namespace webcrypto { 17 18namespace { 19 20bool SupportsAesCtr() { 21#if defined(USE_OPENSSL) 22 return true; 23#else 24 return false; 25#endif 26} 27 28// Creates an AES-CTR algorithm for encryption/decryption. 29blink::WebCryptoAlgorithm CreateAesCtrAlgorithm( 30 const std::vector<uint8_t>& counter, 31 uint8_t length_bits) { 32 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( 33 blink::WebCryptoAlgorithmIdAesCtr, 34 new blink::WebCryptoAesCtrParams( 35 length_bits, vector_as_array(&counter), counter.size())); 36} 37 38TEST(WebCryptoAesCtrTest, EncryptDecryptKnownAnswer) { 39 if (!SupportsAesCtr()) { 40 LOG(WARNING) << "Skipping test because AES-CTR is not supported"; 41 return; 42 } 43 44 scoped_ptr<base::ListValue> tests; 45 ASSERT_TRUE(ReadJsonTestFileToList("aes_ctr.json", &tests)); 46 47 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) { 48 SCOPED_TRACE(test_index); 49 base::DictionaryValue* test; 50 ASSERT_TRUE(tests->GetDictionary(test_index, &test)); 51 52 std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key"); 53 std::vector<uint8_t> test_counter = GetBytesFromHexString(test, "counter"); 54 int counter_length_bits = 0; 55 ASSERT_TRUE(test->GetInteger("length", &counter_length_bits)); 56 57 std::vector<uint8_t> test_plain_text = 58 GetBytesFromHexString(test, "plain_text"); 59 std::vector<uint8_t> test_cipher_text = 60 GetBytesFromHexString(test, "cipher_text"); 61 62 blink::WebCryptoKey key = ImportSecretKeyFromRaw( 63 test_key, 64 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), 65 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); 66 67 EXPECT_EQ(test_key.size() * 8, key.algorithm().aesParams()->lengthBits()); 68 69 std::vector<uint8_t> output; 70 71 // Test encryption. 72 EXPECT_EQ(Status::Success(), 73 Encrypt(CreateAesCtrAlgorithm(test_counter, counter_length_bits), 74 key, 75 CryptoData(test_plain_text), 76 &output)); 77 EXPECT_BYTES_EQ(test_cipher_text, output); 78 79 // Test decryption. 80 EXPECT_EQ(Status::Success(), 81 Decrypt(CreateAesCtrAlgorithm(test_counter, counter_length_bits), 82 key, 83 CryptoData(test_cipher_text), 84 &output)); 85 EXPECT_BYTES_EQ(test_plain_text, output); 86 } 87} 88 89// The counter block must be exactly 16 bytes. 90TEST(WebCryptoAesCtrTest, InvalidCounterBlockLength) { 91 if (!SupportsAesCtr()) { 92 LOG(WARNING) << "Skipping test because AES-CTR is not supported"; 93 return; 94 } 95 96 const unsigned int kBadCounterBlockLengthBytes[] = {0, 15, 17}; 97 98 blink::WebCryptoKey key = ImportSecretKeyFromRaw( 99 std::vector<uint8>(16), // 128-bit key of all zeros. 100 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), 101 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); 102 103 std::vector<uint8_t> input(32); 104 std::vector<uint8_t> output; 105 106 for (size_t i = 0; i < arraysize(kBadCounterBlockLengthBytes); ++i) { 107 std::vector<uint8_t> bad_counter(kBadCounterBlockLengthBytes[i]); 108 109 EXPECT_EQ(Status::ErrorIncorrectSizeAesCtrCounter(), 110 Encrypt(CreateAesCtrAlgorithm(bad_counter, 128), 111 key, 112 CryptoData(input), 113 &output)); 114 115 EXPECT_EQ(Status::ErrorIncorrectSizeAesCtrCounter(), 116 Decrypt(CreateAesCtrAlgorithm(bad_counter, 128), 117 key, 118 CryptoData(input), 119 &output)); 120 } 121} 122 123// The counter length cannot be less than 1 or greater than 128. 124TEST(WebCryptoAesCtrTest, InvalidCounterLength) { 125 if (!SupportsAesCtr()) { 126 LOG(WARNING) << "Skipping test because AES-CTR is not supported"; 127 return; 128 } 129 130 const uint8_t kBadCounterLengthBits[] = {0, 129}; 131 132 blink::WebCryptoKey key = ImportSecretKeyFromRaw( 133 std::vector<uint8>(16), // 128-bit key of all zeros. 134 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), 135 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); 136 137 std::vector<uint8_t> counter(16); 138 std::vector<uint8_t> input(32); 139 std::vector<uint8_t> output; 140 141 for (size_t i = 0; i < arraysize(kBadCounterLengthBits); ++i) { 142 uint8_t bad_counter_length_bits = kBadCounterLengthBits[i]; 143 144 EXPECT_EQ(Status::ErrorInvalidAesCtrCounterLength(), 145 Encrypt(CreateAesCtrAlgorithm(counter, bad_counter_length_bits), 146 key, 147 CryptoData(input), 148 &output)); 149 150 EXPECT_EQ(Status::ErrorInvalidAesCtrCounterLength(), 151 Decrypt(CreateAesCtrAlgorithm(counter, bad_counter_length_bits), 152 key, 153 CryptoData(input), 154 &output)); 155 } 156} 157 158// Tests wrap-around using a 4-bit counter. 159// 160// Wrap-around is allowed, however if the counter repeats itself an error should 161// be thrown. 162// 163// Using a 4-bit counter it is possible to encrypt 16 blocks. However the 17th 164// block would end up wrapping back to the starting value. 165TEST(WebCryptoAesCtrTest, OverflowAndRepeatCounter) { 166 if (!SupportsAesCtr()) { 167 LOG(WARNING) << "Skipping test because AES-CTR is not supported"; 168 return; 169 } 170 171 const uint8_t kCounterLengthBits = 4; 172 const uint8_t kStartCounter[] = {0, 1, 15}; 173 174 blink::WebCryptoKey key = ImportSecretKeyFromRaw( 175 std::vector<uint8>(16), // 128-bit key of all zeros. 176 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCtr), 177 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); 178 179 std::vector<uint8_t> buffer(272); 180 181 // 16 and 17 AES blocks worth of data respectively (AES blocks are 16 bytes 182 // long). 183 CryptoData input_16(vector_as_array(&buffer), 256); 184 CryptoData input_17(vector_as_array(&buffer), 272); 185 186 std::vector<uint8_t> output; 187 188 for (size_t i = 0; i < arraysize(kStartCounter); ++i) { 189 std::vector<uint8_t> counter(16); 190 counter[15] = kStartCounter[i]; 191 192 // Baseline test: Encrypting 16 blocks should work (don't bother to check 193 // output, the known answer tests already do that). 194 EXPECT_EQ(Status::Success(), 195 Encrypt(CreateAesCtrAlgorithm(counter, kCounterLengthBits), 196 key, 197 input_16, 198 &output)); 199 200 // Encrypting/Decrypting 17 however should fail. 201 EXPECT_EQ(Status::ErrorAesCtrInputTooLongCounterRepeated(), 202 Encrypt(CreateAesCtrAlgorithm(counter, kCounterLengthBits), 203 key, 204 input_17, 205 &output)); 206 EXPECT_EQ(Status::ErrorAesCtrInputTooLongCounterRepeated(), 207 Decrypt(CreateAesCtrAlgorithm(counter, kCounterLengthBits), 208 key, 209 input_17, 210 &output)); 211 } 212} 213 214} // namespace 215 216} // namespace webcrypto 217 218} // namespace content 219