Home | History | Annotate | Download | only in test
      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 
     14 namespace content {
     15 
     16 namespace webcrypto {
     17 
     18 namespace {
     19 
     20 bool 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.
     29 blink::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 
     38 TEST(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.
     90 TEST(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.
    124 TEST(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.
    165 TEST(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