chromium/third_party/boringssl/src/crypto/cipher_extra/aead_test.cc

/* Copyright (c) 2014, Google Inc.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */

#include <assert.h>
#include <stdint.h>
#include <string.h>

#include <vector>

#include <gtest/gtest.h>

#include <openssl/aead.h>
#include <openssl/cipher.h>
#include <openssl/err.h>

#include "../fipsmodule/cipher/internal.h"
#include "internal.h"
#include "../internal.h"
#include "../test/abi_test.h"
#include "../test/file_test.h"
#include "../test/test_util.h"
#include "../test/wycheproof_util.h"

// kLimitedImplementation indicates that tests that assume a generic AEAD
// interface should not be performed. For example, the key-wrap AEADs only
// handle inputs that are a multiple of eight bytes in length and the TLS CBC
// AEADs have the concept of “direction”.
constexpr uint32_t kLimitedImplementation =;
// kCanTruncateTags indicates that the AEAD supports truncatating tags to
// arbitrary lengths.
constexpr uint32_t kCanTruncateTags =;
// kVariableNonce indicates that the AEAD supports a variable-length nonce.
constexpr uint32_t kVariableNonce =;
// kNondeterministic indicates that the AEAD performs randomised encryption thus
// one cannot assume that encrypting the same data will result in the same
// ciphertext.
constexpr uint32_t kNondeterministic =;

// RequiresADLength encodes an AD length requirement into flags.
constexpr uint32_t RequiresADLength(size_t length) {}

// RequiredADLength returns the AD length requirement encoded in |flags|, or
// zero if there isn't one.
constexpr size_t RequiredADLength(uint32_t flags) {}

constexpr uint32_t RequiresMinimumTagLength(size_t length) {}

constexpr size_t MinimumTagLength(uint32_t flags) {}

struct KnownAEAD {};

static const struct KnownAEAD kAEADs[] =;

class PerAEADTest : public testing::TestWithParam<KnownAEAD> {};

INSTANTIATE_TEST_SUITE_P();

// Tests an AEAD against a series of test vectors from a file, using the
// FileTest format. As an example, here's a valid test case:
//
//   KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4
//   NONCE: 978105dfce667bf4
//   IN: 6a4583908d
//   AD: b654574932
//   CT: 5294265a60
//   TAG: 1d45758621762e061368e68868e2f929
TEST_P(PerAEADTest, TestVector) {}

TEST_P(PerAEADTest, TestExtraInput) {}

TEST_P(PerAEADTest, TestVectorScatterGather) {}

TEST_P(PerAEADTest, CleanupAfterInitFailure) {}

TEST_P(PerAEADTest, TruncatedTags) {}

TEST_P(PerAEADTest, AliasedBuffers) {}

TEST_P(PerAEADTest, UnalignedInput) {}

TEST_P(PerAEADTest, Overflow) {}

TEST_P(PerAEADTest, InvalidNonceLength) {}

#if defined(SUPPORTS_ABI_TEST)
// CHECK_ABI can't pass enums, i.e. |evp_aead_seal| and |evp_aead_open|. Thus
// these two wrappers.
static int aead_ctx_init_for_seal(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
                                  const uint8_t *key, size_t key_len) {
  return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, 0,
                                          evp_aead_seal);
}

static int aead_ctx_init_for_open(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
                                  const uint8_t *key, size_t key_len) {
  return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, 0,
                                          evp_aead_open);
}

// CHECK_ABI can pass, at most, eight arguments. Thus these wrappers that
// figure out the output length from the input length, and take the nonce length
// from the configuration of the AEAD.
static int aead_ctx_seal(EVP_AEAD_CTX *ctx, uint8_t *out_ciphertext,
                         size_t *out_ciphertext_len, const uint8_t *nonce,
                         const uint8_t *plaintext, size_t plaintext_len,
                         const uint8_t *ad, size_t ad_len) {
  const size_t nonce_len = EVP_AEAD_nonce_length(EVP_AEAD_CTX_aead(ctx));
  return EVP_AEAD_CTX_seal(ctx, out_ciphertext, out_ciphertext_len,
                           plaintext_len + EVP_AEAD_MAX_OVERHEAD, nonce,
                           nonce_len, plaintext, plaintext_len, ad, ad_len);
}

static int aead_ctx_open(EVP_AEAD_CTX *ctx, uint8_t *out_plaintext,
                         size_t *out_plaintext_len, const uint8_t *nonce,
                         const uint8_t *ciphertext, size_t ciphertext_len,
                         const uint8_t *ad, size_t ad_len) {
  const size_t nonce_len = EVP_AEAD_nonce_length(EVP_AEAD_CTX_aead(ctx));
  return EVP_AEAD_CTX_open(ctx, out_plaintext, out_plaintext_len,
                           ciphertext_len, nonce, nonce_len, ciphertext,
                           ciphertext_len, ad, ad_len);
}

TEST_P(PerAEADTest, ABI) {
  uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
  OPENSSL_memset(key, 'K', sizeof(key));
  const size_t key_len = EVP_AEAD_key_length(aead());
  ASSERT_LE(key_len, sizeof(key));

  bssl::ScopedEVP_AEAD_CTX ctx_seal;
  ASSERT_TRUE(
      CHECK_ABI(aead_ctx_init_for_seal, ctx_seal.get(), aead(), key, key_len));

  bssl::ScopedEVP_AEAD_CTX ctx_open;
  ASSERT_TRUE(
      CHECK_ABI(aead_ctx_init_for_open, ctx_open.get(), aead(), key, key_len));

  alignas(2) uint8_t plaintext[512];
  OPENSSL_memset(plaintext, 'P', sizeof(plaintext));

  alignas(2) uint8_t ad_buf[512];
  OPENSSL_memset(ad_buf, 'A', sizeof(ad_buf));
  const uint8_t *const ad = ad_buf + 1;
  ASSERT_LE(RequiredADLength(GetParam().flags), sizeof(ad_buf) - 1);
  const size_t ad_len = RequiredADLength(GetParam().flags) != 0
                            ? RequiredADLength(GetParam().flags)
                            : sizeof(ad_buf) - 1;

  uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
  OPENSSL_memset(nonce, 'N', sizeof(nonce));
  const size_t nonce_len = EVP_AEAD_nonce_length(aead());
  ASSERT_LE(nonce_len, sizeof(nonce));

  alignas(2) uint8_t ciphertext[sizeof(plaintext) + EVP_AEAD_MAX_OVERHEAD + 1];
  size_t ciphertext_len;
  // Knock plaintext, ciphertext, and AD off alignment and give odd lengths for
  // plaintext and AD. This hopefully triggers any edge-cases in the assembly.
  ASSERT_TRUE(CHECK_ABI(aead_ctx_seal, ctx_seal.get(), ciphertext + 1,
                        &ciphertext_len, nonce, plaintext + 1,
                        sizeof(plaintext) - 1, ad, ad_len));

  alignas(2) uint8_t plaintext2[sizeof(ciphertext) + 1];
  size_t plaintext2_len;
  ASSERT_TRUE(CHECK_ABI(aead_ctx_open, ctx_open.get(), plaintext2 + 1,
                        &plaintext2_len, nonce, ciphertext + 1, ciphertext_len,
                        ad, ad_len));

  EXPECT_EQ(Bytes(plaintext + 1, sizeof(plaintext) - 1),
            Bytes(plaintext2 + 1, plaintext2_len));
}

TEST(ChaChaPoly1305Test, ABI) {
  if (!chacha20_poly1305_asm_capable()) {
    return;
  }

  auto buf = std::make_unique<uint8_t[]>(1024);
  for (size_t len = 0; len <= 1024; len += 5) {
    SCOPED_TRACE(len);
    union chacha20_poly1305_open_data open_ctx = {};
    CHECK_ABI(chacha20_poly1305_open, buf.get(), buf.get(), len, buf.get(),
              len % 128, &open_ctx);
  }

  for (size_t len = 0; len <= 1024; len += 5) {
    SCOPED_TRACE(len);
    union chacha20_poly1305_seal_data seal_ctx = {};
    CHECK_ABI(chacha20_poly1305_seal, buf.get(), buf.get(), len, buf.get(),
              len % 128, &seal_ctx);
  }
}
#endif  // SUPPORTS_ABI_TEST

TEST(AEADTest, AESCCMLargeAD) {}

static void RunWycheproofTestCase(FileTest *t, const EVP_AEAD *aead) {}

TEST(AEADTest, WycheproofAESGCMSIV) {}

TEST(AEADTest, WycheproofAESGCM) {}

TEST(AEADTest, WycheproofChaCha20Poly1305) {}

TEST(AEADTest, WycheproofXChaCha20Poly1305) {}

TEST(AEADTest, FreeNull) {}