Home | History | Annotate | Download | only in cipher
      1 /* Copyright (c) 2014, Google Inc.
      2  *
      3  * Permission to use, copy, modify, and/or distribute this software for any
      4  * purpose with or without fee is hereby granted, provided that the above
      5  * copyright notice and this permission notice appear in all copies.
      6  *
      7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
     14 
     15 #include <stdint.h>
     16 #include <string.h>
     17 
     18 #include <vector>
     19 
     20 #include <openssl/aead.h>
     21 #include <openssl/crypto.h>
     22 #include <openssl/err.h>
     23 
     24 #include "../test/file_test.h"
     25 #include "../test/scoped_types.h"
     26 
     27 
     28 // This program tests an AEAD against a series of test vectors from a file,
     29 // using the FileTest format. As an example, here's a valid test case:
     30 //
     31 //   KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4
     32 //   NONCE: 978105dfce667bf4
     33 //   IN: 6a4583908d
     34 //   AD: b654574932
     35 //   CT: 5294265a60
     36 //   TAG: 1d45758621762e061368e68868e2f929
     37 
     38 static bool TestAEAD(FileTest *t, void *arg) {
     39   const EVP_AEAD *aead = reinterpret_cast<const EVP_AEAD*>(arg);
     40 
     41   std::vector<uint8_t> key, nonce, in, ad, ct, tag;
     42   if (!t->GetBytes(&key, "KEY") ||
     43       !t->GetBytes(&nonce, "NONCE") ||
     44       !t->GetBytes(&in, "IN") ||
     45       !t->GetBytes(&ad, "AD") ||
     46       !t->GetBytes(&ct, "CT") ||
     47       !t->GetBytes(&tag, "TAG")) {
     48     return false;
     49   }
     50 
     51   ScopedEVP_AEAD_CTX ctx;
     52   if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(),
     53                                         tag.size(), evp_aead_seal)) {
     54     t->PrintLine("Failed to init AEAD.");
     55     return false;
     56   }
     57 
     58   std::vector<uint8_t> out(in.size() + EVP_AEAD_max_overhead(aead));
     59   if (!t->HasAttribute("NO_SEAL")) {
     60     size_t out_len;
     61     if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
     62                            nonce.data(), nonce.size(), in.data(), in.size(),
     63                            ad.data(), ad.size())) {
     64       t->PrintLine("Failed to run AEAD.");
     65       return false;
     66     }
     67     out.resize(out_len);
     68 
     69     if (out.size() != ct.size() + tag.size()) {
     70       t->PrintLine("Bad output length: %u vs %u.", (unsigned)out_len,
     71                    (unsigned)(ct.size() + tag.size()));
     72       return false;
     73     }
     74     if (!t->ExpectBytesEqual(ct.data(), ct.size(), out.data(), ct.size()) ||
     75         !t->ExpectBytesEqual(tag.data(), tag.size(), out.data() + ct.size(),
     76                              tag.size())) {
     77       return false;
     78     }
     79   } else {
     80     out.resize(ct.size() + tag.size());
     81     memcpy(out.data(), ct.data(), ct.size());
     82     memcpy(out.data() + ct.size(), tag.data(), tag.size());
     83   }
     84 
     85   // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
     86   // reset after each operation.
     87   ctx.Reset();
     88   if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(),
     89                                         tag.size(), evp_aead_open)) {
     90     t->PrintLine("Failed to init AEAD.");
     91     return false;
     92   }
     93 
     94   std::vector<uint8_t> out2(out.size());
     95   size_t out2_len;
     96   int ret = EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(),
     97                               nonce.data(), nonce.size(), out.data(),
     98                               out.size(), ad.data(), ad.size());
     99   if (t->HasAttribute("FAILS")) {
    100     if (ret) {
    101       t->PrintLine("Decrypted bad data.");
    102       return false;
    103     }
    104     ERR_clear_error();
    105     return true;
    106   }
    107 
    108   if (!ret) {
    109     t->PrintLine("Failed to decrypt.");
    110     return false;
    111   }
    112   out2.resize(out2_len);
    113   if (!t->ExpectBytesEqual(in.data(), in.size(), out2.data(), out2.size())) {
    114     return false;
    115   }
    116 
    117   // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
    118   // reset after each operation.
    119   ctx.Reset();
    120   if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(),
    121                                         tag.size(), evp_aead_open)) {
    122     t->PrintLine("Failed to init AEAD.");
    123     return false;
    124   }
    125 
    126   // Garbage at the end isn't ignored.
    127   out.push_back(0);
    128   out2.resize(out.size());
    129   if (EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(),
    130                         nonce.data(), nonce.size(), out.data(), out.size(),
    131                         ad.data(), ad.size())) {
    132     t->PrintLine("Decrypted bad data with trailing garbage.");
    133     return false;
    134   }
    135   ERR_clear_error();
    136 
    137   // The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
    138   // reset after each operation.
    139   ctx.Reset();
    140   if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(),
    141                                         tag.size(), evp_aead_open)) {
    142     t->PrintLine("Failed to init AEAD.");
    143     return false;
    144   }
    145 
    146   // Verify integrity is checked.
    147   out[0] ^= 0x80;
    148   out.resize(out.size() - 1);
    149   out2.resize(out.size());
    150   if (EVP_AEAD_CTX_open(ctx.get(), out2.data(), &out2_len, out2.size(),
    151                         nonce.data(), nonce.size(), out.data(), out.size(),
    152                         ad.data(), ad.size())) {
    153     t->PrintLine("Decrypted bad data with corrupted byte.");
    154     return false;
    155   }
    156   ERR_clear_error();
    157 
    158   return true;
    159 }
    160 
    161 static int TestCleanupAfterInitFailure(const EVP_AEAD *aead) {
    162   EVP_AEAD_CTX ctx;
    163   uint8_t key[128];
    164 
    165   memset(key, 0, sizeof(key));
    166   const size_t key_len = EVP_AEAD_key_length(aead);
    167   if (key_len > sizeof(key)) {
    168     fprintf(stderr, "Key length of AEAD too long.\n");
    169     return 0;
    170   }
    171 
    172   if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len,
    173                         9999 /* a silly tag length to trigger an error */,
    174                         NULL /* ENGINE */) != 0) {
    175     fprintf(stderr, "A silly tag length didn't trigger an error!\n");
    176     return 0;
    177   }
    178   ERR_clear_error();
    179 
    180   /* Running a second, failed _init should not cause a memory leak. */
    181   if (EVP_AEAD_CTX_init(&ctx, aead, key, key_len,
    182                         9999 /* a silly tag length to trigger an error */,
    183                         NULL /* ENGINE */) != 0) {
    184     fprintf(stderr, "A silly tag length didn't trigger an error!\n");
    185     return 0;
    186   }
    187   ERR_clear_error();
    188 
    189   /* Calling _cleanup on an |EVP_AEAD_CTX| after a failed _init should be a
    190    * no-op. */
    191   EVP_AEAD_CTX_cleanup(&ctx);
    192   return 1;
    193 }
    194 
    195 struct AEADName {
    196   const char name[40];
    197   const EVP_AEAD *(*func)(void);
    198 };
    199 
    200 static const struct AEADName kAEADs[] = {
    201   { "aes-128-gcm", EVP_aead_aes_128_gcm },
    202   { "aes-256-gcm", EVP_aead_aes_256_gcm },
    203   { "chacha20-poly1305", EVP_aead_chacha20_poly1305 },
    204   { "chacha20-poly1305-old", EVP_aead_chacha20_poly1305_old },
    205   { "rc4-md5-tls", EVP_aead_rc4_md5_tls },
    206   { "rc4-sha1-tls", EVP_aead_rc4_sha1_tls },
    207   { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls },
    208   { "aes-128-cbc-sha1-tls-implicit-iv", EVP_aead_aes_128_cbc_sha1_tls_implicit_iv },
    209   { "aes-128-cbc-sha256-tls", EVP_aead_aes_128_cbc_sha256_tls },
    210   { "aes-256-cbc-sha1-tls", EVP_aead_aes_256_cbc_sha1_tls },
    211   { "aes-256-cbc-sha1-tls-implicit-iv", EVP_aead_aes_256_cbc_sha1_tls_implicit_iv },
    212   { "aes-256-cbc-sha256-tls", EVP_aead_aes_256_cbc_sha256_tls },
    213   { "aes-256-cbc-sha384-tls", EVP_aead_aes_256_cbc_sha384_tls },
    214   { "des-ede3-cbc-sha1-tls", EVP_aead_des_ede3_cbc_sha1_tls },
    215   { "des-ede3-cbc-sha1-tls-implicit-iv", EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv },
    216   { "rc4-md5-ssl3", EVP_aead_rc4_md5_ssl3 },
    217   { "rc4-sha1-ssl3", EVP_aead_rc4_sha1_ssl3 },
    218   { "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3 },
    219   { "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3 },
    220   { "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3 },
    221   { "aes-128-key-wrap", EVP_aead_aes_128_key_wrap },
    222   { "aes-256-key-wrap", EVP_aead_aes_256_key_wrap },
    223   { "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256 },
    224   { "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256 },
    225   { "", NULL },
    226 };
    227 
    228 int main(int argc, char **argv) {
    229   CRYPTO_library_init();
    230 
    231   if (argc != 3) {
    232     fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]);
    233     return 1;
    234   }
    235 
    236   const EVP_AEAD *aead;
    237   for (unsigned i = 0;; i++) {
    238     const struct AEADName &aead_name = kAEADs[i];
    239     if (aead_name.func == NULL) {
    240       fprintf(stderr, "Unknown AEAD: %s\n", argv[1]);
    241       return 2;
    242     }
    243     if (strcmp(aead_name.name, argv[1]) == 0) {
    244       aead = aead_name.func();
    245       break;
    246     }
    247   }
    248 
    249   if (!TestCleanupAfterInitFailure(aead)) {
    250     return 1;
    251   }
    252 
    253   return FileTestMain(TestAEAD, const_cast<EVP_AEAD*>(aead), argv[2]);
    254 }
    255