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