[ALTS] Create GsecKeyInterface and related classes in ALTS (#34814)

As such, `alts_zero_copy_grpc_protector_create` will take a
`GsecKeyFactoryInterface` to create `GsecKeyInterface` objects for the
underlying crypter to use.

This enables the caller to control how all the key related buffers are
prepared and protected.

`gsec_aes_gcm_aead_crypter` holds the raw pointer to `GsecKeyInterface`
instead of a `unique_ptr` possibly because somewhere in the test (and
maybe production code as well), the structure is getting copied. A SEGV
error would be caused with `unique_ptr` which doesn't support copy
operations.
pull/34862/head
Luwei Ge 1 year ago committed by GitHub
parent 609e96446a
commit 2fdcba26dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      BUILD
  2. 246
      src/core/tsi/alts/crypt/aes_gcm.cc
  3. 706
      src/core/tsi/alts/crypt/gsec.h
  4. 18
      src/core/tsi/alts/frame_protector/alts_frame_protector.cc
  5. 10
      src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc
  6. 24
      src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc
  7. 51
      src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h
  8. 5
      test/core/tsi/alts/crypt/BUILD
  9. 106
      test/core/tsi/alts/crypt/aes_gcm_test.cc
  10. 5
      test/core/tsi/alts/frame_protector/BUILD
  11. 65
      test/core/tsi/alts/frame_protector/alts_crypter_test.cc
  12. 15
      test/core/tsi/alts/zero_copy_frame_protector/BUILD
  13. 54
      test/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_test.cc
  14. 41
      test/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol_test.cc
  15. 16
      test/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector_test.cc

@ -3487,6 +3487,7 @@ grpc_cc_library(
"//src/core:tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h",
],
external_deps = [
"absl/types:span",
"libcrypto",
"libssl",
],

@ -20,12 +20,16 @@
#include <string.h>
#include <memory>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include "absl/types/span.h"
#include <grpc/support/alloc.h>
#include "src/core/tsi/alts/crypt/gsec.h"
@ -35,26 +39,111 @@ constexpr size_t kKdfCounterLen = 6;
constexpr size_t kKdfCounterOffset = 2;
constexpr size_t kRekeyAeadKeyLen = kAes128GcmKeyLength;
namespace grpc_core {
GsecKeyFactory::GsecKeyFactory(absl::Span<const uint8_t> key, bool is_rekey)
: key_(key.begin(), key.end()), is_rekey_(is_rekey) {}
std::unique_ptr<GsecKeyInterface> GsecKeyFactory::Create() const {
return std::make_unique<GsecKey>(key_, is_rekey_);
}
GsecKey::GsecKey(absl::Span<const uint8_t> key, bool is_rekey)
: is_rekey_(is_rekey) {
if (is_rekey_) {
aead_key_.resize(kRekeyAeadKeyLen);
kdf_buffer_.resize(EVP_MAX_MD_SIZE);
nonce_mask_.resize(kAesGcmNonceLength);
memcpy(nonce_mask_.data(), key.data() + kKdfKeyLen, kAesGcmNonceLength);
kdf_counter_.resize(kKdfCounterLen, 0);
}
key_.resize(is_rekey_ ? kKdfKeyLen : key.size());
memcpy(key_.data(), key.data(), key_.size());
}
bool GsecKey::IsRekey() { return is_rekey_; }
absl::Span<const uint8_t> GsecKey::key() { return key_; }
absl::Span<const uint8_t> GsecKey::nonce_mask() { return nonce_mask_; }
absl::Span<uint8_t> GsecKey::kdf_counter() {
return absl::MakeSpan(kdf_counter_);
}
absl::Span<uint8_t> GsecKey::aead_key() { return absl::MakeSpan(aead_key_); }
absl::Span<uint8_t> GsecKey::kdf_buffer() {
return absl::MakeSpan(kdf_buffer_);
}
} // namespace grpc_core
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
const char kEvpMacAlgorithm[] = "HMAC";
char kEvpDigest[] = "SHA-256";
#endif
/* Struct for additional data required if rekeying is enabled. */
struct gsec_aes_gcm_aead_rekey_data {
uint8_t kdf_counter[kKdfCounterLen];
uint8_t nonce_mask[kAesGcmNonceLength];
};
static grpc_status_code aes_gcm_derive_aead_key(
absl::Span<uint8_t> dst, uint8_t* buf, absl::Span<const uint8_t> kdf_key,
absl::Span<const uint8_t> kdf_counter) {
unsigned char ctr = 1;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
HMAC_CTX hmac;
HMAC_CTX_init(&hmac);
if (!HMAC_Init_ex(&hmac, kdf_key.data(), kdf_key.size(), EVP_sha256(),
nullptr) ||
!HMAC_Update(&hmac, kdf_counter.data(), kdf_counter.size()) ||
!HMAC_Update(&hmac, &ctr, 1) || !HMAC_Final(&hmac, buf, nullptr)) {
HMAC_CTX_cleanup(&hmac);
return GRPC_STATUS_INTERNAL;
}
HMAC_CTX_cleanup(&hmac);
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
HMAC_CTX* hmac = HMAC_CTX_new();
if (hmac == nullptr) {
return GRPC_STATUS_INTERNAL;
}
if (!HMAC_Init_ex(hmac, kdf_key.data(), kdf_key.size(), EVP_sha256(),
nullptr) ||
!HMAC_Update(hmac, kdf_counter.data(), kdf_counter.size()) ||
!HMAC_Update(hmac, &ctr, 1) || !HMAC_Final(hmac, buf, nullptr)) {
HMAC_CTX_free(hmac);
return GRPC_STATUS_INTERNAL;
}
HMAC_CTX_free(hmac);
#else
EVP_MAC* mac = EVP_MAC_fetch(nullptr, kEvpMacAlgorithm, nullptr);
EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac);
if (ctx == nullptr) {
return GRPC_STATUS_INTERNAL;
}
OSSL_PARAM params[2];
params[0] = OSSL_PARAM_construct_utf8_string("digest", kEvpDigest, 0);
params[1] = OSSL_PARAM_construct_end();
if (!EVP_MAC_init(ctx, kdf_key.data(), kdf_key.size(), params) ||
!EVP_MAC_update(ctx, kdf_counter.data(), kdf_counter.size()) ||
!EVP_MAC_update(ctx, &ctr, 1) ||
!EVP_MAC_final(ctx, buf, nullptr, EVP_MAX_MD_SIZE)) {
EVP_MAC_CTX_free(ctx);
EVP_MAC_free(mac);
return GRPC_STATUS_INTERNAL;
}
EVP_MAC_CTX_free(ctx);
EVP_MAC_free(mac);
#endif
memcpy(dst.data(), buf, dst.size());
return GRPC_STATUS_OK;
}
// Main struct for AES_GCM crypter interface.
struct gsec_aes_gcm_aead_crypter {
gsec_aead_crypter crypter;
size_t key_length;
size_t nonce_length;
size_t tag_length;
uint8_t* key;
gsec_aes_gcm_aead_rekey_data* rekey_data;
EVP_CIPHER_CTX* ctx;
grpc_core::GsecKeyInterface* gsec_key;
};
static char* aes_gcm_get_openssl_errors() {
@ -152,7 +241,7 @@ static grpc_status_code gsec_aes_gcm_aead_crypter_key_length(
gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
reinterpret_cast<gsec_aes_gcm_aead_crypter*>(
const_cast<gsec_aead_crypter*>(crypter));
*key_length = aes_gcm_crypter->key_length;
*key_length = aes_gcm_crypter->gsec_key->key().size();
return GRPC_STATUS_OK;
}
@ -186,58 +275,6 @@ static void aes_gcm_mask_nonce(uint8_t* dst, const uint8_t* nonce,
memcpy(dst + sizeof(nonce1), &nonce2, sizeof(nonce2));
}
static grpc_status_code aes_gcm_derive_aead_key(uint8_t* dst,
const uint8_t* kdf_key,
const uint8_t* kdf_counter) {
unsigned char buf[EVP_MAX_MD_SIZE];
unsigned char ctr = 1;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
HMAC_CTX hmac;
HMAC_CTX_init(&hmac);
if (!HMAC_Init_ex(&hmac, kdf_key, kKdfKeyLen, EVP_sha256(), nullptr) ||
!HMAC_Update(&hmac, kdf_counter, kKdfCounterLen) ||
!HMAC_Update(&hmac, &ctr, 1) || !HMAC_Final(&hmac, buf, nullptr)) {
HMAC_CTX_cleanup(&hmac);
return GRPC_STATUS_INTERNAL;
}
HMAC_CTX_cleanup(&hmac);
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
HMAC_CTX* hmac = HMAC_CTX_new();
if (hmac == nullptr) {
return GRPC_STATUS_INTERNAL;
}
if (!HMAC_Init_ex(hmac, kdf_key, kKdfKeyLen, EVP_sha256(), nullptr) ||
!HMAC_Update(hmac, kdf_counter, kKdfCounterLen) ||
!HMAC_Update(hmac, &ctr, 1) || !HMAC_Final(hmac, buf, nullptr)) {
HMAC_CTX_free(hmac);
return GRPC_STATUS_INTERNAL;
}
HMAC_CTX_free(hmac);
#else
EVP_MAC* mac = EVP_MAC_fetch(nullptr, kEvpMacAlgorithm, nullptr);
EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac);
if (ctx == nullptr) {
return GRPC_STATUS_INTERNAL;
}
OSSL_PARAM params[2];
params[0] = OSSL_PARAM_construct_utf8_string("digest", kEvpDigest, 0);
params[1] = OSSL_PARAM_construct_end();
if (!EVP_MAC_init(ctx, kdf_key, kKdfKeyLen, params) ||
!EVP_MAC_update(ctx, kdf_counter, kKdfCounterLen) ||
!EVP_MAC_update(ctx, &ctr, 1) ||
!EVP_MAC_final(ctx, buf, nullptr, EVP_MAX_MD_SIZE)) {
EVP_MAC_CTX_free(ctx);
EVP_MAC_free(mac);
return GRPC_STATUS_INTERNAL;
}
EVP_MAC_CTX_free(ctx);
EVP_MAC_free(mac);
#endif
memcpy(dst, buf, kRekeyAeadKeyLen);
return GRPC_STATUS_OK;
}
static grpc_status_code aes_gcm_rekey_if_required(
gsec_aes_gcm_aead_crypter* aes_gcm_crypter, const uint8_t* nonce,
char** error_details) {
@ -245,21 +282,25 @@ static grpc_status_code aes_gcm_rekey_if_required(
// If bytes 2-7 of kdf_counter differ from the (per message) nonce, then the
// encryption key is recomputed from a new kdf_counter to ensure that we don't
// encrypt more than 2^16 messages per encryption key (in each direction).
if (aes_gcm_crypter->rekey_data == nullptr ||
memcmp(aes_gcm_crypter->rekey_data->kdf_counter,
nonce + kKdfCounterOffset, kKdfCounterLen) == 0) {
if (!aes_gcm_crypter->gsec_key->IsRekey() ||
memcmp(aes_gcm_crypter->gsec_key->kdf_counter().data(),
nonce + kKdfCounterOffset,
aes_gcm_crypter->gsec_key->kdf_counter().size()) == 0) {
return GRPC_STATUS_OK;
}
memcpy(aes_gcm_crypter->rekey_data->kdf_counter, nonce + kKdfCounterOffset,
kKdfCounterLen);
uint8_t aead_key[kRekeyAeadKeyLen];
if (aes_gcm_derive_aead_key(aead_key, aes_gcm_crypter->key,
aes_gcm_crypter->rekey_data->kdf_counter) !=
memcpy(aes_gcm_crypter->gsec_key->kdf_counter().data(),
nonce + kKdfCounterOffset,
aes_gcm_crypter->gsec_key->kdf_counter().size());
if (aes_gcm_derive_aead_key(aes_gcm_crypter->gsec_key->aead_key(),
aes_gcm_crypter->gsec_key->kdf_buffer().data(),
aes_gcm_crypter->gsec_key->key(),
aes_gcm_crypter->gsec_key->kdf_counter()) !=
GRPC_STATUS_OK) {
aes_gcm_format_errors("Rekeying failed in key derivation.", error_details);
return GRPC_STATUS_INTERNAL;
}
if (!EVP_DecryptInit_ex(aes_gcm_crypter->ctx, nullptr, nullptr, aead_key,
if (!EVP_DecryptInit_ex(aes_gcm_crypter->ctx, nullptr, nullptr,
aes_gcm_crypter->gsec_key->aead_key().data(),
nullptr)) {
aes_gcm_format_errors("Rekeying failed in context update.", error_details);
return GRPC_STATUS_INTERNAL;
@ -308,9 +349,9 @@ static grpc_status_code gsec_aes_gcm_aead_crypter_encrypt_iovec(
// mask nonce if required
const uint8_t* nonce_aead = nonce;
uint8_t nonce_masked[kAesGcmNonceLength];
if (aes_gcm_crypter->rekey_data != nullptr) {
aes_gcm_mask_nonce(nonce_masked, aes_gcm_crypter->rekey_data->nonce_mask,
nonce);
if (aes_gcm_crypter->gsec_key->IsRekey()) {
aes_gcm_mask_nonce(nonce_masked,
aes_gcm_crypter->gsec_key->nonce_mask().data(), nonce);
nonce_aead = nonce_masked;
}
// init openssl context
@ -459,9 +500,9 @@ static grpc_status_code gsec_aes_gcm_aead_crypter_decrypt_iovec(
// mask nonce if required
const uint8_t* nonce_aead = nonce;
uint8_t nonce_masked[kAesGcmNonceLength];
if (aes_gcm_crypter->rekey_data != nullptr) {
aes_gcm_mask_nonce(nonce_masked, aes_gcm_crypter->rekey_data->nonce_mask,
nonce);
if (aes_gcm_crypter->gsec_key->IsRekey()) {
aes_gcm_mask_nonce(nonce_masked,
aes_gcm_crypter->gsec_key->nonce_mask().data(), nonce);
nonce_aead = nonce_masked;
}
// init openssl context
@ -603,9 +644,8 @@ static void gsec_aes_gcm_aead_crypter_destroy(gsec_aead_crypter* crypter) {
gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
reinterpret_cast<gsec_aes_gcm_aead_crypter*>(
const_cast<gsec_aead_crypter*>(crypter));
gpr_free(aes_gcm_crypter->key);
gpr_free(aes_gcm_crypter->rekey_data);
EVP_CIPHER_CTX_free(aes_gcm_crypter->ctx);
delete aes_gcm_crypter->gsec_key;
}
static const gsec_aead_crypter_vtable vtable = {
@ -621,25 +661,30 @@ static const gsec_aead_crypter_vtable vtable = {
static grpc_status_code aes_gcm_new_evp_cipher_ctx(
gsec_aes_gcm_aead_crypter* aes_gcm_crypter, char** error_details) {
const EVP_CIPHER* cipher = nullptr;
bool is_rekey = aes_gcm_crypter->rekey_data != nullptr;
switch (is_rekey ? kRekeyAeadKeyLen : aes_gcm_crypter->key_length) {
bool is_rekey = aes_gcm_crypter->gsec_key->IsRekey();
switch (is_rekey ? kRekeyAeadKeyLen
: aes_gcm_crypter->gsec_key->key().size()) {
case kAes128GcmKeyLength:
cipher = EVP_aes_128_gcm();
break;
case kAes256GcmKeyLength:
cipher = EVP_aes_256_gcm();
break;
default:
aes_gcm_format_errors("Invalid key length.", error_details);
return GRPC_STATUS_INTERNAL;
}
const uint8_t* aead_key = aes_gcm_crypter->key;
uint8_t aead_key_rekey[kRekeyAeadKeyLen];
const uint8_t* aead_key = aes_gcm_crypter->gsec_key->key().data();
if (is_rekey) {
if (aes_gcm_derive_aead_key(aead_key_rekey, aes_gcm_crypter->key,
aes_gcm_crypter->rekey_data->kdf_counter) !=
if (aes_gcm_derive_aead_key(aes_gcm_crypter->gsec_key->aead_key(),
aes_gcm_crypter->gsec_key->kdf_buffer().data(),
aes_gcm_crypter->gsec_key->key(),
aes_gcm_crypter->gsec_key->kdf_counter()) !=
GRPC_STATUS_OK) {
aes_gcm_format_errors("Deriving key failed.", error_details);
return GRPC_STATUS_INTERNAL;
}
aead_key = aead_key_rekey;
aead_key = aes_gcm_crypter->gsec_key->aead_key().data();
}
if (!EVP_DecryptInit_ex(aes_gcm_crypter->ctx, cipher, nullptr, aead_key,
nullptr)) {
@ -655,12 +700,9 @@ static grpc_status_code aes_gcm_new_evp_cipher_ctx(
return GRPC_STATUS_OK;
}
grpc_status_code gsec_aes_gcm_aead_crypter_create(const uint8_t* key,
size_t key_length,
size_t nonce_length,
size_t tag_length, bool rekey,
gsec_aead_crypter** crypter,
char** error_details) {
grpc_status_code gsec_aes_gcm_aead_crypter_create(
std::unique_ptr<grpc_core::GsecKeyInterface> key, size_t nonce_length,
size_t tag_length, gsec_aead_crypter** crypter, char** error_details) {
if (key == nullptr) {
aes_gcm_format_errors("key is nullptr.", error_details);
return GRPC_STATUS_FAILED_PRECONDITION;
@ -670,9 +712,9 @@ grpc_status_code gsec_aes_gcm_aead_crypter_create(const uint8_t* key,
return GRPC_STATUS_FAILED_PRECONDITION;
}
*crypter = nullptr;
if ((rekey && key_length != kAes128GcmRekeyKeyLength) ||
(!rekey && key_length != kAes128GcmKeyLength &&
key_length != kAes256GcmKeyLength) ||
if ((key->IsRekey() && key->key().size() != kKdfKeyLen) ||
(!key->IsRekey() && key->key().size() != kAes128GcmKeyLength &&
key->key().size() != kAes256GcmKeyLength) ||
(tag_length != kAesGcmTagLength) ||
(nonce_length != kAesGcmNonceLength)) {
aes_gcm_format_errors(
@ -687,21 +729,7 @@ grpc_status_code gsec_aes_gcm_aead_crypter_create(const uint8_t* key,
aes_gcm_crypter->crypter.vtable = &vtable;
aes_gcm_crypter->nonce_length = nonce_length;
aes_gcm_crypter->tag_length = tag_length;
if (rekey) {
aes_gcm_crypter->key_length = kKdfKeyLen;
aes_gcm_crypter->rekey_data = static_cast<gsec_aes_gcm_aead_rekey_data*>(
gpr_malloc(sizeof(gsec_aes_gcm_aead_rekey_data)));
memcpy(aes_gcm_crypter->rekey_data->nonce_mask, key + kKdfKeyLen,
kAesGcmNonceLength);
// Set kdf_counter to all-zero for initial key derivation.
memset(aes_gcm_crypter->rekey_data->kdf_counter, 0, kKdfCounterLen);
} else {
aes_gcm_crypter->key_length = key_length;
aes_gcm_crypter->rekey_data = nullptr;
}
aes_gcm_crypter->key =
static_cast<uint8_t*>(gpr_malloc(aes_gcm_crypter->key_length));
memcpy(aes_gcm_crypter->key, key, aes_gcm_crypter->key_length);
aes_gcm_crypter->gsec_key = key.release();
aes_gcm_crypter->ctx = EVP_CIPHER_CTX_new();
grpc_status_code status =
aes_gcm_new_evp_cipher_ctx(aes_gcm_crypter, error_details);

@ -25,9 +25,81 @@
#include <stdint.h>
#include <stdlib.h>
#include <memory>
#include <vector>
#include "absl/types/span.h"
#include <grpc/event_engine/port.h>
#include <grpc/grpc.h>
namespace grpc_core {
// Provides accessors to all information representing a gsec key. Owns all the
// read-only or mutable buffers via the accessors. Mutable accessors such as
// `aead_key()` or `kdf_buffer()` are NOT thread-safe.
class GsecKeyInterface {
public:
virtual ~GsecKeyInterface() = default;
virtual bool IsRekey() = 0;
virtual absl::Span<const uint8_t> key() = 0;
// All the accessors below should only be called when IsRekey() is true.
virtual absl::Span<uint8_t> aead_key() = 0;
virtual absl::Span<const uint8_t> nonce_mask() = 0;
virtual absl::Span<uint8_t> kdf_counter() = 0;
virtual absl::Span<uint8_t> kdf_buffer() = 0;
};
// Interface for a GsecKey factory.
class GsecKeyFactoryInterface {
public:
virtual ~GsecKeyFactoryInterface() = default;
// Creates identical and independent GsecKeyInterface objects.
virtual std::unique_ptr<GsecKeyInterface> Create() const = 0;
};
class GsecKeyFactory : public GsecKeyFactoryInterface {
public:
// The exact given parameters will be used to create GsecKey objects.
GsecKeyFactory(absl::Span<const uint8_t> key, bool is_rekey);
~GsecKeyFactory() override = default;
std::unique_ptr<GsecKeyInterface> Create() const override;
private:
std::vector<uint8_t> key_;
bool is_rekey_;
};
class GsecKey : public GsecKeyInterface {
public:
// If `is_rekey` is false, the given key will be copied as the symmetric key.
// Otherwise, part of the given key is copied as the KDF key and another part
// is copied as the nonce mask.
GsecKey(absl::Span<const uint8_t> key, bool is_rekey);
~GsecKey() override = default;
bool IsRekey() override;
absl::Span<const uint8_t> key() override;
absl::Span<uint8_t> aead_key() override;
absl::Span<const uint8_t> nonce_mask() override;
absl::Span<uint8_t> kdf_counter() override;
absl::Span<uint8_t> kdf_buffer() override;
private:
bool is_rekey_;
std::vector<uint8_t> key_;
std::vector<uint8_t> aead_key_;
std::vector<uint8_t> kdf_buffer_;
std::vector<uint8_t> nonce_mask_;
std::vector<uint8_t> kdf_counter_;
};
} // namespace grpc_core
#ifndef _STRUCT_IOVEC
#if !defined(GRPC_EVENT_ENGINE_POSIX)
struct iovec {
@ -37,11 +109,11 @@ struct iovec {
#endif // GRPC_EVENT_ENGINE_POSIX
#endif // _STRUCT_IOVEC
///
/// A gsec interface for AEAD encryption schemes. The API is thread-compatible.
/// Each implementation of this interface should specify supported values for
/// key, nonce, and tag lengths.
///
//
// A gsec interface for AEAD encryption schemes. The API is thread-compatible.
// Each implementation of this interface should specify supported values for
// key, nonce, and tag lengths.
//
// Key, nonce, and tag length in bytes
const size_t kAesGcmNonceLength = 12;
@ -55,92 +127,92 @@ const size_t kAes128GcmRekeyKeyLength = 44;
typedef struct gsec_aead_crypter gsec_aead_crypter;
///
/// The gsec_aead_crypter is an API for different AEAD implementations such as
/// AES_GCM. It encapsulates all AEAD-related operations in the format of
/// V-table that stores pointers to functions implementing those operations.
/// It also provides helper functions to wrap each of those function pointers.
///
/// A typical usage of this object would be:
///
///------------------------------------------------------------------------------
///// Declare a gsec_aead_crypter object, and create and assign an instance
///// of specific AEAD implementation e.g., AES_GCM to it. We assume both
///// key and nonce contain cryptographically secure random bytes, and the key
///// can be derived from an upper-layer application.
/// gsec_aead_crypter* crypter;
/// char* error_in_creation;
///// User can populate the message with any 100 bytes data.
/// uint8_t* message = gpr_malloc(100);
/// grpc_status_code creation_status = gsec_aes_gcm_aead_crypter_create(key,
/// kAes128GcmKeyLength,
/// kAesGcmNonceLength,
/// kAesGcmTagLength,
/// &crypter,
/// false,
/// 0
/// &error_in_creation);
///
/// if (creation_status == GRPC_STATUS_OK) {
/// // Allocate a correct amount of memory to hold a ciphertext.
/// size_t clength = 0;
/// gsec_aead_crypter_max_ciphertext_and_tag_length(crypter, 100, &clength,
/// nullptr);
/// uint8_t* ciphertext = gpr_malloc(clength);
///
/// // Perform encryption
/// size_t num_encrypted_bytes = 0;
/// char* error_in_encryption = nullptr;
/// grpc_status_code status = gsec_aead_crypter_encrypt(crypter, nonce,
/// kAesGcmNonceLength,
/// nullptr, 0, message,
/// 100, ciphertext,
/// clength,
/// &num_encrypted_bytes,
/// &error_in_encryption);
/// if (status == GRPC_STATUS_OK) {
/// // Allocate a correct amount of memory to hold a plaintext.
/// size_t plength = 0;
/// gsec_aead_crypter_max_plaintext_length(crypter, num_encrypted_bytes,
/// &plength, nullptr);
/// uint8_t* plaintext = gpr_malloc(plength);
///
/// // Perform decryption.
/// size_t num_decrypted_bytes = 0;
/// char* error_in_decryption = nullptr;
/// status = gsec_aead_crypter_decrypt(crypter, nonce,
/// kAesGcmNonceLength, nullptr, 0,
/// ciphertext, num_encrypted_bytes,
/// plaintext, plength,
/// &num_decrypted_bytes,
/// &error_in_decryption);
/// if (status != GRPC_STATUS_OK) {
/// fprintf(stderr, "AEAD decrypt operation failed with error code:"
/// "%d, message: %s\n", status, error_in_decryption);
/// }
/// ...
/// gpr_free(plaintext);
/// gpr_free(error_in_decryption);
/// } else {
/// fprintf(stderr, "AEAD encrypt operation failed with error code:"
/// "%d, message: %s\n", status, error_in_encryption);
/// }
/// ...
/// gpr_free(ciphertext);
/// gpr_free(error_in_encryption);
///} else {
/// fprintf(stderr, "Creation of AEAD crypter instance failed with error code:"
/// "%d, message: %s\n", creation_status, error_in_creation);
///}
///
///// Destruct AEAD crypter instance.
/// if (creation_status == GRPC_STATUS_OK) {
/// gsec_aead_crypter_destroy(crypter);
///}
/// gpr_free(error_in_creation);
/// gpr_free(message);
///-----------------------------------------------------------------------------
///
//
// The gsec_aead_crypter is an API for different AEAD implementations such as
// AES_GCM. It encapsulates all AEAD-related operations in the format of
// V-table that stores pointers to functions implementing those operations.
// It also provides helper functions to wrap each of those function pointers.
//
// A typical usage of this object would be:
//
//------------------------------------------------------------------------------
//// Declare a gsec_aead_crypter object, and create and assign an instance
//// of specific AEAD implementation e.g., AES_GCM to it. We assume both
//// key and nonce contain cryptographically secure random bytes, and the key
//// can be derived from an upper-layer application.
// gsec_aead_crypter* crypter;
// char* error_in_creation;
//// User can populate the message with any 100 bytes data.
// uint8_t* message = gpr_malloc(100);
// grpc_status_code creation_status = gsec_aes_gcm_aead_crypter_create(key,
// kAes128GcmKeyLength,
// kAesGcmNonceLength,
// kAesGcmTagLength,
// &crypter,
// false,
// 0
// &error_in_creation);
//
// if (creation_status == GRPC_STATUS_OK) {
// // Allocate a correct amount of memory to hold a ciphertext.
// size_t clength = 0;
// gsec_aead_crypter_max_ciphertext_and_tag_length(crypter, 100, &clength,
// nullptr);
// uint8_t* ciphertext = gpr_malloc(clength);
//
// // Perform encryption
// size_t num_encrypted_bytes = 0;
// char* error_in_encryption = nullptr;
// grpc_status_code status = gsec_aead_crypter_encrypt(crypter, nonce,
// kAesGcmNonceLength,
// nullptr, 0, message,
// 100, ciphertext,
// clength,
// &num_encrypted_bytes,
// &error_in_encryption);
// if (status == GRPC_STATUS_OK) {
// // Allocate a correct amount of memory to hold a plaintext.
// size_t plength = 0;
// gsec_aead_crypter_max_plaintext_length(crypter, num_encrypted_bytes,
// &plength, nullptr);
// uint8_t* plaintext = gpr_malloc(plength);
//
// // Perform decryption.
// size_t num_decrypted_bytes = 0;
// char* error_in_decryption = nullptr;
// status = gsec_aead_crypter_decrypt(crypter, nonce,
// kAesGcmNonceLength, nullptr, 0,
// ciphertext, num_encrypted_bytes,
// plaintext, plength,
// &num_decrypted_bytes,
// &error_in_decryption);
// if (status != GRPC_STATUS_OK) {
// fprintf(stderr, "AEAD decrypt operation failed with error code:"
// "%d, message: %s\n", status, error_in_decryption);
// }
// ...
// gpr_free(plaintext);
// gpr_free(error_in_decryption);
// } else {
// fprintf(stderr, "AEAD encrypt operation failed with error code:"
// "%d, message: %s\n", status, error_in_encryption);
// }
// ...
// gpr_free(ciphertext);
// gpr_free(error_in_encryption);
//} else {
// fprintf(stderr, "Creation of AEAD crypter instance failed with error code:"
// "%d, message: %s\n", creation_status, error_in_creation);
//}
//
//// Destruct AEAD crypter instance.
// if (creation_status == GRPC_STATUS_OK) {
// gsec_aead_crypter_destroy(crypter);
//}
// gpr_free(error_in_creation);
// gpr_free(message);
//-----------------------------------------------------------------------------
//
// V-table for gsec AEAD operations
typedef struct gsec_aead_crypter_vtable {
@ -179,39 +251,39 @@ struct gsec_aead_crypter {
const struct gsec_aead_crypter_vtable* vtable;
};
///
/// This method performs an AEAD encrypt operation.
///
///- crypter: AEAD crypter instance.
///- nonce: buffer containing a nonce with its size equal to nonce_length.
///- nonce_length: size of nonce buffer, and must be equal to the value returned
/// from method gsec_aead_crypter_nonce_length.
///- aad: buffer containing data that needs to be authenticated but not
/// encrypted with its size equal to aad_length.
///- aad_length: size of aad buffer, which should be zero if the buffer is
/// nullptr.
///- plaintext: buffer containing data that needs to be both encrypted and
/// authenticated with its size equal to plaintext_length.
///- plaintext_length: size of plaintext buffer, which should be zero if
/// plaintext is nullptr.
///- ciphertext_and_tag: buffer that will contain ciphertext and tags the method
/// produced. The buffer should not overlap the plaintext buffer, and pointers
/// to those buffers should not be equal. Also if the ciphertext+tag buffer is
/// nullptr, the plaintext_length should be zero.
///- ciphertext_and_tag_length: size of ciphertext+tag buffer, which should be
/// at least as long as the one returned from method
/// gsec_aead_crypter_max_ciphertext_and_tag_length.
///- bytes_written: the actual number of bytes written to the ciphertext+tag
/// buffer. If bytes_written is nullptr, the plaintext_length should be zero.
///- error_details: a buffer containing an error message if the method does not
/// function correctly. It is legal to pass nullptr into error_details, and
/// otherwise, the parameter should be freed with gpr_free.
///
/// On the success of encryption, the method returns GRPC_STATUS_OK. Otherwise,
/// it returns an error status code along with its details specified in
/// error_details (if error_details is not nullptr).
///
///
//
// This method performs an AEAD encrypt operation.
//
//- crypter: AEAD crypter instance.
//- nonce: buffer containing a nonce with its size equal to nonce_length.
//- nonce_length: size of nonce buffer, and must be equal to the value returned
// from method gsec_aead_crypter_nonce_length.
//- aad: buffer containing data that needs to be authenticated but not
// encrypted with its size equal to aad_length.
//- aad_length: size of aad buffer, which should be zero if the buffer is
// nullptr.
//- plaintext: buffer containing data that needs to be both encrypted and
// authenticated with its size equal to plaintext_length.
//- plaintext_length: size of plaintext buffer, which should be zero if
// plaintext is nullptr.
//- ciphertext_and_tag: buffer that will contain ciphertext and tags the method
// produced. The buffer should not overlap the plaintext buffer, and pointers
// to those buffers should not be equal. Also if the ciphertext+tag buffer is
// nullptr, the plaintext_length should be zero.
//- ciphertext_and_tag_length: size of ciphertext+tag buffer, which should be
// at least as long as the one returned from method
// gsec_aead_crypter_max_ciphertext_and_tag_length.
//- bytes_written: the actual number of bytes written to the ciphertext+tag
// buffer. If bytes_written is nullptr, the plaintext_length should be zero.
//- error_details: a buffer containing an error message if the method does not
// function correctly. It is legal to pass nullptr into error_details, and
// otherwise, the parameter should be freed with gpr_free.
//
// On the success of encryption, the method returns GRPC_STATUS_OK. Otherwise,
// it returns an error status code along with its details specified in
// error_details (if error_details is not nullptr).
//
//
grpc_status_code gsec_aead_crypter_encrypt(
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
const uint8_t* aad, size_t aad_length, const uint8_t* plaintext,
@ -219,32 +291,32 @@ grpc_status_code gsec_aead_crypter_encrypt(
size_t ciphertext_and_tag_length, size_t* bytes_written,
char** error_details);
///
/// This method performs an AEAD encrypt operation.
///
///- crypter: AEAD crypter instance.
///- nonce: buffer containing a nonce with its size equal to nonce_length.
///- nonce_length: size of nonce buffer, and must be equal to the value returned
/// from method gsec_aead_crypter_nonce_length.
///- aad_vec: an iovec array containing data that needs to be authenticated but
/// not encrypted.
///- aad_vec_length: the array length of aad_vec.
///- plaintext_vec: an iovec array containing data that needs to be both
/// encrypted and authenticated.
///- plaintext_vec_length: the array length of plaintext_vec.
///- ciphertext_vec: an iovec containing a ciphertext buffer. The buffer should
/// not overlap the plaintext buffer.
///- ciphertext_bytes_written: the actual number of bytes written to
/// ciphertext_vec.
///- error_details: a buffer containing an error message if the method does not
/// function correctly. It is legal to pass nullptr into error_details, and
/// otherwise, the parameter should be freed with gpr_free.
///
/// On the success of encryption, the method returns GRPC_STATUS_OK. Otherwise,
/// it returns an error status code along with its details specified in
/// error_details (if error_details is not nullptr).
///
///
//
// This method performs an AEAD encrypt operation.
//
//- crypter: AEAD crypter instance.
//- nonce: buffer containing a nonce with its size equal to nonce_length.
//- nonce_length: size of nonce buffer, and must be equal to the value returned
// from method gsec_aead_crypter_nonce_length.
//- aad_vec: an iovec array containing data that needs to be authenticated but
// not encrypted.
//- aad_vec_length: the array length of aad_vec.
//- plaintext_vec: an iovec array containing data that needs to be both
// encrypted and authenticated.
//- plaintext_vec_length: the array length of plaintext_vec.
//- ciphertext_vec: an iovec containing a ciphertext buffer. The buffer should
// not overlap the plaintext buffer.
//- ciphertext_bytes_written: the actual number of bytes written to
// ciphertext_vec.
//- error_details: a buffer containing an error message if the method does not
// function correctly. It is legal to pass nullptr into error_details, and
// otherwise, the parameter should be freed with gpr_free.
//
// On the success of encryption, the method returns GRPC_STATUS_OK. Otherwise,
// it returns an error status code along with its details specified in
// error_details (if error_details is not nullptr).
//
//
grpc_status_code gsec_aead_crypter_encrypt_iovec(
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
const struct iovec* aad_vec, size_t aad_vec_length,
@ -252,67 +324,67 @@ grpc_status_code gsec_aead_crypter_encrypt_iovec(
struct iovec ciphertext_vec, size_t* ciphertext_bytes_written,
char** error_details);
///
/// This method performs an AEAD decrypt operation.
///
///- crypter: AEAD crypter instance.
///- nonce: buffer containing a nonce with its size equal to nonce_length.
///- nonce_length: size of nonce buffer, and must be equal to the value returned
/// from method gsec_aead_crypter_nonce_length.
///- aad: buffer containing data that needs to be authenticated only.
///- aad_length: size of aad buffer, which should be zero if the buffer is
/// nullptr.
///- ciphertext_and_tag: buffer containing ciphertext and tag.
///- ciphertext_and_tag_length: length of ciphertext and tag. It should be zero
/// if any of plaintext, ciphertext_and_tag, or bytes_written is nullptr. Also,
/// ciphertext_and_tag_length should be at least as large as the tag length set
/// at AEAD crypter instance construction time.
///- plaintext: buffer containing decrypted and authenticated data the method
/// produced. The buffer should not overlap with the ciphertext+tag buffer, and
/// pointers to those buffers should not be equal.
///- plaintext_length: size of plaintext buffer, which should be at least as
/// long as the one returned from gsec_aead_crypter_max_plaintext_length
/// method.
///- bytes_written: the actual number of bytes written to the plaintext
/// buffer.
///- error_details: a buffer containing an error message if the method does not
/// function correctly. It is legal to pass nullptr into error_details, and
/// otherwise, the parameter should be freed with gpr_free.
///
/// On the success of decryption, the method returns GRPC_STATUS_OK. Otherwise,
/// it returns an error status code along with its details specified in
/// error_details (if error_details is not nullptr).
///
//
// This method performs an AEAD decrypt operation.
//
//- crypter: AEAD crypter instance.
//- nonce: buffer containing a nonce with its size equal to nonce_length.
//- nonce_length: size of nonce buffer, and must be equal to the value returned
// from method gsec_aead_crypter_nonce_length.
//- aad: buffer containing data that needs to be authenticated only.
//- aad_length: size of aad buffer, which should be zero if the buffer is
// nullptr.
//- ciphertext_and_tag: buffer containing ciphertext and tag.
//- ciphertext_and_tag_length: length of ciphertext and tag. It should be zero
// if any of plaintext, ciphertext_and_tag, or bytes_written is nullptr. Also,
// ciphertext_and_tag_length should be at least as large as the tag length set
// at AEAD crypter instance construction time.
//- plaintext: buffer containing decrypted and authenticated data the method
// produced. The buffer should not overlap with the ciphertext+tag buffer, and
// pointers to those buffers should not be equal.
//- plaintext_length: size of plaintext buffer, which should be at least as
// long as the one returned from gsec_aead_crypter_max_plaintext_length
// method.
//- bytes_written: the actual number of bytes written to the plaintext
// buffer.
//- error_details: a buffer containing an error message if the method does not
// function correctly. It is legal to pass nullptr into error_details, and
// otherwise, the parameter should be freed with gpr_free.
//
// On the success of decryption, the method returns GRPC_STATUS_OK. Otherwise,
// it returns an error status code along with its details specified in
// error_details (if error_details is not nullptr).
//
grpc_status_code gsec_aead_crypter_decrypt(
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
const uint8_t* aad, size_t aad_length, const uint8_t* ciphertext_and_tag,
size_t ciphertext_and_tag_length, uint8_t* plaintext,
size_t plaintext_length, size_t* bytes_written, char** error_details);
///
/// This method performs an AEAD decrypt operation.
///
///- crypter: AEAD crypter instance.
///- nonce: buffer containing a nonce with its size equal to nonce_length.
///- nonce_length: size of nonce buffer, and must be equal to the value returned
/// from method gsec_aead_crypter_nonce_length.
///- aad_vec: an iovec array containing data that needs to be authenticated but
/// not encrypted.
///- aad_vec_length: the array length of aad_vec.
///- ciphertext_vec: an iovec array containing the ciphertext and tag.
///- ciphertext_vec_length: the array length of ciphertext_vec.
///- plaintext_vec: an iovec containing a plaintext buffer. The buffer should
/// not overlap the ciphertext buffer.
///- plaintext_bytes_written: the actual number of bytes written to
/// plaintext_vec.
///- error_details: a buffer containing an error message if the method does not
/// function correctly. It is legal to pass nullptr into error_details, and
/// otherwise, the parameter should be freed with gpr_free.
///
/// On the success of decryption, the method returns GRPC_STATUS_OK. Otherwise,
/// it returns an error status code along with its details specified in
/// error_details (if error_details is not nullptr).
///
//
// This method performs an AEAD decrypt operation.
//
//- crypter: AEAD crypter instance.
//- nonce: buffer containing a nonce with its size equal to nonce_length.
//- nonce_length: size of nonce buffer, and must be equal to the value returned
// from method gsec_aead_crypter_nonce_length.
//- aad_vec: an iovec array containing data that needs to be authenticated but
// not encrypted.
//- aad_vec_length: the array length of aad_vec.
//- ciphertext_vec: an iovec array containing the ciphertext and tag.
//- ciphertext_vec_length: the array length of ciphertext_vec.
//- plaintext_vec: an iovec containing a plaintext buffer. The buffer should
// not overlap the ciphertext buffer.
//- plaintext_bytes_written: the actual number of bytes written to
// plaintext_vec.
//- error_details: a buffer containing an error message if the method does not
// function correctly. It is legal to pass nullptr into error_details, and
// otherwise, the parameter should be freed with gpr_free.
//
// On the success of decryption, the method returns GRPC_STATUS_OK. Otherwise,
// it returns an error status code along with its details specified in
// error_details (if error_details is not nullptr).
//
grpc_status_code gsec_aead_crypter_decrypt_iovec(
gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length,
const struct iovec* aad_vec, size_t aad_vec_length,
@ -320,140 +392,136 @@ grpc_status_code gsec_aead_crypter_decrypt_iovec(
struct iovec plaintext_vec, size_t* plaintext_bytes_written,
char** error_details);
///
/// This method computes the size of ciphertext+tag buffer that must be passed
/// to gsec_aead_crypter_encrypt function to ensure correct encryption of a
/// plaintext. The actual size of ciphertext+tag written to the buffer could be
/// smaller.
///
///- crypter: AEAD crypter instance.
///- plaintext_length: length of plaintext.
///- max_ciphertext_and_tag_length_to_return: the size of ciphertext+tag buffer
/// the method returns.
///- error_details: a buffer containing an error message if the method does not
/// function correctly. It is legal to pass nullptr into error_details, and
/// otherwise, the parameter should be freed with gpr_free.
///
/// On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
/// it returns an error status code along with its details specified in
/// error_details (if error_details is not nullptr).
///
//
// This method computes the size of ciphertext+tag buffer that must be passed
// to gsec_aead_crypter_encrypt function to ensure correct encryption of a
// plaintext. The actual size of ciphertext+tag written to the buffer could be
// smaller.
//
//- crypter: AEAD crypter instance.
//- plaintext_length: length of plaintext.
//- max_ciphertext_and_tag_length_to_return: the size of ciphertext+tag buffer
// the method returns.
//- error_details: a buffer containing an error message if the method does not
// function correctly. It is legal to pass nullptr into error_details, and
// otherwise, the parameter should be freed with gpr_free.
//
// On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
// it returns an error status code along with its details specified in
// error_details (if error_details is not nullptr).
//
grpc_status_code gsec_aead_crypter_max_ciphertext_and_tag_length(
const gsec_aead_crypter* crypter, size_t plaintext_length,
size_t* max_ciphertext_and_tag_length_to_return, char** error_details);
///
/// This method computes the size of plaintext buffer that must be passed to
/// gsec_aead_crypter_decrypt function to ensure correct decryption of a
/// ciphertext. The actual size of plaintext written to the buffer could be
/// smaller.
///
///- crypter: AEAD crypter instance.
///- ciphertext_and_tag_length: length of ciphertext and tag.
///- max_plaintext_length_to_return: the size of plaintext buffer the method
/// returns.
///- error_details: a buffer containing an error message if the method does not
/// function correctly. It is legal to pass nullptr into error_details, and
/// otherwise, the parameter should be freed with gpr_free.
///
/// On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
/// it returns an error status code along with its details specified in
/// error_details (if error_details is not nullptr).
///
//
// This method computes the size of plaintext buffer that must be passed to
// gsec_aead_crypter_decrypt function to ensure correct decryption of a
// ciphertext. The actual size of plaintext written to the buffer could be
// smaller.
//
//- crypter: AEAD crypter instance.
//- ciphertext_and_tag_length: length of ciphertext and tag.
//- max_plaintext_length_to_return: the size of plaintext buffer the method
// returns.
//- error_details: a buffer containing an error message if the method does not
// function correctly. It is legal to pass nullptr into error_details, and
// otherwise, the parameter should be freed with gpr_free.
//
// On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
// it returns an error status code along with its details specified in
// error_details (if error_details is not nullptr).
//
grpc_status_code gsec_aead_crypter_max_plaintext_length(
const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length,
size_t* max_plaintext_length_to_return, char** error_details);
///
/// This method returns a valid size of nonce array used at the construction of
/// AEAD crypter instance. It is also the size that should be passed to encrypt
/// and decrypt methods executed on the instance.
///
///- crypter: AEAD crypter instance.
///- nonce_length_to_return: the length of nonce array the method returns.
///- error_details: a buffer containing an error message if the method does not
/// function correctly. It is legal to pass nullptr into error_details, and
/// otherwise, the parameter should be freed with gpr_free.
///
/// On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
/// it returns an error status code along with its details specified in
/// error_details (if error_details is not nullptr).
///
//
// This method returns a valid size of nonce array used at the construction of
// AEAD crypter instance. It is also the size that should be passed to encrypt
// and decrypt methods executed on the instance.
//
//- crypter: AEAD crypter instance.
//- nonce_length_to_return: the length of nonce array the method returns.
//- error_details: a buffer containing an error message if the method does not
// function correctly. It is legal to pass nullptr into error_details, and
// otherwise, the parameter should be freed with gpr_free.
//
// On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
// it returns an error status code along with its details specified in
// error_details (if error_details is not nullptr).
//
grpc_status_code gsec_aead_crypter_nonce_length(
const gsec_aead_crypter* crypter, size_t* nonce_length_to_return,
char** error_details);
///
/// This method returns a valid size of key array used at the construction of
/// AEAD crypter instance. It is also the size that should be passed to encrypt
/// and decrypt methods executed on the instance.
///
///- crypter: AEAD crypter instance.
///- key_length_to_return: the length of key array the method returns.
///- error_details: a buffer containing an error message if the method does not
/// function correctly. It is legal to pass nullptr into error_details, and
/// otherwise, the parameter should be freed with gpr_free.
///
/// On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
/// it returns an error status code along with its details specified in
/// error_details (if error_details is not nullptr).
///
//
// This method returns a valid size of key array used at the construction of
// AEAD crypter instance. It is also the size that should be passed to encrypt
// and decrypt methods executed on the instance.
//
//- crypter: AEAD crypter instance.
//- key_length_to_return: the length of key array the method returns.
//- error_details: a buffer containing an error message if the method does not
// function correctly. It is legal to pass nullptr into error_details, and
// otherwise, the parameter should be freed with gpr_free.
//
// On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
// it returns an error status code along with its details specified in
// error_details (if error_details is not nullptr).
//
grpc_status_code gsec_aead_crypter_key_length(const gsec_aead_crypter* crypter,
size_t* key_length_to_return,
char** error_details);
///
/// This method returns a valid size of tag array used at the construction of
/// AEAD crypter instance. It is also the size that should be passed to encrypt
/// and decrypt methods executed on the instance.
///
///- crypter: AEAD crypter instance.
///- tag_length_to_return: the length of tag array the method returns.
///- error_details: a buffer containing an error message if the method does not
/// function correctly. It is legal to pass nullptr into error_details, and
/// otherwise, the parameter should be freed with gpr_free.
///
/// On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
/// it returns an error status code along with its details specified in
/// error_details (if error_details is not nullptr).
///
//
// This method returns a valid size of tag array used at the construction of
// AEAD crypter instance. It is also the size that should be passed to encrypt
// and decrypt methods executed on the instance.
//
//- crypter: AEAD crypter instance.
//- tag_length_to_return: the length of tag array the method returns.
//- error_details: a buffer containing an error message if the method does not
// function correctly. It is legal to pass nullptr into error_details, and
// otherwise, the parameter should be freed with gpr_free.
//
// On the success of execution, the method returns GRPC_STATUS_OK. Otherwise,
// it returns an error status code along with its details specified in
// error_details (if error_details is not nullptr).
//
grpc_status_code gsec_aead_crypter_tag_length(const gsec_aead_crypter* crypter,
size_t* tag_length_to_return,
char** error_details);
///
/// This method destroys an AEAD crypter instance by de-allocating all of its
/// occupied memory.
///
///- crypter: AEAD crypter instance that needs to be destroyed.
///
//
// This method destroys an AEAD crypter instance by de-allocating all of its
// occupied memory.
//
//- crypter: AEAD crypter instance that needs to be destroyed.
//
void gsec_aead_crypter_destroy(gsec_aead_crypter* crypter);
///
/// This method creates an AEAD crypter instance of AES-GCM encryption scheme
/// which supports 16 and 32 bytes long keys, 12 and 16 bytes long nonces, and
/// 16 bytes long tags. It should be noted that once the lengths of key, nonce,
/// and tag are determined at construction time, they cannot be modified later.
///
///- key: buffer containing a key which is binded with AEAD crypter instance.
///- key_length: length of a key in bytes, which should be 44 if rekeying is
/// enabled and 16 or 32 otherwise.
///- nonce_length: length of a nonce in bytes, which should be either 12 or 16.
///- tag_length: length of a tag in bytes, which should be always 16.
///- rekey: enable nonce-based rekeying and nonce-masking.
///- crypter: address of AES_GCM crypter instance returned from the method.
///- error_details: a buffer containing an error message if the method does not
/// function correctly. It is legal to pass nullptr into error_details, and
/// otherwise, the parameter should be freed with gpr_free.
///
/// On success of instance creation, it stores the address of instance at
/// crypter. Otherwise, it returns an error status code together with its
/// details specified in error_details.
///
grpc_status_code gsec_aes_gcm_aead_crypter_create(const uint8_t* key,
size_t key_length,
size_t nonce_length,
size_t tag_length, bool rekey,
gsec_aead_crypter** crypter,
char** error_details);
//
// This method creates an AEAD crypter instance of AES-GCM encryption scheme
// which supports 16 and 32 bytes long keys, 12 and 16 bytes long nonces, and
// 16 bytes long tags. It should be noted that once the lengths of key, nonce,
// and tag are determined at construction time, they cannot be modified later.
//
//- key: an instance of GsecKeyInterface, which will provide accessors to the
// key, aead_key, kdf_counter, nonce_mask as well as the buffer for aead_key
// derivation. It also tells whether rekey is supported.
//- nonce_length: length of a nonce in bytes, which should be either 12 or 16.
//- tag_length: length of a tag in bytes, which should be always 16.
//- crypter: address of AES_GCM crypter instance returned from the method.
//- error_details: a buffer containing an error message if the method does not
// function correctly. It is legal to pass nullptr into error_details, and
// otherwise, the parameter should be freed with gpr_free.
//
// On success of instance creation, it stores the address of instance at
// crypter. Otherwise, it returns an error status code together with its
// details specified in error_details.
//
grpc_status_code gsec_aes_gcm_aead_crypter_create(
std::unique_ptr<grpc_core::GsecKeyInterface> key, size_t nonce_length,
size_t tag_length, gsec_aead_crypter** crypter, char** error_details);
#endif // GRPC_SRC_CORE_TSI_ALTS_CRYPT_GSEC_H

@ -24,12 +24,13 @@
#include <stdlib.h>
#include <algorithm>
#include <memory>
#include "absl/types/span.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/crash.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/tsi/alts/crypt/gsec.h"
#include "src/core/tsi/alts/frame_protector/alts_crypter.h"
@ -337,15 +338,18 @@ static grpc_status_code create_alts_crypters(const uint8_t* key,
grpc_status_code status;
gsec_aead_crypter* aead_crypter_seal = nullptr;
gsec_aead_crypter* aead_crypter_unseal = nullptr;
status = gsec_aes_gcm_aead_crypter_create(key, key_size, kAesGcmNonceLength,
kAesGcmTagLength, is_rekey,
&aead_crypter_seal, error_details);
status = gsec_aes_gcm_aead_crypter_create(
std::make_unique<grpc_core::GsecKey>(absl::MakeConstSpan(key, key_size),
is_rekey),
kAesGcmNonceLength, kAesGcmTagLength, &aead_crypter_seal, error_details);
if (status != GRPC_STATUS_OK) {
return status;
}
status = gsec_aes_gcm_aead_crypter_create(
key, key_size, kAesGcmNonceLength, kAesGcmTagLength, is_rekey,
&aead_crypter_unseal, error_details);
std::make_unique<grpc_core::GsecKey>(absl::MakeConstSpan(key, key_size),
is_rekey),
kAesGcmNonceLength, kAesGcmTagLength, &aead_crypter_unseal,
error_details);
if (status != GRPC_STATUS_OK) {
return status;
}

@ -33,17 +33,13 @@
#include <grpc/support/sync.h>
#include <grpc/support/thd_id.h>
#include "src/core/lib/gprpp/crash.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/tsi/alts/frame_protector/alts_frame_protector.h"
#include "src/core/tsi/alts/handshaker/alts_handshaker_client.h"
#include "src/core/tsi/alts/handshaker/alts_shared_resource.h"
#include "src/core/tsi/alts/handshaker/alts_tsi_utils.h"
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.h"
// Main struct for ALTS TSI handshaker.
@ -193,8 +189,10 @@ static tsi_result handshaker_result_create_zero_copy_grpc_protector(
"protector equals %zu",
*max_output_protected_frame_size);
tsi_result ok = alts_zero_copy_grpc_protector_create(
reinterpret_cast<const uint8_t*>(result->key_data),
kAltsAes128GcmRekeyKeyLength, /*is_rekey=*/true, result->is_client,
grpc_core::GsecKeyFactory({reinterpret_cast<uint8_t*>(result->key_data),
kAltsAes128GcmRekeyKeyLength},
/*is_rekey=*/true),
result->is_client,
/*is_integrity_only=*/false, /*enable_extra_copy=*/false,
max_output_protected_frame_size, protector);
if (ok != TSI_OK) {

@ -22,13 +22,12 @@
#include <string.h>
#include <memory>
#include <utility>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/crash.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/tsi/alts/crypt/gsec.h"
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h"
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h"
@ -110,7 +109,7 @@ static bool read_frame_size(const grpc_slice_buffer* sb,
/// for protect or unprotect.
///
static tsi_result create_alts_grpc_record_protocol(
const uint8_t* key, size_t key_size, bool is_rekey, bool is_client,
std::unique_ptr<grpc_core::GsecKeyInterface> key, bool is_client,
bool is_integrity_only, bool is_protect, bool enable_extra_copy,
alts_grpc_record_protocol** record_protocol) {
if (key == nullptr || record_protocol == nullptr) {
@ -119,9 +118,10 @@ static tsi_result create_alts_grpc_record_protocol(
grpc_status_code status;
gsec_aead_crypter* crypter = nullptr;
char* error_details = nullptr;
status = gsec_aes_gcm_aead_crypter_create(key, key_size, kAesGcmNonceLength,
kAesGcmTagLength, is_rekey,
&crypter, &error_details);
bool is_rekey = key->IsRekey();
status = gsec_aes_gcm_aead_crypter_create(std::move(key), kAesGcmNonceLength,
kAesGcmTagLength, &crypter,
&error_details);
if (status != GRPC_STATUS_OK) {
gpr_log(GPR_ERROR, "Failed to create AEAD crypter, %s", error_details);
gpr_free(error_details);
@ -259,11 +259,11 @@ static const tsi_zero_copy_grpc_protector_vtable
alts_zero_copy_grpc_protector_max_frame_size};
tsi_result alts_zero_copy_grpc_protector_create(
const uint8_t* key, size_t key_size, bool is_rekey, bool is_client,
const grpc_core::GsecKeyFactoryInterface& key_factory, bool is_client,
bool is_integrity_only, bool enable_extra_copy,
size_t* max_protected_frame_size,
tsi_zero_copy_grpc_protector** protector) {
if (key == nullptr || protector == nullptr) {
if (protector == nullptr) {
gpr_log(
GPR_ERROR,
"Invalid nullptr arguments to alts_zero_copy_grpc_protector create.");
@ -275,11 +275,11 @@ tsi_result alts_zero_copy_grpc_protector_create(
gpr_zalloc(sizeof(alts_zero_copy_grpc_protector)));
// Creates alts_grpc_record_protocol objects.
tsi_result status = create_alts_grpc_record_protocol(
key, key_size, is_rekey, is_client, is_integrity_only,
key_factory.Create(), is_client, is_integrity_only,
/*is_protect=*/true, enable_extra_copy, &impl->record_protocol);
if (status == TSI_OK) {
status = create_alts_grpc_record_protocol(
key, key_size, is_rekey, is_client, is_integrity_only,
key_factory.Create(), is_client, is_integrity_only,
/*is_protect=*/false, enable_extra_copy, &impl->unrecord_protocol);
if (status == TSI_OK) {
// Sets maximum frame size.

@ -23,33 +23,34 @@
#include <stdbool.h>
#include "src/core/tsi/transport_security_grpc.h"
#include "src/core/tsi/alts/crypt/gsec.h"
#include "src/core/tsi/transport_security_interface.h"
///
/// This method creates an ALTS zero-copy grpc protector.
///
///- key: a symmetric key used to seal/unseal frames.
///- key_size: the size of symmetric key.
///- is_rekey: use rekeying AEAD crypter.
///- is_client: a flag indicating if the protector will be used at client or
/// server side.
///- is_integrity_only: a flag indicating if the protector instance will be
/// used for integrity-only or privacy-integrity mode.
///- enable_extra_copy: a flag indicating if the protector instance does one
/// extra memory copy during the protect operation for integrity_only mode.
/// For the unprotect operation, it is still zero-copy. If application intends
/// to modify the data buffer after the protect operation, we can turn on this
/// mode to avoid integrity check failure.
///- max_protected_frame_size: an in/out parameter indicating max frame size
/// to be used by the protector. If it is nullptr, the default frame size will
/// be used. Otherwise, the provided frame size will be adjusted (if not
/// falling into a valid frame range) and used.
///- protector: a pointer to the zero-copy protector returned from the method.
///
/// This method returns TSI_OK on success or a specific error code otherwise.
///
//
// This method creates an ALTS zero-copy grpc protector.
//
//- key_factory: a key factory that creates keys to seal/unseal frames.
// it self-contains the information such as key length and whether rekey is
// supported.
//- is_client: a flag indicating if the protector will be used at client or
// server side.
//- is_integrity_only: a flag indicating if the protector instance will be
// used for integrity-only or privacy-integrity mode.
//- enable_extra_copy: a flag indicating if the protector instance does one
// extra memory copy during the protect operation for integrity_only mode.
// For the unprotect operation, it is still zero-copy. If application intends
// to modify the data buffer after the protect operation, we can turn on this
// mode to avoid integrity check failure.
//- max_protected_frame_size: an in/out parameter indicating max frame size
// to be used by the protector. If it is nullptr, the default frame size will
// be used. Otherwise, the provided frame size will be adjusted (if not
// falling into a valid frame range) and used.
//- protector: a pointer to the zero-copy protector returned from the method.
//
// This method returns TSI_OK on success or a specific error code otherwise.
//
tsi_result alts_zero_copy_grpc_protector_create(
const uint8_t* key, size_t key_size, bool is_rekey, bool is_client,
const grpc_core::GsecKeyFactoryInterface& key_factory, bool is_client,
bool is_integrity_only, bool enable_extra_copy,
size_t* max_protected_frame_size, tsi_zero_copy_grpc_protector** protector);

@ -24,7 +24,10 @@ grpc_package(
grpc_cc_test(
name = "alts_crypt_test",
srcs = ["aes_gcm_test.cc"],
external_deps = ["gtest"],
external_deps = [
"gtest",
"absl/types:span",
],
language = "C++",
deps = [
":alts_crypt_test_util",

@ -16,12 +16,15 @@
//
//
#include <memory>
#include <gtest/gtest.h>
#include "absl/types/span.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gprpp/crash.h"
#include "src/core/tsi/alts/crypt/gsec.h"
#include "test/core/tsi/alts/crypt/gsec_test_util.h"
#include "test/core/util/test_config.h"
@ -86,8 +89,9 @@ static void gsec_test_random_encrypt_decrypt(gsec_aead_crypter* crypter,
ASSERT_NE(crypter, nullptr);
size_t nonce_length, tag_length;
uint8_t *nonce, *aad, *message;
gsec_aead_crypter_nonce_length(crypter, &nonce_length, nullptr);
gsec_aead_crypter_tag_length(crypter, &tag_length, nullptr);
gsec_aead_crypter_nonce_length(crypter, &nonce_length,
/*error_details=*/nullptr);
gsec_aead_crypter_tag_length(crypter, &tag_length, /*error_details=*/nullptr);
gsec_test_random_array(&nonce, nonce_length);
gsec_test_random_array(&aad, aad_length);
@ -95,8 +99,9 @@ static void gsec_test_random_encrypt_decrypt(gsec_aead_crypter* crypter,
// Test encryption
size_t ciphertext_and_tag_length, ciphertext_bytes_written = 0;
gsec_aead_crypter_max_ciphertext_and_tag_length(
crypter, message_length, &ciphertext_and_tag_length, nullptr);
gsec_aead_crypter_max_ciphertext_and_tag_length(crypter, message_length,
&ciphertext_and_tag_length,
/*error_details=*/nullptr);
uint8_t* ciphertext_and_tag =
static_cast<uint8_t*>(gpr_malloc(ciphertext_and_tag_length));
@ -114,12 +119,13 @@ static void gsec_test_random_encrypt_decrypt(gsec_aead_crypter* crypter,
// Test decryption
size_t plaintext_length, plaintext_bytes_written = 0;
gsec_aead_crypter_max_plaintext_length(crypter, ciphertext_bytes_written,
&plaintext_length, nullptr);
&plaintext_length,
/*error_details=*/nullptr);
uint8_t* plaintext = static_cast<uint8_t*>(gpr_malloc(plaintext_length));
grpc_status_code status = gsec_aead_crypter_decrypt(
crypter, nonce, nonce_length, aad, aad_length, ciphertext_and_tag,
ciphertext_bytes_written, plaintext, plaintext_length,
&plaintext_bytes_written, nullptr);
&plaintext_bytes_written, /*error_details=*/nullptr);
ASSERT_EQ(status, GRPC_STATUS_OK);
ASSERT_EQ(message_length, plaintext_bytes_written);
@ -245,8 +251,9 @@ static void gsec_test_multiple_random_encrypt_decrypt(
aads = static_cast<uint8_t**>(gpr_malloc(sizeof(uint8_t*) * count));
messages = static_cast<uint8_t**>(gpr_malloc(sizeof(uint8_t*) * count));
gsec_aead_crypter_nonce_length(crypter, &nonce_length, nullptr);
gsec_aead_crypter_tag_length(crypter, &tag_length, nullptr);
gsec_aead_crypter_nonce_length(crypter, &nonce_length,
/*error_details=*/nullptr);
gsec_aead_crypter_tag_length(crypter, &tag_length, /*error_details=*/nullptr);
size_t ind;
for (ind = 0; ind < count; ind++) {
@ -277,14 +284,15 @@ static void gsec_test_multiple_random_encrypt_decrypt(
size_t message_length =
(message_lengths == nullptr) ? 0 : message_lengths[ind];
gsec_aead_crypter_max_ciphertext_and_tag_length(
crypter, message_length, &(ciphertext_and_tag_lengths[ind]), nullptr);
crypter, message_length, &(ciphertext_and_tag_lengths[ind]),
/*error_details=*/nullptr);
ciphertext_and_tags[ind] =
static_cast<uint8_t*>(gpr_malloc(ciphertext_and_tag_lengths[ind]));
grpc_status_code status = gsec_aead_crypter_encrypt(
crypter, nonces[ind], nonce_length, aads[ind], aad_length,
messages[ind], message_length, ciphertext_and_tags[ind],
ciphertext_and_tag_lengths[ind], &(ciphertext_bytes_writtens[ind]),
nullptr);
/*error_details=*/nullptr);
ASSERT_EQ(status, GRPC_STATUS_OK);
ASSERT_EQ(message_length + tag_length, ciphertext_and_tag_lengths[ind]);
ASSERT_EQ(ciphertext_bytes_writtens[ind], ciphertext_and_tag_lengths[ind]);
@ -294,15 +302,15 @@ static void gsec_test_multiple_random_encrypt_decrypt(
size_t aad_length = (aad_lengths == nullptr) ? 0 : aad_lengths[ind];
size_t message_length =
(message_lengths == nullptr) ? 0 : message_lengths[ind];
gsec_aead_crypter_max_plaintext_length(crypter,
ciphertext_bytes_writtens[ind],
&(plaintext_lengths[ind]), nullptr);
gsec_aead_crypter_max_plaintext_length(
crypter, ciphertext_bytes_writtens[ind], &(plaintext_lengths[ind]),
/*error_details=*/nullptr);
plaintexts[ind] = static_cast<uint8_t*>(gpr_malloc(plaintext_lengths[ind]));
grpc_status_code status = gsec_aead_crypter_decrypt(
crypter, nonces[ind], nonce_length, aads[ind], aad_length,
ciphertext_and_tags[ind], ciphertext_bytes_writtens[ind],
plaintexts[ind], plaintext_lengths[ind],
&(plaintext_bytes_writtens[ind]), nullptr);
&(plaintext_bytes_writtens[ind]), /*error_details=*/nullptr);
ASSERT_EQ(status, GRPC_STATUS_OK);
ASSERT_EQ(message_length, plaintext_bytes_writtens[ind]);
if (message_length != 0) {
@ -432,14 +440,16 @@ static void gsec_test_encryption_failure(gsec_aead_crypter* crypter) {
char* error_message;
uint8_t *nonce, *aad, *message;
gsec_aead_crypter_nonce_length(crypter, &nonce_length, nullptr);
gsec_aead_crypter_nonce_length(crypter, &nonce_length,
/*error_details=*/nullptr);
gsec_test_random_array(&nonce, nonce_length);
gsec_test_random_array(&aad, aad_length);
gsec_test_random_array(&message, message_length);
size_t ciphertext_and_tag_length, ciphertext_bytes_written = 0;
gsec_aead_crypter_max_ciphertext_and_tag_length(
crypter, message_length, &ciphertext_and_tag_length, nullptr);
gsec_aead_crypter_max_ciphertext_and_tag_length(crypter, message_length,
&ciphertext_and_tag_length,
/*error_details=*/nullptr);
uint8_t* ciphertext_and_tag =
static_cast<uint8_t*>(gpr_malloc(ciphertext_and_tag_length));
@ -556,29 +566,32 @@ static void gsec_test_decryption_failure(gsec_aead_crypter* crypter) {
size_t nonce_length, tag_length;
uint8_t *nonce, *aad, *message;
gsec_aead_crypter_nonce_length(crypter, &nonce_length, nullptr);
gsec_aead_crypter_tag_length(crypter, &tag_length, nullptr);
gsec_aead_crypter_nonce_length(crypter, &nonce_length,
/*error_details=*/nullptr);
gsec_aead_crypter_tag_length(crypter, &tag_length, /*error_details=*/nullptr);
gsec_test_random_array(&nonce, nonce_length);
gsec_test_random_array(&aad, aad_length);
gsec_test_random_array(&message, message_length);
// Test encryption
size_t ciphertext_and_tag_length, ciphertext_bytes_written = 0;
gsec_aead_crypter_max_ciphertext_and_tag_length(
crypter, message_length, &ciphertext_and_tag_length, nullptr);
gsec_aead_crypter_max_ciphertext_and_tag_length(crypter, message_length,
&ciphertext_and_tag_length,
/*error_details=*/nullptr);
uint8_t* ciphertext_and_tag =
static_cast<uint8_t*>(gpr_malloc(ciphertext_and_tag_length));
grpc_status_code status = gsec_aead_crypter_encrypt(
crypter, nonce, nonce_length, aad, aad_length, message, message_length,
ciphertext_and_tag, ciphertext_and_tag_length, &ciphertext_bytes_written,
nullptr);
/*error_details=*/nullptr);
ASSERT_EQ(status, GRPC_STATUS_OK);
ASSERT_EQ(ciphertext_bytes_written, ciphertext_and_tag_length);
size_t plaintext_length, plaintext_bytes_written = 0;
gsec_aead_crypter_max_plaintext_length(crypter, ciphertext_bytes_written,
&plaintext_length, nullptr);
&plaintext_length,
/*error_details=*/nullptr);
uint8_t* plaintext = static_cast<uint8_t*>(gpr_malloc(plaintext_length));
char* error_message;
@ -705,14 +718,15 @@ static void gsec_test_encrypt_decrypt_test_vector(
size_t ciphertext_and_tag_length, ciphertext_bytes_written = 0;
gsec_aead_crypter_max_ciphertext_and_tag_length(
crypter, test_vector->plaintext_length, &ciphertext_and_tag_length,
nullptr);
/*error_details=*/nullptr);
uint8_t* ciphertext_and_tag_bytes =
static_cast<uint8_t*>(gpr_malloc(ciphertext_and_tag_length));
grpc_status_code status = gsec_aead_crypter_encrypt(
crypter, test_vector->nonce, test_vector->nonce_length, test_vector->aad,
test_vector->aad_length, test_vector->plaintext,
test_vector->plaintext_length, ciphertext_and_tag_bytes,
ciphertext_and_tag_length, &ciphertext_bytes_written, nullptr);
ciphertext_and_tag_length, &ciphertext_bytes_written,
/*error_details=*/nullptr);
ASSERT_EQ(status, GRPC_STATUS_OK);
ASSERT_EQ(ciphertext_bytes_written, ciphertext_and_tag_length);
@ -723,14 +737,15 @@ static void gsec_test_encrypt_decrypt_test_vector(
// Test byte-based decryption interface
size_t plaintext_length, plaintext_bytes_written = 0;
gsec_aead_crypter_max_plaintext_length(crypter, ciphertext_and_tag_length,
&plaintext_length, nullptr);
&plaintext_length,
/*error_details=*/nullptr);
uint8_t* plaintext_bytes =
static_cast<uint8_t*>(gpr_malloc(plaintext_length));
status = gsec_aead_crypter_decrypt(
crypter, test_vector->nonce, test_vector->nonce_length, test_vector->aad,
test_vector->aad_length, test_vector->ciphertext_and_tag,
test_vector->ciphertext_and_tag_length, plaintext_bytes, plaintext_length,
&plaintext_bytes_written, nullptr);
&plaintext_bytes_written, /*error_details=*/nullptr);
ASSERT_EQ(status, GRPC_STATUS_OK);
if (plaintext_bytes_written != 0) {
ASSERT_EQ(memcmp(test_vector->plaintext, plaintext_bytes,
@ -755,8 +770,10 @@ static void gsec_test_get_crypter_from_test_vector(
size_t ciphertext_and_tag_length = test_vector->ciphertext_and_tag_length;
ASSERT_EQ(ciphertext_and_tag_length, plaintext_length + kAesGcmTagLength);
size_t tag_length = ciphertext_and_tag_length - plaintext_length;
gsec_aes_gcm_aead_crypter_create(test_vector->key, key_length, nonce_length,
tag_length, rekey, crypter, nullptr);
gsec_aes_gcm_aead_crypter_create(
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(test_vector->key, key_length), rekey),
nonce_length, tag_length, crypter, /*error_details=*/nullptr);
}
static void gsec_test_verify_crypter_on_test_vector(
@ -803,8 +820,10 @@ static void gsec_test_create_random_aes_gcm_crypter(gsec_aead_crypter** crypter,
bool rekey) {
uint8_t* key;
gsec_test_random_array(&key, key_length);
gsec_aes_gcm_aead_crypter_create(key, key_length, nonce_length, tag_length,
rekey, crypter, nullptr);
gsec_aes_gcm_aead_crypter_create(
std::make_unique<grpc_core::GsecKey>(absl::MakeConstSpan(key, key_length),
rekey),
nonce_length, tag_length, crypter, /*error_details=*/nullptr);
gpr_free(key);
}
@ -823,6 +842,29 @@ static void gsec_test_get_random_aes_gcm_crypters(
kAesGcmTagLength, /*rekey=*/true);
}
TEST(AltsCryptTest, GsecKeyCreationIsRekey) {
uint8_t* key;
gsec_test_random_array(&key, kAes128GcmRekeyKeyLength);
grpc_core::GsecKey gsec_key({key, kAes128GcmRekeyKeyLength},
/*is_rekey=*/true);
EXPECT_TRUE(gsec_key.IsRekey());
EXPECT_EQ(gsec_key.key().size(), kAes256GcmKeyLength);
EXPECT_EQ(gsec_key.aead_key().size(), kAes128GcmKeyLength);
EXPECT_EQ(gsec_key.kdf_counter().size(), 6);
EXPECT_EQ(gsec_key.nonce_mask().size(), kAesGcmNonceLength);
gpr_free(key);
}
TEST(AltsCryptTest, GsecKeyCreationIsNotRekey) {
uint8_t* key;
gsec_test_random_array(&key, kAes256GcmKeyLength);
grpc_core::GsecKey gsec_key({key, kAes256GcmKeyLength},
/*is_rekey=*/false);
EXPECT_FALSE(gsec_key.IsRekey());
EXPECT_EQ(gsec_key.key().size(), kAes256GcmKeyLength);
gpr_free(key);
}
TEST(AltsCryptTest, GsecTestDoGenericCrypterTests) {
gsec_aead_crypter** crypters;
gsec_test_get_random_aes_gcm_crypters(&crypters);

@ -34,7 +34,10 @@ grpc_cc_test(
grpc_cc_test(
name = "alts_crypter_test",
srcs = ["alts_crypter_test.cc"],
external_deps = ["gtest"],
external_deps = [
"gtest",
"absl/types:span",
],
language = "C++",
deps = [
"//:gpr",

@ -22,12 +22,15 @@
#include <stdlib.h>
#include <string.h>
#include <memory>
#include <gtest/gtest.h>
#include "absl/types/span.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gprpp/crash.h"
#include "test/core/tsi/alts/crypt/gsec_test_util.h"
static void alts_crypter_test_random_seal_unseal(alts_crypter* server_seal,
@ -354,28 +357,48 @@ static void create_random_alts_seal_crypter(
size_t key_length = rekey ? kAes128GcmRekeyKeyLength : kAes128GcmKeyLength;
uint8_t* key;
gsec_test_random_array(&key, key_length);
gsec_aes_gcm_aead_crypter_create(key, key_length, kAesGcmNonceLength,
kAesGcmTagLength, rekey, server_crypter_seal,
nullptr);
gsec_aes_gcm_aead_crypter_create(key, key_length, kAesGcmNonceLength,
kAesGcmTagLength, rekey,
server_crypter_unseal, nullptr);
gsec_aes_gcm_aead_crypter_create(key, key_length, kAesGcmNonceLength,
kAesGcmTagLength, rekey, client_crypter_seal,
nullptr);
gsec_aes_gcm_aead_crypter_create(key, key_length, kAesGcmNonceLength,
kAesGcmTagLength, rekey,
client_crypter_unseal, nullptr);
ASSERT_EQ(gsec_aes_gcm_aead_crypter_create(
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, server_crypter_seal,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
ASSERT_EQ(gsec_aes_gcm_aead_crypter_create(
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, server_crypter_unseal,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
ASSERT_EQ(gsec_aes_gcm_aead_crypter_create(
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, client_crypter_seal,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
ASSERT_EQ(gsec_aes_gcm_aead_crypter_create(
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, client_crypter_unseal,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
size_t overflow_size = rekey ? 8 : 5;
alts_seal_crypter_create(*client_crypter_seal, /*is_client=*/true,
overflow_size, client_seal, nullptr);
alts_unseal_crypter_create(*client_crypter_unseal, /*is_client=*/true,
overflow_size, client_unseal, nullptr);
alts_seal_crypter_create(*server_crypter_seal, /*is_client=*/false,
overflow_size, server_seal, nullptr);
alts_unseal_crypter_create(*server_crypter_unseal, /*is_client=*/false,
overflow_size, server_unseal, nullptr);
ASSERT_EQ(alts_seal_crypter_create(*client_crypter_seal, /*is_client=*/true,
overflow_size, client_seal,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
ASSERT_EQ(alts_unseal_crypter_create(
*client_crypter_unseal, /*is_client=*/true, overflow_size,
client_unseal, /*error_details=*/nullptr),
GRPC_STATUS_OK);
ASSERT_EQ(alts_seal_crypter_create(*server_crypter_seal, /*is_client=*/false,
overflow_size, server_seal,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
ASSERT_EQ(alts_unseal_crypter_create(
*server_crypter_unseal, /*is_client=*/false, overflow_size,
server_unseal, /*error_details=*/nullptr),
GRPC_STATUS_OK);
gpr_free(key);
}

@ -21,7 +21,10 @@ grpc_package(name = "test/core/tsi/alts/zero_copy_frame_protector")
grpc_cc_test(
name = "alts_grpc_record_protocol_test",
srcs = ["alts_grpc_record_protocol_test.cc"],
external_deps = ["gtest"],
external_deps = [
"gtest",
"absl/types:span",
],
language = "C++",
deps = [
"//:gpr",
@ -36,7 +39,10 @@ grpc_cc_test(
grpc_cc_test(
name = "alts_iovec_record_protocol_test",
srcs = ["alts_iovec_record_protocol_test.cc"],
external_deps = ["gtest"],
external_deps = [
"gtest",
"absl/types:span",
],
language = "C++",
deps = [
"//:gpr",
@ -49,7 +55,10 @@ grpc_cc_test(
grpc_cc_test(
name = "alts_zero_copy_grpc_protector_test",
srcs = ["alts_zero_copy_grpc_protector_test.cc"],
external_deps = ["gtest"],
external_deps = [
"gtest",
"absl/types:span",
],
language = "C++",
deps = [
"//:gpr",

@ -18,13 +18,15 @@
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol.h"
#include <memory>
#include <gtest/gtest.h>
#include "absl/types/span.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gprpp/crash.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h"
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.h"
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
@ -124,8 +126,10 @@ test_fixture_integrity_only_create(bool rekey, bool extra_copy) {
// Create client record protocol for protect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_grpc_integrity_only_record_protocol_create(
crypter, 8, /*is_client=*/true, /*is_protect=*/true, extra_copy,
@ -133,8 +137,10 @@ test_fixture_integrity_only_create(bool rekey, bool extra_copy) {
TSI_OK);
// Create client record protocol for unprotect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_grpc_integrity_only_record_protocol_create(
crypter, 8, /*is_client=*/true, /*is_protect=*/false,
@ -142,8 +148,10 @@ test_fixture_integrity_only_create(bool rekey, bool extra_copy) {
TSI_OK);
// Create server record protocol for protect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_grpc_integrity_only_record_protocol_create(
crypter, 8, /*is_client=*/false, /*is_protect=*/true,
@ -151,8 +159,10 @@ test_fixture_integrity_only_create(bool rekey, bool extra_copy) {
TSI_OK);
// Create server record protocol for unprotect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_grpc_integrity_only_record_protocol_create(
crypter, 8, /*is_client=*/false, /*is_protect=*/false,
@ -190,8 +200,10 @@ test_fixture_privacy_integrity_create(bool rekey) {
// Create client record protocol for protect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_grpc_privacy_integrity_record_protocol_create(
crypter, 8, /*is_client=*/true, /*is_protect=*/true,
@ -199,8 +211,10 @@ test_fixture_privacy_integrity_create(bool rekey) {
TSI_OK);
// Create client record protocol for unprotect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_grpc_privacy_integrity_record_protocol_create(
crypter, 8, /*is_client=*/true, /*is_protect=*/false,
@ -208,8 +222,10 @@ test_fixture_privacy_integrity_create(bool rekey) {
TSI_OK);
// Create server record protocol for protect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_grpc_privacy_integrity_record_protocol_create(
crypter, 8, /*is_client=*/false, /*is_protect=*/true,
@ -217,8 +233,10 @@ test_fixture_privacy_integrity_create(bool rekey) {
TSI_OK);
// Create server record protocol for unprotect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_grpc_privacy_integrity_record_protocol_create(
crypter, 8, /*is_client=*/false, /*is_protect=*/false,

@ -18,12 +18,15 @@
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
#include <memory>
#include <gtest/gtest.h>
#include "absl/types/span.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gprpp/crash.h"
#include "test/core/tsi/alts/crypt/gsec_test_util.h"
constexpr size_t kMaxDataSize = 1024;
@ -106,39 +109,51 @@ alts_iovec_record_protocol_test_fixture_create(bool rekey,
gsec_aead_crypter* crypter = nullptr;
// Create client record protocol for protect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_iovec_record_protocol_create(
crypter, overflow_size, /*is_client=*/true, integrity_only,
/*is_protect=*/true, &fixture->client_protect, nullptr),
/*is_protect=*/true, &fixture->client_protect,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
// Create client record protocol for unprotect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_iovec_record_protocol_create(
crypter, overflow_size, /*is_client=*/true, integrity_only,
/*is_protect=*/false, &fixture->client_unprotect, nullptr),
/*is_protect=*/false, &fixture->client_unprotect,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
// Create server record protocol for protect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_iovec_record_protocol_create(
crypter, overflow_size, /*is_client=*/false, integrity_only,
/*is_protect=*/true, &fixture->server_protect, nullptr),
/*is_protect=*/true, &fixture->server_protect,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
// Create server record protocol for unprotect.
EXPECT_EQ(gsec_aes_gcm_aead_crypter_create(
key, key_length, kAesGcmNonceLength, kAesGcmTagLength, rekey,
&crypter, nullptr),
std::make_unique<grpc_core::GsecKey>(
absl::MakeConstSpan(key, key_length), rekey),
kAesGcmNonceLength, kAesGcmTagLength, &crypter,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
EXPECT_EQ(alts_iovec_record_protocol_create(
crypter, overflow_size, /*is_client=*/false, integrity_only,
/*is_protect=*/false, &fixture->server_unprotect, nullptr),
/*is_protect=*/false, &fixture->server_unprotect,
/*error_details=*/nullptr),
GRPC_STATUS_OK);
gpr_free(key);
return fixture;

@ -20,12 +20,12 @@
#include <gtest/gtest.h>
#include "absl/types/span.h"
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gprpp/crash.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/tsi/alts/crypt/gsec.h"
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"
#include "src/core/tsi/transport_security_grpc.h"
@ -116,16 +116,20 @@ alts_zero_copy_grpc_protector_test_fixture_create(bool rekey,
size_t actual_max_protected_frame_size;
gsec_test_random_array(&key, key_length);
EXPECT_EQ(alts_zero_copy_grpc_protector_create(
key, key_length, rekey, /*is_client=*/true, integrity_only,
enable_extra_copy, &max_protected_frame_size, &fixture->client),
grpc_core::GsecKeyFactory(absl::MakeConstSpan(key, key_length),
rekey),
/*is_client=*/true, integrity_only, enable_extra_copy,
&max_protected_frame_size, &fixture->client),
TSI_OK);
EXPECT_EQ(tsi_zero_copy_grpc_protector_max_frame_size(
fixture->client, &actual_max_protected_frame_size),
TSI_OK);
EXPECT_EQ(actual_max_protected_frame_size, max_protected_frame_size);
EXPECT_EQ(alts_zero_copy_grpc_protector_create(
key, key_length, rekey, /*is_client=*/false, integrity_only,
enable_extra_copy, &max_protected_frame_size, &fixture->server),
grpc_core::GsecKeyFactory(absl::MakeConstSpan(key, key_length),
rekey),
/*is_client=*/false, integrity_only, enable_extra_copy,
&max_protected_frame_size, &fixture->server),
TSI_OK);
EXPECT_EQ(tsi_zero_copy_grpc_protector_max_frame_size(
fixture->server, &actual_max_protected_frame_size),

Loading…
Cancel
Save