Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / wsutil / wsgcrypt.c
blob69481cd764979c4d3474ddcf547a6f165b9a3fe4
1 /* wsgcrypt.c
2 * Helper functions for libgcrypt
3 * By Erik de Jong <erikdejong@gmail.com>
4 * Copyright 2017 Erik de Jong
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "wsgcrypt.h"
15 gcry_error_t ws_hmac_buffer(int algo, void *digest, const void *buffer, size_t length, const void *key, size_t keylen)
17 gcry_md_hd_t hmac_handle;
18 gcry_error_t result = gcry_md_open(&hmac_handle, algo, GCRY_MD_FLAG_HMAC);
19 if (result) {
20 return result;
22 result = gcry_md_setkey(hmac_handle, key, keylen);
23 if (result) {
24 gcry_md_close(hmac_handle);
25 return result;
27 gcry_md_write(hmac_handle, buffer, length);
28 memcpy(digest, gcry_md_read(hmac_handle, 0), gcry_md_get_algo_dlen(algo));
29 gcry_md_close(hmac_handle);
30 return GPG_ERR_NO_ERROR;
33 gcry_error_t ws_cmac_buffer(int algo, void *digest, const void *buffer, size_t length, const void *key, size_t keylen)
35 gcry_mac_hd_t cmac_handle;
36 gcry_error_t result = gcry_mac_open(&cmac_handle, algo, 0, NULL);
37 if (result) {
38 return result;
40 result = gcry_mac_setkey(cmac_handle, key, keylen);
41 if (result) {
42 gcry_mac_close(cmac_handle);
43 return result;
45 gcry_mac_write(cmac_handle, buffer, length);
46 result = gcry_mac_read(cmac_handle, digest, &keylen);
47 gcry_mac_close(cmac_handle);
48 return result;
51 void crypt_des_ecb(uint8_t *output, const uint8_t *buffer, const uint8_t *key56)
53 uint8_t key64[8];
54 gcry_cipher_hd_t handle;
56 memset(output, 0x00, 8);
58 /* Transform 56 bits key into 64 bits DES key */
59 key64[0] = key56[0];
60 key64[1] = (key56[0] << 7) | (key56[1] >> 1);
61 key64[2] = (key56[1] << 6) | (key56[2] >> 2);
62 key64[3] = (key56[2] << 5) | (key56[3] >> 3);
63 key64[4] = (key56[3] << 4) | (key56[4] >> 4);
64 key64[5] = (key56[4] << 3) | (key56[5] >> 5);
65 key64[6] = (key56[5] << 2) | (key56[6] >> 6);
66 key64[7] = (key56[6] << 1);
68 if (gcry_cipher_open(&handle, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0)) {
69 return;
71 if (gcry_cipher_setkey(handle, key64, 8)) {
72 gcry_cipher_close(handle);
73 return;
75 gcry_cipher_encrypt(handle, output, 8, buffer, 8);
76 gcry_cipher_close(handle);
79 void decrypt_des_ecb(uint8_t *output, const uint8_t *buffer, const uint8_t *key56)
81 uint8_t key64[8];
82 gcry_cipher_hd_t handle;
84 memset(output, 0x00, 8);
86 /* Transform 56 bits key into 64 bits DES key */
87 key64[0] = key56[0];
88 key64[1] = (key56[0] << 7) | (key56[1] >> 1);
89 key64[2] = (key56[1] << 6) | (key56[2] >> 2);
90 key64[3] = (key56[2] << 5) | (key56[3] >> 3);
91 key64[4] = (key56[3] << 4) | (key56[4] >> 4);
92 key64[5] = (key56[4] << 3) | (key56[5] >> 5);
93 key64[6] = (key56[5] << 2) | (key56[6] >> 6);
94 key64[7] = (key56[6] << 1);
96 if (gcry_cipher_open(&handle, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0)) {
97 return;
99 if (gcry_cipher_setkey(handle, key64, 8)) {
100 gcry_cipher_close(handle);
101 return;
103 gcry_cipher_decrypt(handle, output, 8, buffer, 8);
104 gcry_cipher_close(handle);
107 size_t rsa_decrypt_inplace(const unsigned len, unsigned char* data, gcry_sexp_t pk, bool pkcs1_padding, char **err)
109 int rc = 0;
110 size_t decr_len = 0, i = 0;
111 gcry_sexp_t s_data = NULL, s_plain = NULL;
112 gcry_mpi_t encr_mpi = NULL, text = NULL;
114 *err = NULL;
116 /* create mpi representation of encrypted data */
117 rc = gcry_mpi_scan(&encr_mpi, GCRYMPI_FMT_USG, data, len, NULL);
118 if (rc != 0 ) {
119 *err = ws_strdup_printf("can't convert data to mpi (size %d):%s", len, gcry_strerror(rc));
120 return 0;
123 /* put the data into a simple list */
124 rc = gcry_sexp_build(&s_data, NULL, "(enc-val(rsa(a%m)))", encr_mpi);
125 if (rc != 0) {
126 *err = ws_strdup_printf("can't build encr_sexp:%s", gcry_strerror(rc));
127 decr_len = 0;
128 goto out;
131 /* pass it to libgcrypt */
132 rc = gcry_pk_decrypt(&s_plain, s_data, pk);
133 if (rc != 0)
135 *err = ws_strdup_printf("can't decrypt key:%s", gcry_strerror(rc));
136 decr_len = 0;
137 goto out;
140 /* convert plain text sexp to mpi format */
141 text = gcry_sexp_nth_mpi(s_plain, 0, 0);
142 if (! text) {
143 *err = g_strdup("can't convert sexp to mpi");
144 decr_len = 0;
145 goto out;
148 /* compute size requested for plaintext buffer */
149 rc = gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &decr_len, text);
150 if (rc != 0) {
151 *err = ws_strdup_printf("can't compute decr size:%s", gcry_strerror(rc));
152 decr_len = 0;
153 goto out;
156 /* sanity check on out buffer */
157 if (decr_len > len) {
158 *err = ws_strdup_printf("decrypted data is too long ?!? (%zu max %d)", decr_len, len);
159 decr_len = 0;
160 goto out;
163 /* write plain text to newly allocated buffer */
164 rc = gcry_mpi_print(GCRYMPI_FMT_USG, data, len, &decr_len, text);
165 if (rc != 0) {
166 *err = ws_strdup_printf("can't print decr data to mpi (size %zu):%s", decr_len, gcry_strerror(rc));
167 decr_len = 0;
168 goto out;
171 if (pkcs1_padding) {
172 /* strip the padding*/
173 rc = 0;
174 for (i = 1; i < decr_len; i++) {
175 if (data[i] == 0) {
176 rc = (int) i+1;
177 break;
181 decr_len -= rc;
182 memmove(data, data+rc, decr_len);
185 out:
186 gcry_sexp_release(s_data);
187 gcry_sexp_release(s_plain);
188 gcry_mpi_release(encr_mpi);
189 gcry_mpi_release(text);
190 return decr_len;
193 gcry_error_t
194 hkdf_expand(int hashalgo, const uint8_t *prk, unsigned prk_len, const uint8_t *info, unsigned info_len,
195 uint8_t *out, unsigned out_len)
197 // Current maximum hash output size: 48 bytes for SHA-384.
198 unsigned char lastoutput[48];
199 gcry_md_hd_t h;
200 gcry_error_t err;
201 const unsigned hash_len = gcry_md_get_algo_dlen(hashalgo);
203 /* Some sanity checks */
204 if (!(out_len > 0 && out_len <= 255 * hash_len) ||
205 !(hash_len > 0 && hash_len <= sizeof(lastoutput))) {
206 return GPG_ERR_INV_ARG;
209 err = gcry_md_open(&h, hashalgo, GCRY_MD_FLAG_HMAC);
210 if (err) {
211 return err;
214 for (unsigned offset = 0; offset < out_len; offset += hash_len) {
215 gcry_md_reset(h);
216 gcry_md_setkey(h, prk, prk_len); /* Set PRK */
217 if (offset > 0) {
218 gcry_md_write(h, lastoutput, hash_len); /* T(1..N) */
220 gcry_md_write(h, info, info_len); /* info */
221 gcry_md_putc(h, (uint8_t) (offset / hash_len + 1)); /* constant 0x01..N */
223 memcpy(lastoutput, gcry_md_read(h, hashalgo), hash_len);
224 memcpy(out + offset, lastoutput, MIN(hash_len, out_len - offset));
227 gcry_md_close(h);
228 return 0;
231 gcry_error_t
232 hpke_extract(uint16_t kdf_id, const uint8_t *salt, unsigned salt_len, const uint8_t *suite_id, const char *label,
233 const uint8_t *ikm, unsigned ikm_len, uint8_t *out)
235 int hashalgo;
236 gcry_md_hd_t hmac_handle;
237 switch (kdf_id) {
238 case HPKE_HKDF_SHA256:
239 hashalgo = GCRY_MD_SHA256;
240 break;
241 case HPKE_HKDF_SHA384:
242 hashalgo = GCRY_MD_SHA384;
243 break;
244 case HPKE_HKDF_SHA512:
245 hashalgo = GCRY_MD_SHA512;
246 break;
247 default:
248 return GPG_ERR_DIGEST_ALGO;
250 gcry_error_t result = gcry_md_open(&hmac_handle, hashalgo, GCRY_MD_FLAG_HMAC);
251 if (result) {
252 return result;
254 result = gcry_md_setkey(hmac_handle, salt, salt_len);
255 if (result) {
256 gcry_md_close(hmac_handle);
257 return result;
259 gcry_md_write(hmac_handle, HPKE_VERSION_ID, sizeof(HPKE_VERSION_ID) - 1);
260 gcry_md_write(hmac_handle, suite_id, HPKE_SUIT_ID_LEN);
261 gcry_md_write(hmac_handle, label, strlen(label));
262 gcry_md_write(hmac_handle, ikm, ikm_len);
263 memcpy(out, gcry_md_read(hmac_handle, 0), hpke_hkdf_len(kdf_id));
264 gcry_md_close(hmac_handle);
265 return GPG_ERR_NO_ERROR;
268 uint16_t
269 hpke_hkdf_len(uint16_t kdf_id)
271 switch (kdf_id) {
272 case HPKE_HKDF_SHA256:
273 return HASH_SHA2_256_LENGTH;
274 case HPKE_HKDF_SHA384:
275 return HASH_SHA2_384_LENGTH;
276 case HPKE_HKDF_SHA512:
277 return HASH_SHA2_512_LENGTH;
278 default:
279 return 0;
283 uint16_t
284 hpke_aead_key_len(uint16_t aead_id)
286 switch (aead_id) {
287 case HPKE_AEAD_AES_128_GCM:
288 return AEAD_AES_128_GCM_KEY_LENGTH;
289 case HPKE_AEAD_AES_256_GCM:
290 return AEAD_AES_256_GCM_KEY_LENGTH;
291 case HPKE_AEAD_CHACHA20POLY1305:
292 return AEAD_CHACHA20POLY1305_KEY_LENGTH;
293 default:
294 return 0;
298 uint16_t
299 hpke_aead_nonce_len(uint16_t aead_id)
301 switch (aead_id) {
302 case HPKE_AEAD_AES_128_GCM:
303 case HPKE_AEAD_AES_256_GCM:
304 case HPKE_AEAD_CHACHA20POLY1305:
305 return HPKE_AEAD_NONCE_LENGTH;
306 default:
307 return 0;
311 void
312 hpke_suite_id(uint16_t kem_id, uint16_t kdf_id, uint16_t aead_id, uint8_t *suite_id)
314 uint8_t offset = 0;
315 memcpy(suite_id, HPKE_SUIT_PREFIX, sizeof(HPKE_SUIT_PREFIX) - 1);
316 offset += sizeof(HPKE_SUIT_PREFIX) - 1;
317 suite_id[offset++] = (kem_id >> 8) & 0xFF;
318 suite_id[offset++] = kem_id & 0xFF;
319 suite_id[offset++] = (kdf_id >> 8) & 0xFF;
320 suite_id[offset++] = kdf_id & 0xFF;
321 suite_id[offset++] = (aead_id >> 8) & 0xFF;
322 suite_id[offset++] = aead_id & 0xFF;
325 static gcry_error_t
326 hpke_expand(uint16_t kdf_id, const uint8_t *prk, const uint8_t *suite_id, const char *label,
327 const uint8_t *info, uint8_t *out, uint16_t out_len)
329 int hashalgo;
330 GByteArray * labeled_info = g_byte_array_new();
331 uint16_t out_len_be = GUINT16_TO_BE(out_len);
332 gcry_error_t result;
333 switch (kdf_id) {
334 case HPKE_HKDF_SHA256:
335 hashalgo = GCRY_MD_SHA256;
336 break;
337 case HPKE_HKDF_SHA384:
338 hashalgo = GCRY_MD_SHA384;
339 break;
340 case HPKE_HKDF_SHA512:
341 hashalgo = GCRY_MD_SHA512;
342 break;
343 default:
344 return GPG_ERR_DIGEST_ALGO;
346 g_byte_array_append(labeled_info, (uint8_t *)&out_len_be, 2);
347 g_byte_array_append(labeled_info, HPKE_VERSION_ID, sizeof(HPKE_VERSION_ID) - 1);
348 g_byte_array_append(labeled_info, suite_id, HPKE_SUIT_ID_LEN);
349 g_byte_array_append(labeled_info, label, (unsigned)strlen(label));
350 g_byte_array_append(labeled_info, info, (unsigned)(1 + hpke_hkdf_len(kdf_id) * 2));
351 result = hkdf_expand(hashalgo, prk, (unsigned)hpke_hkdf_len(kdf_id), labeled_info->data, labeled_info->len, out, out_len);
352 g_byte_array_free(labeled_info, TRUE);
353 return result;
356 gcry_error_t
357 hpke_key_schedule(uint16_t kdf_id, uint16_t aead_id, const uint8_t *salt, unsigned salt_len, const uint8_t *suite_id,
358 const uint8_t *ikm, unsigned ikm_len, uint8_t mode, uint8_t *key, uint8_t *base_nonce)
360 uint8_t secret[HPKE_MAX_KDF_LEN];
361 uint8_t context[HPKE_MAX_KDF_LEN * 2 + 1];
362 size_t kdf_len = hpke_hkdf_len(kdf_id);
363 context[0] = mode;
364 gcry_error_t result = hpke_extract(kdf_id, NULL, 0, suite_id, "psk_id_hash", NULL, 0, context + 1);
365 if (result) {
366 return result;
368 result = hpke_extract(kdf_id, NULL, 0, suite_id, "info_hash", ikm, ikm_len, context + 1 + kdf_len);
369 if (result) {
370 return result;
372 result = hpke_extract(kdf_id, salt, salt_len, suite_id, "secret", NULL, 0, secret);
373 if (result) {
374 return result;
376 result = hpke_expand(kdf_id, secret, suite_id, "key", context, key, hpke_aead_key_len(aead_id));
377 if (result) {
378 return result;
380 result = hpke_expand(kdf_id, secret, suite_id, "base_nonce", context, base_nonce, hpke_aead_nonce_len(aead_id));
381 return result;
384 gcry_error_t
385 hpke_setup_aead(gcry_cipher_hd_t* cipher, uint16_t aead_id, uint8_t *key)
387 gcry_error_t err;
388 switch (aead_id) {
389 case HPKE_AEAD_AES_128_GCM:
390 err = gcry_cipher_open(cipher, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_GCM, 0);
391 break;
392 case HPKE_AEAD_AES_256_GCM:
393 err = gcry_cipher_open(cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, 0);
394 break;
395 case HPKE_AEAD_CHACHA20POLY1305:
396 err = gcry_cipher_open(cipher, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_POLY1305, 0);
397 break;
398 default:
399 return GPG_ERR_CIPHER_ALGO;
401 if (err)
402 return err;
403 return gcry_cipher_setkey(*(cipher), key, hpke_aead_key_len(aead_id));
406 gcry_error_t
407 hpke_set_nonce(gcry_cipher_hd_t cipher, uint64_t seq, uint8_t *base_nonce, size_t nonce_len)
409 size_t i;
410 uint8_t *nonce = (uint8_t *)wmem_alloc0(NULL, nonce_len);
412 for (i = 1; i < 9; i++) {
413 nonce[nonce_len - i] = seq & 255;
414 seq >>= 8;
416 for (i = 0; i < nonce_len; i++) {
417 nonce[i] ^= base_nonce[i];
419 return gcry_cipher_setiv(cipher, nonce, nonce_len);
423 * Editor modelines - https://www.wireshark.org/tools/modelines.html
425 * Local variables:
426 * c-basic-offset: 8
427 * tab-width: 8
428 * indent-tabs-mode: t
429 * End:
431 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
432 * :indentSize=8:tabSize=8:noTabs=false: