blob: 4d65caa944747987ff2da92facde4ad3200c880f [file] [log] [blame]
/*
*
* Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_TSI_ALTS_CRYPT_GSEC_H
#define GRPC_CORE_TSI_ALTS_CRYPT_GSEC_H
#include <grpc/support/port_platform.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <grpc/grpc.h>
struct iovec {
void* iov_base;
size_t iov_len;
};
/**
* 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;
const size_t kAesGcmTagLength = 16;
const size_t kAes128GcmKeyLength = 16;
const size_t kAes256GcmKeyLength = 32;
// The first 32 bytes are used as a KDF key and the remaining 12 bytes are used
// to mask the nonce.
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);
* -----------------------------------------------------------------------------
*/
/* V-table for gsec AEAD operations */
typedef struct gsec_aead_crypter_vtable {
grpc_status_code (*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);
grpc_status_code (*decrypt_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* ciphertext_vec, size_t ciphertext_vec_length,
struct iovec plaintext_vec, size_t* plaintext_bytes_written,
char** error_details);
grpc_status_code (*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);
grpc_status_code (*max_plaintext_length)(
const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length,
size_t* max_plaintext_length_to_return, char** error_details);
grpc_status_code (*nonce_length)(const gsec_aead_crypter* crypter,
size_t* nonce_length_to_return,
char** error_details);
grpc_status_code (*key_length)(const gsec_aead_crypter* crypter,
size_t* key_length_to_return,
char** error_details);
grpc_status_code (*tag_length)(const gsec_aead_crypter* crypter,
size_t* tag_length_to_return,
char** error_details);
void (*destruct)(gsec_aead_crypter* crypter);
} gsec_aead_crypter_vtable;
/* Main struct for gsec interface */
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).
*
*/
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,
size_t plaintext_length, uint8_t* ciphertext_and_tag,
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).
*
*/
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,
const struct iovec* plaintext_vec, size_t plaintext_vec_length,
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).
*/
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).
*/
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,
const struct iovec* ciphertext_vec, size_t ciphertext_vec_length,
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).
*/
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).
*/
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).
*/
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).
*/
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).
*/
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.
*/
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);
#endif /* GRPC_CORE_TSI_ALTS_CRYPT_GSEC_H */