• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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