1 // 2 // 3 // Copyright 2018 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // 17 // 18 19 #ifndef GRPC_SRC_CORE_TSI_ALTS_CRYPT_GSEC_H 20 #define GRPC_SRC_CORE_TSI_ALTS_CRYPT_GSEC_H 21 22 #include <grpc/support/port_platform.h> 23 24 #include <assert.h> 25 #include <stdint.h> 26 #include <stdlib.h> 27 28 #include <memory> 29 #include <vector> 30 31 #include "absl/types/span.h" 32 33 #include <grpc/event_engine/port.h> 34 #include <grpc/grpc.h> 35 36 namespace grpc_core { 37 38 // Provides accessors to all information representing a gsec key. Owns all the 39 // read-only or mutable buffers via the accessors. Mutable accessors such as 40 // `aead_key()` or `kdf_buffer()` are NOT thread-safe. 41 class GsecKeyInterface { 42 public: 43 virtual ~GsecKeyInterface() = default; 44 45 virtual bool IsRekey() = 0; 46 virtual absl::Span<const uint8_t> key() = 0; 47 48 // All the accessors below should only be called when IsRekey() is true. 49 virtual absl::Span<uint8_t> aead_key() = 0; 50 virtual absl::Span<const uint8_t> nonce_mask() = 0; 51 virtual absl::Span<uint8_t> kdf_counter() = 0; 52 virtual absl::Span<uint8_t> kdf_buffer() = 0; 53 }; 54 55 // Interface for a GsecKey factory. 56 class GsecKeyFactoryInterface { 57 public: 58 virtual ~GsecKeyFactoryInterface() = default; 59 60 // Creates identical and independent GsecKeyInterface objects. 61 virtual std::unique_ptr<GsecKeyInterface> Create() const = 0; 62 }; 63 64 class GsecKeyFactory : public GsecKeyFactoryInterface { 65 public: 66 // The exact given parameters will be used to create GsecKey objects. 67 GsecKeyFactory(absl::Span<const uint8_t> key, bool is_rekey); 68 ~GsecKeyFactory() override = default; 69 70 std::unique_ptr<GsecKeyInterface> Create() const override; 71 72 private: 73 std::vector<uint8_t> key_; 74 bool is_rekey_; 75 }; 76 77 class GsecKey : public GsecKeyInterface { 78 public: 79 // If `is_rekey` is false, the given key will be copied as the symmetric key. 80 // Otherwise, part of the given key is copied as the KDF key and another part 81 // is copied as the nonce mask. 82 GsecKey(absl::Span<const uint8_t> key, bool is_rekey); 83 ~GsecKey() override = default; 84 85 bool IsRekey() override; 86 absl::Span<const uint8_t> key() override; 87 absl::Span<uint8_t> aead_key() override; 88 absl::Span<const uint8_t> nonce_mask() override; 89 absl::Span<uint8_t> kdf_counter() override; 90 absl::Span<uint8_t> kdf_buffer() override; 91 92 private: 93 bool is_rekey_; 94 std::vector<uint8_t> key_; 95 std::vector<uint8_t> aead_key_; 96 std::vector<uint8_t> kdf_buffer_; 97 std::vector<uint8_t> nonce_mask_; 98 std::vector<uint8_t> kdf_counter_; 99 }; 100 101 } // namespace grpc_core 102 103 #ifndef _STRUCT_IOVEC 104 #if !defined(GRPC_EVENT_ENGINE_POSIX) 105 struct iovec { 106 void* iov_base; 107 size_t iov_len; 108 }; 109 #endif // GRPC_EVENT_ENGINE_POSIX 110 #endif // _STRUCT_IOVEC 111 112 // 113 // A gsec interface for AEAD encryption schemes. The API is thread-compatible. 114 // Each implementation of this interface should specify supported values for 115 // key, nonce, and tag lengths. 116 // 117 118 // Key, nonce, and tag length in bytes 119 const size_t kAesGcmNonceLength = 12; 120 const size_t kAesGcmTagLength = 16; 121 const size_t kAes128GcmKeyLength = 16; 122 const size_t kAes256GcmKeyLength = 32; 123 124 // The first 32 bytes are used as a KDF key and the remaining 12 bytes are used 125 // to mask the nonce. 126 const size_t kAes128GcmRekeyKeyLength = 44; 127 128 typedef struct gsec_aead_crypter gsec_aead_crypter; 129 130 // 131 // The gsec_aead_crypter is an API for different AEAD implementations such as 132 // AES_GCM. It encapsulates all AEAD-related operations in the format of 133 // V-table that stores pointers to functions implementing those operations. 134 // It also provides helper functions to wrap each of those function pointers. 135 // 136 // A typical usage of this object would be: 137 // 138 //------------------------------------------------------------------------------ 139 //// Declare a gsec_aead_crypter object, and create and assign an instance 140 //// of specific AEAD implementation e.g., AES_GCM to it. We assume both 141 //// key and nonce contain cryptographically secure random bytes, and the key 142 //// can be derived from an upper-layer application. 143 // gsec_aead_crypter* crypter; 144 // char* error_in_creation; 145 //// User can populate the message with any 100 bytes data. 146 // uint8_t* message = gpr_malloc(100); 147 // grpc_status_code creation_status = gsec_aes_gcm_aead_crypter_create(key, 148 // kAes128GcmKeyLength, 149 // kAesGcmNonceLength, 150 // kAesGcmTagLength, 151 // &crypter, 152 // false, 153 // 0 154 // &error_in_creation); 155 // 156 // if (creation_status == GRPC_STATUS_OK) { 157 // // Allocate a correct amount of memory to hold a ciphertext. 158 // size_t clength = 0; 159 // gsec_aead_crypter_max_ciphertext_and_tag_length(crypter, 100, &clength, 160 // nullptr); 161 // uint8_t* ciphertext = gpr_malloc(clength); 162 // 163 // // Perform encryption 164 // size_t num_encrypted_bytes = 0; 165 // char* error_in_encryption = nullptr; 166 // grpc_status_code status = gsec_aead_crypter_encrypt(crypter, nonce, 167 // kAesGcmNonceLength, 168 // nullptr, 0, message, 169 // 100, ciphertext, 170 // clength, 171 // &num_encrypted_bytes, 172 // &error_in_encryption); 173 // if (status == GRPC_STATUS_OK) { 174 // // Allocate a correct amount of memory to hold a plaintext. 175 // size_t plength = 0; 176 // gsec_aead_crypter_max_plaintext_length(crypter, num_encrypted_bytes, 177 // &plength, nullptr); 178 // uint8_t* plaintext = gpr_malloc(plength); 179 // 180 // // Perform decryption. 181 // size_t num_decrypted_bytes = 0; 182 // char* error_in_decryption = nullptr; 183 // status = gsec_aead_crypter_decrypt(crypter, nonce, 184 // kAesGcmNonceLength, nullptr, 0, 185 // ciphertext, num_encrypted_bytes, 186 // plaintext, plength, 187 // &num_decrypted_bytes, 188 // &error_in_decryption); 189 // if (status != GRPC_STATUS_OK) { 190 // fprintf(stderr, "AEAD decrypt operation failed with error code:" 191 // "%d, message: %s\n", status, error_in_decryption); 192 // } 193 // ... 194 // gpr_free(plaintext); 195 // gpr_free(error_in_decryption); 196 // } else { 197 // fprintf(stderr, "AEAD encrypt operation failed with error code:" 198 // "%d, message: %s\n", status, error_in_encryption); 199 // } 200 // ... 201 // gpr_free(ciphertext); 202 // gpr_free(error_in_encryption); 203 //} else { 204 // fprintf(stderr, "Creation of AEAD crypter instance failed with error code:" 205 // "%d, message: %s\n", creation_status, error_in_creation); 206 //} 207 // 208 //// Destruct AEAD crypter instance. 209 // if (creation_status == GRPC_STATUS_OK) { 210 // gsec_aead_crypter_destroy(crypter); 211 //} 212 // gpr_free(error_in_creation); 213 // gpr_free(message); 214 //----------------------------------------------------------------------------- 215 // 216 217 // V-table for gsec AEAD operations 218 typedef struct gsec_aead_crypter_vtable { 219 grpc_status_code (*encrypt_iovec)( 220 gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, 221 const struct iovec* aad_vec, size_t aad_vec_length, 222 const struct iovec* plaintext_vec, size_t plaintext_vec_length, 223 struct iovec ciphertext_vec, size_t* ciphertext_bytes_written, 224 char** error_details); 225 grpc_status_code (*decrypt_iovec)( 226 gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, 227 const struct iovec* aad_vec, size_t aad_vec_length, 228 const struct iovec* ciphertext_vec, size_t ciphertext_vec_length, 229 struct iovec plaintext_vec, size_t* plaintext_bytes_written, 230 char** error_details); 231 grpc_status_code (*max_ciphertext_and_tag_length)( 232 const gsec_aead_crypter* crypter, size_t plaintext_length, 233 size_t* max_ciphertext_and_tag_length_to_return, char** error_details); 234 grpc_status_code (*max_plaintext_length)( 235 const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length, 236 size_t* max_plaintext_length_to_return, char** error_details); 237 grpc_status_code (*nonce_length)(const gsec_aead_crypter* crypter, 238 size_t* nonce_length_to_return, 239 char** error_details); 240 grpc_status_code (*key_length)(const gsec_aead_crypter* crypter, 241 size_t* key_length_to_return, 242 char** error_details); 243 grpc_status_code (*tag_length)(const gsec_aead_crypter* crypter, 244 size_t* tag_length_to_return, 245 char** error_details); 246 void (*destruct)(gsec_aead_crypter* crypter); 247 } gsec_aead_crypter_vtable; 248 249 // Main struct for gsec interface 250 struct gsec_aead_crypter { 251 const struct gsec_aead_crypter_vtable* vtable; 252 }; 253 254 // 255 // This method performs an AEAD encrypt operation. 256 // 257 //- crypter: AEAD crypter instance. 258 //- nonce: buffer containing a nonce with its size equal to nonce_length. 259 //- nonce_length: size of nonce buffer, and must be equal to the value returned 260 // from method gsec_aead_crypter_nonce_length. 261 //- aad: buffer containing data that needs to be authenticated but not 262 // encrypted with its size equal to aad_length. 263 //- aad_length: size of aad buffer, which should be zero if the buffer is 264 // nullptr. 265 //- plaintext: buffer containing data that needs to be both encrypted and 266 // authenticated with its size equal to plaintext_length. 267 //- plaintext_length: size of plaintext buffer, which should be zero if 268 // plaintext is nullptr. 269 //- ciphertext_and_tag: buffer that will contain ciphertext and tags the method 270 // produced. The buffer should not overlap the plaintext buffer, and pointers 271 // to those buffers should not be equal. Also if the ciphertext+tag buffer is 272 // nullptr, the plaintext_length should be zero. 273 //- ciphertext_and_tag_length: size of ciphertext+tag buffer, which should be 274 // at least as long as the one returned from method 275 // gsec_aead_crypter_max_ciphertext_and_tag_length. 276 //- bytes_written: the actual number of bytes written to the ciphertext+tag 277 // buffer. If bytes_written is nullptr, the plaintext_length should be zero. 278 //- error_details: a buffer containing an error message if the method does not 279 // function correctly. It is legal to pass nullptr into error_details, and 280 // otherwise, the parameter should be freed with gpr_free. 281 // 282 // On the success of encryption, the method returns GRPC_STATUS_OK. Otherwise, 283 // it returns an error status code along with its details specified in 284 // error_details (if error_details is not nullptr). 285 // 286 // 287 grpc_status_code gsec_aead_crypter_encrypt( 288 gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, 289 const uint8_t* aad, size_t aad_length, const uint8_t* plaintext, 290 size_t plaintext_length, uint8_t* ciphertext_and_tag, 291 size_t ciphertext_and_tag_length, size_t* bytes_written, 292 char** error_details); 293 294 // 295 // This method performs an AEAD encrypt operation. 296 // 297 //- crypter: AEAD crypter instance. 298 //- nonce: buffer containing a nonce with its size equal to nonce_length. 299 //- nonce_length: size of nonce buffer, and must be equal to the value returned 300 // from method gsec_aead_crypter_nonce_length. 301 //- aad_vec: an iovec array containing data that needs to be authenticated but 302 // not encrypted. 303 //- aad_vec_length: the array length of aad_vec. 304 //- plaintext_vec: an iovec array containing data that needs to be both 305 // encrypted and authenticated. 306 //- plaintext_vec_length: the array length of plaintext_vec. 307 //- ciphertext_vec: an iovec containing a ciphertext buffer. The buffer should 308 // not overlap the plaintext buffer. 309 //- ciphertext_bytes_written: the actual number of bytes written to 310 // ciphertext_vec. 311 //- error_details: a buffer containing an error message if the method does not 312 // function correctly. It is legal to pass nullptr into error_details, and 313 // otherwise, the parameter should be freed with gpr_free. 314 // 315 // On the success of encryption, the method returns GRPC_STATUS_OK. Otherwise, 316 // it returns an error status code along with its details specified in 317 // error_details (if error_details is not nullptr). 318 // 319 // 320 grpc_status_code gsec_aead_crypter_encrypt_iovec( 321 gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, 322 const struct iovec* aad_vec, size_t aad_vec_length, 323 const struct iovec* plaintext_vec, size_t plaintext_vec_length, 324 struct iovec ciphertext_vec, size_t* ciphertext_bytes_written, 325 char** error_details); 326 327 // 328 // This method performs an AEAD decrypt operation. 329 // 330 //- crypter: AEAD crypter instance. 331 //- nonce: buffer containing a nonce with its size equal to nonce_length. 332 //- nonce_length: size of nonce buffer, and must be equal to the value returned 333 // from method gsec_aead_crypter_nonce_length. 334 //- aad: buffer containing data that needs to be authenticated only. 335 //- aad_length: size of aad buffer, which should be zero if the buffer is 336 // nullptr. 337 //- ciphertext_and_tag: buffer containing ciphertext and tag. 338 //- ciphertext_and_tag_length: length of ciphertext and tag. It should be zero 339 // if any of plaintext, ciphertext_and_tag, or bytes_written is nullptr. Also, 340 // ciphertext_and_tag_length should be at least as large as the tag length set 341 // at AEAD crypter instance construction time. 342 //- plaintext: buffer containing decrypted and authenticated data the method 343 // produced. The buffer should not overlap with the ciphertext+tag buffer, and 344 // pointers to those buffers should not be equal. 345 //- plaintext_length: size of plaintext buffer, which should be at least as 346 // long as the one returned from gsec_aead_crypter_max_plaintext_length 347 // method. 348 //- bytes_written: the actual number of bytes written to the plaintext 349 // buffer. 350 //- error_details: a buffer containing an error message if the method does not 351 // function correctly. It is legal to pass nullptr into error_details, and 352 // otherwise, the parameter should be freed with gpr_free. 353 // 354 // On the success of decryption, the method returns GRPC_STATUS_OK. Otherwise, 355 // it returns an error status code along with its details specified in 356 // error_details (if error_details is not nullptr). 357 // 358 grpc_status_code gsec_aead_crypter_decrypt( 359 gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, 360 const uint8_t* aad, size_t aad_length, const uint8_t* ciphertext_and_tag, 361 size_t ciphertext_and_tag_length, uint8_t* plaintext, 362 size_t plaintext_length, size_t* bytes_written, char** error_details); 363 364 // 365 // This method performs an AEAD decrypt operation. 366 // 367 //- crypter: AEAD crypter instance. 368 //- nonce: buffer containing a nonce with its size equal to nonce_length. 369 //- nonce_length: size of nonce buffer, and must be equal to the value returned 370 // from method gsec_aead_crypter_nonce_length. 371 //- aad_vec: an iovec array containing data that needs to be authenticated but 372 // not encrypted. 373 //- aad_vec_length: the array length of aad_vec. 374 //- ciphertext_vec: an iovec array containing the ciphertext and tag. 375 //- ciphertext_vec_length: the array length of ciphertext_vec. 376 //- plaintext_vec: an iovec containing a plaintext buffer. The buffer should 377 // not overlap the ciphertext buffer. 378 //- plaintext_bytes_written: the actual number of bytes written to 379 // plaintext_vec. 380 //- error_details: a buffer containing an error message if the method does not 381 // function correctly. It is legal to pass nullptr into error_details, and 382 // otherwise, the parameter should be freed with gpr_free. 383 // 384 // On the success of decryption, the method returns GRPC_STATUS_OK. Otherwise, 385 // it returns an error status code along with its details specified in 386 // error_details (if error_details is not nullptr). 387 // 388 grpc_status_code gsec_aead_crypter_decrypt_iovec( 389 gsec_aead_crypter* crypter, const uint8_t* nonce, size_t nonce_length, 390 const struct iovec* aad_vec, size_t aad_vec_length, 391 const struct iovec* ciphertext_vec, size_t ciphertext_vec_length, 392 struct iovec plaintext_vec, size_t* plaintext_bytes_written, 393 char** error_details); 394 395 // 396 // This method computes the size of ciphertext+tag buffer that must be passed 397 // to gsec_aead_crypter_encrypt function to ensure correct encryption of a 398 // plaintext. The actual size of ciphertext+tag written to the buffer could be 399 // smaller. 400 // 401 //- crypter: AEAD crypter instance. 402 //- plaintext_length: length of plaintext. 403 //- max_ciphertext_and_tag_length_to_return: the size of ciphertext+tag buffer 404 // the method returns. 405 //- error_details: a buffer containing an error message if the method does not 406 // function correctly. It is legal to pass nullptr into error_details, and 407 // otherwise, the parameter should be freed with gpr_free. 408 // 409 // On the success of execution, the method returns GRPC_STATUS_OK. Otherwise, 410 // it returns an error status code along with its details specified in 411 // error_details (if error_details is not nullptr). 412 // 413 grpc_status_code gsec_aead_crypter_max_ciphertext_and_tag_length( 414 const gsec_aead_crypter* crypter, size_t plaintext_length, 415 size_t* max_ciphertext_and_tag_length_to_return, char** error_details); 416 417 // 418 // This method computes the size of plaintext buffer that must be passed to 419 // gsec_aead_crypter_decrypt function to ensure correct decryption of a 420 // ciphertext. The actual size of plaintext written to the buffer could be 421 // smaller. 422 // 423 //- crypter: AEAD crypter instance. 424 //- ciphertext_and_tag_length: length of ciphertext and tag. 425 //- max_plaintext_length_to_return: the size of plaintext buffer the method 426 // returns. 427 //- error_details: a buffer containing an error message if the method does not 428 // function correctly. It is legal to pass nullptr into error_details, and 429 // otherwise, the parameter should be freed with gpr_free. 430 // 431 // On the success of execution, the method returns GRPC_STATUS_OK. Otherwise, 432 // it returns an error status code along with its details specified in 433 // error_details (if error_details is not nullptr). 434 // 435 grpc_status_code gsec_aead_crypter_max_plaintext_length( 436 const gsec_aead_crypter* crypter, size_t ciphertext_and_tag_length, 437 size_t* max_plaintext_length_to_return, char** error_details); 438 439 // 440 // This method returns a valid size of nonce array used at the construction of 441 // AEAD crypter instance. It is also the size that should be passed to encrypt 442 // and decrypt methods executed on the instance. 443 // 444 //- crypter: AEAD crypter instance. 445 //- nonce_length_to_return: the length of nonce array the method returns. 446 //- error_details: a buffer containing an error message if the method does not 447 // function correctly. It is legal to pass nullptr into error_details, and 448 // otherwise, the parameter should be freed with gpr_free. 449 // 450 // On the success of execution, the method returns GRPC_STATUS_OK. Otherwise, 451 // it returns an error status code along with its details specified in 452 // error_details (if error_details is not nullptr). 453 // 454 grpc_status_code gsec_aead_crypter_nonce_length( 455 const gsec_aead_crypter* crypter, size_t* nonce_length_to_return, 456 char** error_details); 457 458 // 459 // This method returns a valid size of key array used at the construction of 460 // AEAD crypter instance. It is also the size that should be passed to encrypt 461 // and decrypt methods executed on the instance. 462 // 463 //- crypter: AEAD crypter instance. 464 //- key_length_to_return: the length of key array the method returns. 465 //- error_details: a buffer containing an error message if the method does not 466 // function correctly. It is legal to pass nullptr into error_details, and 467 // otherwise, the parameter should be freed with gpr_free. 468 // 469 // On the success of execution, the method returns GRPC_STATUS_OK. Otherwise, 470 // it returns an error status code along with its details specified in 471 // error_details (if error_details is not nullptr). 472 // 473 grpc_status_code gsec_aead_crypter_key_length(const gsec_aead_crypter* crypter, 474 size_t* key_length_to_return, 475 char** error_details); 476 // 477 // This method returns a valid size of tag array used at the construction of 478 // AEAD crypter instance. It is also the size that should be passed to encrypt 479 // and decrypt methods executed on the instance. 480 // 481 //- crypter: AEAD crypter instance. 482 //- tag_length_to_return: the length of tag array the method returns. 483 //- error_details: a buffer containing an error message if the method does not 484 // function correctly. It is legal to pass nullptr into error_details, and 485 // otherwise, the parameter should be freed with gpr_free. 486 // 487 // On the success of execution, the method returns GRPC_STATUS_OK. Otherwise, 488 // it returns an error status code along with its details specified in 489 // error_details (if error_details is not nullptr). 490 // 491 grpc_status_code gsec_aead_crypter_tag_length(const gsec_aead_crypter* crypter, 492 size_t* tag_length_to_return, 493 char** error_details); 494 495 // 496 // This method destroys an AEAD crypter instance by de-allocating all of its 497 // occupied memory. 498 // 499 //- crypter: AEAD crypter instance that needs to be destroyed. 500 // 501 void gsec_aead_crypter_destroy(gsec_aead_crypter* crypter); 502 503 // 504 // This method creates an AEAD crypter instance of AES-GCM encryption scheme 505 // which supports 16 and 32 bytes long keys, 12 and 16 bytes long nonces, and 506 // 16 bytes long tags. It should be noted that once the lengths of key, nonce, 507 // and tag are determined at construction time, they cannot be modified later. 508 // 509 //- key: an instance of GsecKeyInterface, which will provide accessors to the 510 // key, aead_key, kdf_counter, nonce_mask as well as the buffer for aead_key 511 // derivation. It also tells whether rekey is supported. 512 //- nonce_length: length of a nonce in bytes, which should be either 12 or 16. 513 //- tag_length: length of a tag in bytes, which should be always 16. 514 //- crypter: address of AES_GCM crypter instance returned from the method. 515 //- error_details: a buffer containing an error message if the method does not 516 // function correctly. It is legal to pass nullptr into error_details, and 517 // otherwise, the parameter should be freed with gpr_free. 518 // 519 // On success of instance creation, it stores the address of instance at 520 // crypter. Otherwise, it returns an error status code together with its 521 // details specified in error_details. 522 // 523 grpc_status_code gsec_aes_gcm_aead_crypter_create( 524 std::unique_ptr<grpc_core::GsecKeyInterface> key, size_t nonce_length, 525 size_t tag_length, gsec_aead_crypter** crypter, char** error_details); 526 527 #endif // GRPC_SRC_CORE_TSI_ALTS_CRYPT_GSEC_H 528