1+ /**
2+ * @file lt_openssl_aesgcm.c
3+ * @copyright Copyright (c) 2020-2025 Tropic Square s.r.o.
4+ *
5+ * @license For the license see LICENSE.md in the root directory of this source tree.
6+ */
7+
8+ #include <inttypes.h>
9+ #include <openssl/err.h>
10+ #include <openssl/evp.h>
11+ #include <stdint.h>
12+ #include <stdlib.h>
13+ #include <string.h>
14+
15+ #include "libtropic_common.h"
16+ #include "libtropic_logging.h"
17+ #include "libtropic_openssl.h"
18+ #include "lt_aesgcm.h"
19+
20+ lt_ret_t lt_aesgcm_encrypt_init (void * ctx , const uint8_t * key , const uint32_t key_len )
21+ {
22+ if (key_len != TR01_AES256_KEY_LEN ) {
23+ LT_LOG_ERROR ("Invalid AES-GCM key length: got %" PRIu32 " bytes, expected %d bytes" , key_len ,
24+ TR01_AES256_KEY_LEN );
25+ return LT_PARAM_ERR ;
26+ }
27+
28+ lt_ctx_openssl_t * _ctx = (lt_ctx_openssl_t * )ctx ;
29+ unsigned long err_code ;
30+
31+ // Initialize AES-GCM encryption context.
32+ _ctx -> aesgcm_encrypt_ctx = EVP_CIPHER_CTX_new ();
33+ if (!_ctx -> aesgcm_encrypt_ctx ) {
34+ err_code = ERR_get_error ();
35+ LT_LOG_ERROR ("Failed to allocate AES-GCM encryption context, err_code=%lu (%s)" , err_code ,
36+ ERR_error_string (err_code , NULL ));
37+ return LT_CRYPTO_ERR ;
38+ }
39+
40+ // Set cipher type.
41+ if (!EVP_EncryptInit_ex (_ctx -> aesgcm_encrypt_ctx , EVP_aes_256_gcm (), NULL , NULL , NULL )) {
42+ err_code = ERR_get_error ();
43+ LT_LOG_ERROR ("Failed to initialize AES-GCM encryption context with cipher type, err_code=%lu (%s)" , err_code ,
44+ ERR_error_string (err_code , NULL ));
45+ return LT_CRYPTO_ERR ;
46+ }
47+
48+ // Set IV length.
49+ if (!EVP_CIPHER_CTX_ctrl (_ctx -> aesgcm_encrypt_ctx , EVP_CTRL_GCM_SET_IVLEN , TR01_L3_IV_SIZE , NULL )) {
50+ err_code = ERR_get_error ();
51+ LT_LOG_ERROR ("Failed to initialize AES-GCM encryption context with IV length, err_code=%lu (%s)" , err_code ,
52+ ERR_error_string (err_code , NULL ));
53+ return LT_CRYPTO_ERR ;
54+ }
55+
56+ // Set encryption key.
57+ if (!EVP_EncryptInit_ex (_ctx -> aesgcm_encrypt_ctx , NULL , NULL , key , NULL )) {
58+ err_code = ERR_get_error ();
59+ LT_LOG_ERROR ("Failed to initialize AES-GCM encryption context with key, err_code=%lu (%s)" , err_code ,
60+ ERR_error_string (err_code , NULL ));
61+ return LT_CRYPTO_ERR ;
62+ }
63+
64+ return LT_OK ;
65+ }
66+
67+ lt_ret_t lt_aesgcm_decrypt_init (void * ctx , const uint8_t * key , const uint32_t key_len )
68+ {
69+ if (key_len != TR01_AES256_KEY_LEN ) {
70+ LT_LOG_ERROR ("Invalid AES-GCM key length: got %" PRIu32 " bytes, expected %d bytes" , key_len ,
71+ TR01_AES256_KEY_LEN );
72+ return LT_PARAM_ERR ;
73+ }
74+
75+ lt_ctx_openssl_t * _ctx = (lt_ctx_openssl_t * )ctx ;
76+ unsigned long err_code ;
77+
78+ // Initialize AES-GCM decryption context.
79+ _ctx -> aesgcm_decrypt_ctx = EVP_CIPHER_CTX_new ();
80+ if (!_ctx -> aesgcm_decrypt_ctx ) {
81+ err_code = ERR_get_error ();
82+ LT_LOG_ERROR ("Failed to allocate AES-GCM decryption context, err_code=%lu (%s)" , err_code ,
83+ ERR_error_string (err_code , NULL ));
84+ return LT_CRYPTO_ERR ;
85+ }
86+
87+ // Set cipher type.
88+ if (!EVP_DecryptInit_ex (_ctx -> aesgcm_decrypt_ctx , EVP_aes_256_gcm (), NULL , NULL , NULL )) {
89+ err_code = ERR_get_error ();
90+ LT_LOG_ERROR ("Failed to initialize AES-GCM decryption context with cipher type, err_code=%lu (%s)" , err_code ,
91+ ERR_error_string (err_code , NULL ));
92+ return LT_CRYPTO_ERR ;
93+ }
94+
95+ // Set IV length.
96+ if (!EVP_CIPHER_CTX_ctrl (_ctx -> aesgcm_decrypt_ctx , EVP_CTRL_GCM_SET_IVLEN , TR01_L3_IV_SIZE , NULL )) {
97+ err_code = ERR_get_error ();
98+ LT_LOG_ERROR ("Failed to initialize AES-GCM decryption context with IV length, err_code=%lu (%s)" , err_code ,
99+ ERR_error_string (err_code , NULL ));
100+ return LT_CRYPTO_ERR ;
101+ }
102+
103+ // Set decryption key.
104+ if (!EVP_DecryptInit_ex (_ctx -> aesgcm_decrypt_ctx , NULL , NULL , key , NULL )) {
105+ err_code = ERR_get_error ();
106+ LT_LOG_ERROR ("Failed to initialize AES-GCM decryption context with key, err_code=%lu (%s)" , err_code ,
107+ ERR_error_string (err_code , NULL ));
108+ return LT_CRYPTO_ERR ;
109+ }
110+
111+ return LT_OK ;
112+ }
113+
114+ lt_ret_t lt_aesgcm_encrypt (void * ctx , const uint8_t * iv , const uint32_t iv_len , const uint8_t * add ,
115+ const uint32_t add_len , const uint8_t * plaintext , const uint32_t plaintext_len ,
116+ uint8_t * ciphertext , const uint32_t ciphertext_len )
117+ {
118+ if (iv_len != TR01_L3_IV_SIZE ) {
119+ LT_LOG_ERROR ("Invalid AES-GCM IV length: got %" PRIu32 " bytes, expected %d bytes" , iv_len , TR01_L3_IV_SIZE );
120+ return LT_PARAM_ERR ;
121+ }
122+
123+ lt_ctx_openssl_t * _ctx = (lt_ctx_openssl_t * )ctx ;
124+ unsigned long err_code ;
125+ int out_len ;
126+
127+ // Set IV.
128+ if (!EVP_EncryptInit_ex (_ctx -> aesgcm_encrypt_ctx , NULL , NULL , NULL , iv )) {
129+ err_code = ERR_get_error ();
130+ LT_LOG_ERROR ("Failed to set AES-GCM encryption IV, err_code=%lu (%s)" , err_code ,
131+ ERR_error_string (err_code , NULL ));
132+ return LT_CRYPTO_ERR ;
133+ }
134+
135+ // Process AAD (Additional Authenticated Data).
136+ if (!EVP_EncryptUpdate (_ctx -> aesgcm_encrypt_ctx , NULL , & out_len , add , (int )add_len )) {
137+ err_code = ERR_get_error ();
138+ LT_LOG_ERROR ("Failed to process AES-GCM AAD, err_code=%lu (%s)" , err_code , ERR_error_string (err_code , NULL ));
139+ return LT_CRYPTO_ERR ;
140+ }
141+
142+ // Encrypt plaintext.
143+ if (!EVP_EncryptUpdate (_ctx -> aesgcm_encrypt_ctx , ciphertext , & out_len , plaintext , (int )plaintext_len )) {
144+ err_code = ERR_get_error ();
145+ LT_LOG_ERROR ("Failed to encrypt AES-GCM plaintext, err_code=%lu (%s)" , err_code ,
146+ ERR_error_string (err_code , NULL ));
147+ return LT_CRYPTO_ERR ;
148+ }
149+
150+ // Check that all plaintext data was processed.
151+ if (out_len != (int )(ciphertext_len - TR01_L3_TAG_SIZE )) {
152+ LT_LOG_ERROR ("AES-GCM encryption length mismatch! Current: %d bytes, expected: %" PRIu32 " bytes" , out_len ,
153+ ciphertext_len - TR01_L3_TAG_SIZE );
154+ return LT_CRYPTO_ERR ;
155+ }
156+
157+ // Finalize encryption.
158+ if (!EVP_EncryptFinal_ex (_ctx -> aesgcm_encrypt_ctx , ciphertext + out_len , & out_len )) {
159+ err_code = ERR_get_error ();
160+ LT_LOG_ERROR ("Failed to finalize AES-GCM encryption, err_code=%lu (%s)" , err_code ,
161+ ERR_error_string (err_code , NULL ));
162+ return LT_CRYPTO_ERR ;
163+ }
164+
165+ // Get the tag.
166+ if (!EVP_CIPHER_CTX_ctrl (_ctx -> aesgcm_encrypt_ctx , EVP_CTRL_GCM_GET_TAG , TR01_L3_TAG_SIZE ,
167+ ciphertext + plaintext_len )) {
168+ err_code = ERR_get_error ();
169+ LT_LOG_ERROR ("Failed to get AES-GCM encryption tag, err_code=%lu (%s)" , err_code ,
170+ ERR_error_string (err_code , NULL ));
171+ return LT_CRYPTO_ERR ;
172+ }
173+
174+ return LT_OK ;
175+ }
176+
177+ lt_ret_t lt_aesgcm_decrypt (void * ctx , const uint8_t * iv , const uint32_t iv_len , const uint8_t * add ,
178+ const uint32_t add_len , const uint8_t * ciphertext , const uint32_t ciphertext_len ,
179+ uint8_t * plaintext , const uint32_t plaintext_len )
180+ {
181+ if (iv_len != TR01_L3_IV_SIZE ) {
182+ LT_LOG_ERROR ("Invalid AES-GCM IV length: got %" PRIu32 " bytes, expected %d bytes" , iv_len , TR01_L3_IV_SIZE );
183+ return LT_PARAM_ERR ;
184+ }
185+
186+ lt_ctx_openssl_t * _ctx = (lt_ctx_openssl_t * )ctx ;
187+ unsigned long err_code ;
188+ int out_len ;
189+
190+ // Set IV.
191+ if (!EVP_DecryptInit_ex (_ctx -> aesgcm_decrypt_ctx , NULL , NULL , NULL , iv )) {
192+ err_code = ERR_get_error ();
193+ LT_LOG_ERROR ("Failed to set AES-GCM decryption IV, err_code=%lu (%s)" , err_code ,
194+ ERR_error_string (err_code , NULL ));
195+ return LT_CRYPTO_ERR ;
196+ }
197+
198+ // Process AAD (Additional Authenticated Data).
199+ if (!EVP_DecryptUpdate (_ctx -> aesgcm_decrypt_ctx , NULL , & out_len , add , (int )add_len )) {
200+ err_code = ERR_get_error ();
201+ LT_LOG_ERROR ("Failed to process AES-GCM AAD, err_code=%lu (%s)" , err_code , ERR_error_string (err_code , NULL ));
202+ return LT_CRYPTO_ERR ;
203+ }
204+
205+ // Decrypt ciphertext.
206+ if (!EVP_DecryptUpdate (_ctx -> aesgcm_decrypt_ctx , plaintext , & out_len , ciphertext ,
207+ (int )(ciphertext_len - TR01_L3_TAG_SIZE ))) {
208+ err_code = ERR_get_error ();
209+ LT_LOG_ERROR ("Failed to decrypt AES-GCM ciphertext, err_code=%lu (%s)" , err_code ,
210+ ERR_error_string (err_code , NULL ));
211+ return LT_CRYPTO_ERR ;
212+ }
213+
214+ // Check that all ciphertext data was processed.
215+ if (out_len != (int )(plaintext_len )) {
216+ LT_LOG_ERROR ("AES-GCM decryption length mismatch! Current: %d bytes, expected: %" PRIu32 " bytes" , out_len ,
217+ plaintext_len );
218+ return LT_CRYPTO_ERR ;
219+ }
220+
221+ // Set expected tag value.
222+ if (!EVP_CIPHER_CTX_ctrl (_ctx -> aesgcm_decrypt_ctx , EVP_CTRL_GCM_SET_TAG , TR01_L3_TAG_SIZE ,
223+ (void * )(ciphertext + ciphertext_len - TR01_L3_TAG_SIZE ))) {
224+ err_code = ERR_get_error ();
225+ LT_LOG_ERROR ("Failed to set AES-GCM decryption tag, err_code=%lu (%s)" , err_code ,
226+ ERR_error_string (err_code , NULL ));
227+ return LT_CRYPTO_ERR ;
228+ }
229+
230+ // Finalize decryption.
231+ if (EVP_DecryptFinal_ex (_ctx -> aesgcm_decrypt_ctx , plaintext + out_len , & out_len ) <= 0 ) {
232+ err_code = ERR_get_error ();
233+ LT_LOG_ERROR ("Failed to finalize AES-GCM decryption, err_code=%lu (%s)" , err_code ,
234+ ERR_error_string (err_code , NULL ));
235+ return LT_CRYPTO_ERR ;
236+ }
237+
238+ return LT_OK ;
239+ }
240+
241+ lt_ret_t lt_aesgcm_encrypt_deinit (void * ctx )
242+ {
243+ lt_ctx_openssl_t * _ctx = (lt_ctx_openssl_t * )ctx ;
244+
245+ EVP_CIPHER_CTX_free (_ctx -> aesgcm_encrypt_ctx );
246+ _ctx -> aesgcm_encrypt_ctx = NULL ;
247+
248+ return LT_OK ;
249+ }
250+
251+ lt_ret_t lt_aesgcm_decrypt_deinit (void * ctx )
252+ {
253+ lt_ctx_openssl_t * _ctx = (lt_ctx_openssl_t * )ctx ;
254+
255+ EVP_CIPHER_CTX_free (_ctx -> aesgcm_decrypt_ctx );
256+ _ctx -> aesgcm_decrypt_ctx = NULL ;
257+
258+ return LT_OK ;
259+ }
0 commit comments