xref: /aosp_15_r20/external/grpc-grpc/src/core/tsi/alts/crypt/gsec.h (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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