/* * * 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 #include #include #include #include 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 */