#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"
constexpr uint32_t kLimitedImplementation = …;
constexpr uint32_t kCanTruncateTags = …;
constexpr uint32_t kVariableNonce = …;
constexpr uint32_t kNondeterministic = …;
constexpr uint32_t RequiresADLength(size_t length) { … }
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(…);
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)
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);
}
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;
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
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) { … }