2 chronyd/chronyc - Programs for keeping computer clocks accurate.
4 **********************************************************************
5 * Copyright (C) Miroslav Lichvar 2020, 2023
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 **********************************************************************
22 =======================================================================
24 SIV ciphers using the GnuTLS library
31 #include <gnutls/crypto.h>
37 struct SIV_Instance_Record
{
38 gnutls_cipher_algorithm_t algorithm
;
39 gnutls_aead_cipher_hd_t cipher
;
44 /* ================================================== */
46 static int instance_counter
= 0;
47 static int gnutls_initialised
= 0;
49 /* ================================================== */
56 if (gnutls_initialised
)
59 r
= gnutls_global_init();
61 LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r
));
63 DEBUG_LOG("Initialised");
64 gnutls_initialised
= 1;
67 /* ================================================== */
72 assert(gnutls_initialised
);
73 gnutls_global_deinit();
74 gnutls_initialised
= 0;
75 DEBUG_LOG("Deinitialised");
78 /* ================================================== */
80 static gnutls_cipher_algorithm_t
81 get_cipher_algorithm(SIV_Algorithm algorithm
)
84 case AEAD_AES_SIV_CMAC_256
:
85 return GNUTLS_CIPHER_AES_128_SIV
;
86 #if HAVE_GNUTLS_SIV_GCM
87 case AEAD_AES_128_GCM_SIV
:
88 return GNUTLS_CIPHER_AES_128_SIV_GCM
;
95 /* ================================================== */
98 SIV_CreateInstance(SIV_Algorithm algorithm
)
100 gnutls_cipher_algorithm_t calgo
;
101 SIV_Instance instance
;
103 calgo
= get_cipher_algorithm(algorithm
);
107 if (instance_counter
== 0)
110 /* Check if the cipher is actually supported */
111 if (gnutls_cipher_get_tag_size(calgo
) == 0) {
112 if (instance_counter
== 0)
117 instance
= MallocNew(struct SIV_Instance_Record
);
118 instance
->algorithm
= calgo
;
119 instance
->cipher
= NULL
;
122 case AEAD_AES_SIV_CMAC_256
:
123 instance
->min_nonce_length
= 1;
124 instance
->max_nonce_length
= INT_MAX
;
126 case AEAD_AES_128_GCM_SIV
:
127 instance
->min_nonce_length
= 12;
128 instance
->max_nonce_length
= 12;
139 /* ================================================== */
142 SIV_DestroyInstance(SIV_Instance instance
)
144 if (instance
->cipher
)
145 gnutls_aead_cipher_deinit(instance
->cipher
);
149 if (instance_counter
== 0)
153 /* ================================================== */
156 SIV_GetKeyLength(SIV_Algorithm algorithm
)
158 gnutls_cipher_algorithm_t calgo
= get_cipher_algorithm(algorithm
);
164 len
= gnutls_cipher_get_key_size(calgo
);
168 if (len
< 1 || len
> SIV_MAX_KEY_LENGTH
)
169 LOG_FATAL("Invalid key length");
174 /* ================================================== */
177 SIV_SetKey(SIV_Instance instance
, const unsigned char *key
, int length
)
179 gnutls_aead_cipher_hd_t cipher
;
180 gnutls_datum_t datum
;
183 if (length
<= 0 || length
!= gnutls_cipher_get_key_size(instance
->algorithm
))
186 datum
.data
= (unsigned char *)key
;
189 #ifdef HAVE_GNUTLS_AEAD_CIPHER_SET_KEY
190 if (instance
->cipher
) {
191 r
= gnutls_aead_cipher_set_key(instance
->cipher
, &datum
);
193 DEBUG_LOG("Could not set cipher key : %s", gnutls_strerror(r
));
201 /* Initialise a new cipher with the provided key */
202 r
= gnutls_aead_cipher_init(&cipher
, instance
->algorithm
, &datum
);
204 DEBUG_LOG("Could not initialise %s : %s", "cipher", gnutls_strerror(r
));
208 /* Destroy the previous cipher (if its key could not be changed directly) */
209 if (instance
->cipher
)
210 gnutls_aead_cipher_deinit(instance
->cipher
);
212 instance
->cipher
= cipher
;
217 /* ================================================== */
220 SIV_GetMinNonceLength(SIV_Instance instance
)
222 return instance
->min_nonce_length
;
225 /* ================================================== */
228 SIV_GetMaxNonceLength(SIV_Instance instance
)
230 return instance
->max_nonce_length
;
233 /* ================================================== */
236 SIV_GetTagLength(SIV_Instance instance
)
240 len
= gnutls_cipher_get_tag_size(instance
->algorithm
);
242 if (len
< 1 || len
> SIV_MAX_TAG_LENGTH
)
243 LOG_FATAL("Invalid tag length");
248 /* ================================================== */
251 SIV_Encrypt(SIV_Instance instance
,
252 const unsigned char *nonce
, int nonce_length
,
253 const void *assoc
, int assoc_length
,
254 const void *plaintext
, int plaintext_length
,
255 unsigned char *ciphertext
, int ciphertext_length
)
257 size_t clen
= ciphertext_length
;
259 if (!instance
->cipher
)
262 if (nonce_length
< instance
->min_nonce_length
||
263 nonce_length
> instance
->max_nonce_length
|| assoc_length
< 0 ||
264 plaintext_length
< 0 || ciphertext_length
< 0)
267 assert(assoc
&& plaintext
);
269 if (gnutls_aead_cipher_encrypt(instance
->cipher
,
270 nonce
, nonce_length
, assoc
, assoc_length
, 0,
271 plaintext
, plaintext_length
, ciphertext
, &clen
) < 0)
274 if (clen
!= ciphertext_length
)
280 /* ================================================== */
283 SIV_Decrypt(SIV_Instance instance
,
284 const unsigned char *nonce
, int nonce_length
,
285 const void *assoc
, int assoc_length
,
286 const unsigned char *ciphertext
, int ciphertext_length
,
287 void *plaintext
, int plaintext_length
)
289 size_t plen
= plaintext_length
;
291 if (!instance
->cipher
)
294 if (nonce_length
< instance
->min_nonce_length
||
295 nonce_length
> instance
->max_nonce_length
|| assoc_length
< 0 ||
296 plaintext_length
< 0 || ciphertext_length
< 0)
299 assert(assoc
&& plaintext
);
301 if (gnutls_aead_cipher_decrypt(instance
->cipher
,
302 nonce
, nonce_length
, assoc
, assoc_length
, 0,
303 ciphertext
, ciphertext_length
, plaintext
, &plen
) < 0)
306 if (plen
!= plaintext_length
)