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