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