in src/core/tsi/alts/crypt/aes_gcm.cc [246:382]
static grpc_status_code gsec_aes_gcm_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,
const struct iovec* plaintext_vec, size_t plaintext_vec_length,
struct iovec ciphertext_vec, size_t* ciphertext_bytes_written,
char** error_details) {
gsec_aes_gcm_aead_crypter* aes_gcm_crypter =
reinterpret_cast<gsec_aes_gcm_aead_crypter*>(crypter);
// Input checks
if (nonce == nullptr) {
aes_gcm_format_errors("Nonce buffer is nullptr.", error_details);
return GRPC_STATUS_INVALID_ARGUMENT;
}
if (kAesGcmNonceLength != nonce_length) {
aes_gcm_format_errors("Nonce buffer has the wrong length.", error_details);
return GRPC_STATUS_INVALID_ARGUMENT;
}
if (aad_vec_length > 0 && aad_vec == nullptr) {
aes_gcm_format_errors("Non-zero aad_vec_length but aad_vec is nullptr.",
error_details);
return GRPC_STATUS_INVALID_ARGUMENT;
}
if (plaintext_vec_length > 0 && plaintext_vec == nullptr) {
aes_gcm_format_errors(
"Non-zero plaintext_vec_length but plaintext_vec is nullptr.",
error_details);
return GRPC_STATUS_INVALID_ARGUMENT;
}
if (ciphertext_bytes_written == nullptr) {
aes_gcm_format_errors("bytes_written is nullptr.", error_details);
return GRPC_STATUS_INVALID_ARGUMENT;
}
*ciphertext_bytes_written = 0;
// rekey if required
if (aes_gcm_rekey_if_required(aes_gcm_crypter, nonce, error_details) !=
GRPC_STATUS_OK) {
return GRPC_STATUS_INTERNAL;
}
// 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);
nonce_aead = nonce_masked;
}
// init openssl context
if (!EVP_EncryptInit_ex(aes_gcm_crypter->ctx, nullptr, nullptr, nullptr,
nonce_aead)) {
aes_gcm_format_errors("Initializing nonce failed", error_details);
return GRPC_STATUS_INTERNAL;
}
// process aad
size_t i;
for (i = 0; i < aad_vec_length; i++) {
const uint8_t* aad = static_cast<uint8_t*>(aad_vec[i].iov_base);
size_t aad_length = aad_vec[i].iov_len;
if (aad_length == 0) {
continue;
}
size_t aad_bytes_read = 0;
if (aad == nullptr) {
aes_gcm_format_errors("aad is nullptr.", error_details);
return GRPC_STATUS_INVALID_ARGUMENT;
}
if (!EVP_EncryptUpdate(aes_gcm_crypter->ctx, nullptr,
reinterpret_cast<int*>(&aad_bytes_read), aad,
static_cast<int>(aad_length)) ||
aad_bytes_read != aad_length) {
aes_gcm_format_errors("Setting authenticated associated data failed",
error_details);
return GRPC_STATUS_INTERNAL;
}
}
uint8_t* ciphertext = static_cast<uint8_t*>(ciphertext_vec.iov_base);
size_t ciphertext_length = ciphertext_vec.iov_len;
if (ciphertext == nullptr) {
aes_gcm_format_errors("ciphertext is nullptr.", error_details);
return GRPC_STATUS_INVALID_ARGUMENT;
}
// process plaintext
for (i = 0; i < plaintext_vec_length; i++) {
const uint8_t* plaintext = static_cast<uint8_t*>(plaintext_vec[i].iov_base);
size_t plaintext_length = plaintext_vec[i].iov_len;
if (plaintext == nullptr) {
if (plaintext_length == 0) {
continue;
}
aes_gcm_format_errors("plaintext is nullptr.", error_details);
return GRPC_STATUS_INVALID_ARGUMENT;
}
if (ciphertext_length < plaintext_length) {
aes_gcm_format_errors(
"ciphertext is not large enough to hold the result.", error_details);
return GRPC_STATUS_INVALID_ARGUMENT;
}
int bytes_written = 0;
int bytes_to_write = static_cast<int>(plaintext_length);
if (!EVP_EncryptUpdate(aes_gcm_crypter->ctx, ciphertext, &bytes_written,
plaintext, bytes_to_write)) {
aes_gcm_format_errors("Encrypting plaintext failed.", error_details);
return GRPC_STATUS_INTERNAL;
}
if (bytes_written > bytes_to_write) {
aes_gcm_format_errors("More bytes written than expected.", error_details);
return GRPC_STATUS_INTERNAL;
}
ciphertext += bytes_written;
ciphertext_length -= bytes_written;
}
int bytes_written_temp = 0;
if (!EVP_EncryptFinal_ex(aes_gcm_crypter->ctx, nullptr,
&bytes_written_temp)) {
aes_gcm_format_errors("Finalizing encryption failed.", error_details);
return GRPC_STATUS_INTERNAL;
}
if (bytes_written_temp != 0) {
aes_gcm_format_errors("Openssl wrote some unexpected bytes.",
error_details);
return GRPC_STATUS_INTERNAL;
}
if (ciphertext_length < kAesGcmTagLength) {
aes_gcm_format_errors("ciphertext is too small to hold a tag.",
error_details);
return GRPC_STATUS_INVALID_ARGUMENT;
}
if (!EVP_CIPHER_CTX_ctrl(aes_gcm_crypter->ctx, EVP_CTRL_GCM_GET_TAG,
kAesGcmTagLength, ciphertext)) {
aes_gcm_format_errors("Writing tag failed.", error_details);
return GRPC_STATUS_INTERNAL;
}
ciphertext += kAesGcmTagLength;
ciphertext_length -= kAesGcmTagLength;
*ciphertext_bytes_written = ciphertext_vec.iov_len - ciphertext_length;
return GRPC_STATUS_OK;
}