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 "testing/gtest/include/gtest/gtest.h"
     12 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
     13 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
     14 
     15 namespace content {
     16 
     17 namespace webcrypto {
     18 
     19 namespace {
     20 
     21 // Creates an AES-GCM algorithm.
     22 blink::WebCryptoAlgorithm CreateAesGcmAlgorithm(
     23     const std::vector<uint8_t>& iv,
     24     const std::vector<uint8_t>& additional_data,
     25     unsigned int tag_length_bits) {
     26   EXPECT_TRUE(SupportsAesGcm());
     27   return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
     28       blink::WebCryptoAlgorithmIdAesGcm,
     29       new blink::WebCryptoAesGcmParams(vector_as_array(&iv),
     30                                        iv.size(),
     31                                        true,
     32                                        vector_as_array(&additional_data),
     33                                        additional_data.size(),
     34                                        true,
     35                                        tag_length_bits));
     36 }
     37 
     38 blink::WebCryptoAlgorithm CreateAesGcmKeyGenAlgorithm(
     39     unsigned short key_length_bits) {
     40   EXPECT_TRUE(SupportsAesGcm());
     41   return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesGcm,
     42                                   key_length_bits);
     43 }
     44 
     45 Status AesGcmEncrypt(const blink::WebCryptoKey& key,
     46                      const std::vector<uint8_t>& iv,
     47                      const std::vector<uint8_t>& additional_data,
     48                      unsigned int tag_length_bits,
     49                      const std::vector<uint8_t>& plain_text,
     50                      std::vector<uint8_t>* cipher_text,
     51                      std::vector<uint8_t>* authentication_tag) {
     52   EXPECT_TRUE(SupportsAesGcm());
     53   blink::WebCryptoAlgorithm algorithm =
     54       CreateAesGcmAlgorithm(iv, additional_data, tag_length_bits);
     55 
     56   std::vector<uint8_t> output;
     57   Status status = Encrypt(algorithm, key, CryptoData(plain_text), &output);
     58   if (status.IsError())
     59     return status;
     60 
     61   if ((tag_length_bits % 8) != 0) {
     62     EXPECT_TRUE(false) << "Encrypt should have failed.";
     63     return Status::OperationError();
     64   }
     65 
     66   size_t tag_length_bytes = tag_length_bits / 8;
     67 
     68   if (tag_length_bytes > output.size()) {
     69     EXPECT_TRUE(false) << "tag length is larger than output";
     70     return Status::OperationError();
     71   }
     72 
     73   // The encryption result is cipher text with authentication tag appended.
     74   cipher_text->assign(output.begin(),
     75                       output.begin() + (output.size() - tag_length_bytes));
     76   authentication_tag->assign(output.begin() + cipher_text->size(),
     77                              output.end());
     78 
     79   return Status::Success();
     80 }
     81 
     82 Status AesGcmDecrypt(const blink::WebCryptoKey& key,
     83                      const std::vector<uint8_t>& iv,
     84                      const std::vector<uint8_t>& additional_data,
     85                      unsigned int tag_length_bits,
     86                      const std::vector<uint8_t>& cipher_text,
     87                      const std::vector<uint8_t>& authentication_tag,
     88                      std::vector<uint8_t>* plain_text) {
     89   EXPECT_TRUE(SupportsAesGcm());
     90   blink::WebCryptoAlgorithm algorithm =
     91       CreateAesGcmAlgorithm(iv, additional_data, tag_length_bits);
     92 
     93   // Join cipher text and authentication tag.
     94   std::vector<uint8_t> cipher_text_with_tag;
     95   cipher_text_with_tag.reserve(cipher_text.size() + authentication_tag.size());
     96   cipher_text_with_tag.insert(
     97       cipher_text_with_tag.end(), cipher_text.begin(), cipher_text.end());
     98   cipher_text_with_tag.insert(cipher_text_with_tag.end(),
     99                               authentication_tag.begin(),
    100                               authentication_tag.end());
    101 
    102   return Decrypt(algorithm, key, CryptoData(cipher_text_with_tag), plain_text);
    103 }
    104 
    105 TEST(WebCryptoAesGcmTest, GenerateKeyBadLength) {
    106   if (!SupportsAesGcm()) {
    107     LOG(WARNING) << "AES GCM not supported, skipping tests";
    108     return;
    109   }
    110 
    111   const unsigned short kKeyLen[] = {0, 127, 257};
    112   blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
    113   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kKeyLen); ++i) {
    114     SCOPED_TRACE(i);
    115     EXPECT_EQ(Status::ErrorGenerateKeyLength(),
    116               GenerateSecretKey(
    117                   CreateAesGcmKeyGenAlgorithm(kKeyLen[i]), true, 0, &key));
    118   }
    119 }
    120 
    121 TEST(WebCryptoAesGcmTest, ImportExportJwk) {
    122   // Some Linux test runners may not have a new enough version of NSS.
    123   if (!SupportsAesGcm()) {
    124     LOG(WARNING) << "AES GCM not supported, skipping tests";
    125     return;
    126   }
    127 
    128   const blink::WebCryptoAlgorithm algorithm =
    129       CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm);
    130 
    131   // AES-GCM 128
    132   ImportExportJwkSymmetricKey(
    133       128,
    134       algorithm,
    135       blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
    136       "A128GCM");
    137 
    138   // AES-GCM 256
    139   ImportExportJwkSymmetricKey(
    140       256, algorithm, blink::WebCryptoKeyUsageDecrypt, "A256GCM");
    141 }
    142 
    143 // TODO(eroman):
    144 //   * Test decryption when the tag length exceeds input size
    145 //   * Test decryption with empty input
    146 //   * Test decryption with tag length of 0.
    147 TEST(WebCryptoAesGcmTest, SampleSets) {
    148   // Some Linux test runners may not have a new enough version of NSS.
    149   if (!SupportsAesGcm()) {
    150     LOG(WARNING) << "AES GCM not supported, skipping tests";
    151     return;
    152   }
    153 
    154   scoped_ptr<base::ListValue> tests;
    155   ASSERT_TRUE(ReadJsonTestFileToList("aes_gcm.json", &tests));
    156 
    157   // Note that WebCrypto appends the authentication tag to the ciphertext.
    158   for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
    159     SCOPED_TRACE(test_index);
    160     base::DictionaryValue* test;
    161     ASSERT_TRUE(tests->GetDictionary(test_index, &test));
    162 
    163     const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
    164     const std::vector<uint8_t> test_iv = GetBytesFromHexString(test, "iv");
    165     const std::vector<uint8_t> test_additional_data =
    166         GetBytesFromHexString(test, "additional_data");
    167     const std::vector<uint8_t> test_plain_text =
    168         GetBytesFromHexString(test, "plain_text");
    169     const std::vector<uint8_t> test_authentication_tag =
    170         GetBytesFromHexString(test, "authentication_tag");
    171     const unsigned int test_tag_size_bits = test_authentication_tag.size() * 8;
    172     const std::vector<uint8_t> test_cipher_text =
    173         GetBytesFromHexString(test, "cipher_text");
    174 
    175     blink::WebCryptoKey key = ImportSecretKeyFromRaw(
    176         test_key,
    177         CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
    178         blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
    179 
    180     // Verify exported raw key is identical to the imported data
    181     std::vector<uint8_t> raw_key;
    182     EXPECT_EQ(Status::Success(),
    183               ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
    184 
    185     EXPECT_BYTES_EQ(test_key, raw_key);
    186 
    187     // Test encryption.
    188     std::vector<uint8_t> cipher_text;
    189     std::vector<uint8_t> authentication_tag;
    190     EXPECT_EQ(Status::Success(),
    191               AesGcmEncrypt(key,
    192                             test_iv,
    193                             test_additional_data,
    194                             test_tag_size_bits,
    195                             test_plain_text,
    196                             &cipher_text,
    197                             &authentication_tag));
    198 
    199     EXPECT_BYTES_EQ(test_cipher_text, cipher_text);
    200     EXPECT_BYTES_EQ(test_authentication_tag, authentication_tag);
    201 
    202     // Test decryption.
    203     std::vector<uint8_t> plain_text;
    204     EXPECT_EQ(Status::Success(),
    205               AesGcmDecrypt(key,
    206                             test_iv,
    207                             test_additional_data,
    208                             test_tag_size_bits,
    209                             test_cipher_text,
    210                             test_authentication_tag,
    211                             &plain_text));
    212     EXPECT_BYTES_EQ(test_plain_text, plain_text);
    213 
    214     // Decryption should fail if any of the inputs are tampered with.
    215     EXPECT_EQ(Status::OperationError(),
    216               AesGcmDecrypt(key,
    217                             Corrupted(test_iv),
    218                             test_additional_data,
    219                             test_tag_size_bits,
    220                             test_cipher_text,
    221                             test_authentication_tag,
    222                             &plain_text));
    223     EXPECT_EQ(Status::OperationError(),
    224               AesGcmDecrypt(key,
    225                             test_iv,
    226                             Corrupted(test_additional_data),
    227                             test_tag_size_bits,
    228                             test_cipher_text,
    229                             test_authentication_tag,
    230                             &plain_text));
    231     EXPECT_EQ(Status::OperationError(),
    232               AesGcmDecrypt(key,
    233                             test_iv,
    234                             test_additional_data,
    235                             test_tag_size_bits,
    236                             Corrupted(test_cipher_text),
    237                             test_authentication_tag,
    238                             &plain_text));
    239     EXPECT_EQ(Status::OperationError(),
    240               AesGcmDecrypt(key,
    241                             test_iv,
    242                             test_additional_data,
    243                             test_tag_size_bits,
    244                             test_cipher_text,
    245                             Corrupted(test_authentication_tag),
    246                             &plain_text));
    247 
    248     // Try different incorrect tag lengths
    249     uint8_t kAlternateTagLengths[] = {0, 8, 96, 120, 128, 160, 255};
    250     for (size_t tag_i = 0; tag_i < arraysize(kAlternateTagLengths); ++tag_i) {
    251       unsigned int wrong_tag_size_bits = kAlternateTagLengths[tag_i];
    252       if (test_tag_size_bits == wrong_tag_size_bits)
    253         continue;
    254       EXPECT_NE(Status::Success(),
    255                 AesGcmDecrypt(key,
    256                               test_iv,
    257                               test_additional_data,
    258                               wrong_tag_size_bits,
    259                               test_cipher_text,
    260                               test_authentication_tag,
    261                               &plain_text));
    262     }
    263   }
    264 }
    265 
    266 }  // namespace
    267 
    268 }  // namespace webcrypto
    269 
    270 }  // namespace content
    271