Extract HKDF-Expand from TLS 1.3 dissector
[metze/wireshark/wip.git] / wsutil / wsgcrypt.c
1 /* wsgcrypt.c
2  * Helper functions for libgcrypt
3  * By Erik de Jong <erikdejong@gmail.com>
4  * Copyright 2017 Erik de Jong
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  */
12
13 #include "wsgcrypt.h"
14
15 gcry_error_t ws_hmac_buffer(int algo, void *digest, const void *buffer, size_t length, const void *key, size_t keylen)
16 {
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;
21         }
22         result = gcry_md_setkey(hmac_handle, key, keylen);
23         if (result) {
24                 gcry_md_close(hmac_handle);
25                 return result;
26         }
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;
31 }
32
33 void crypt_des_ecb(guint8 *output, const guint8 *buffer, const guint8 *key56)
34 {
35         guint8 key64[8];
36         gcry_cipher_hd_t handle;
37
38         memset(output, 0x00, 8);
39
40         /* Transform 56 bits key into 64 bits DES key */
41         key64[0] = key56[0];
42         key64[1] = (key56[0] << 7) | (key56[1] >> 1);
43         key64[2] = (key56[1] << 6) | (key56[2] >> 2);
44         key64[3] = (key56[2] << 5) | (key56[3] >> 3);
45         key64[4] = (key56[3] << 4) | (key56[4] >> 4);
46         key64[5] = (key56[4] << 3) | (key56[5] >> 5);
47         key64[6] = (key56[5] << 2) | (key56[6] >> 6);
48         key64[7] = (key56[6] << 1);
49
50         if (gcry_cipher_open(&handle, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0)) {
51                 return;
52         }
53         if (gcry_cipher_setkey(handle, key64, 8)) {
54                 gcry_cipher_close(handle);
55                 return;
56         }
57         gcry_cipher_encrypt(handle, output, 8, buffer, 8);
58         gcry_cipher_close(handle);
59 }
60
61 size_t rsa_decrypt_inplace(const guint len, guchar* data, gcry_sexp_t pk, gboolean pkcs1_padding, char **err)
62 {
63         gint        rc = 0;
64         size_t      decr_len = 0, i = 0;
65         gcry_sexp_t s_data = NULL, s_plain = NULL;
66         gcry_mpi_t  encr_mpi = NULL, text = NULL;
67
68         *err = NULL;
69
70         /* create mpi representation of encrypted data */
71         rc = gcry_mpi_scan(&encr_mpi, GCRYMPI_FMT_USG, data, len, NULL);
72         if (rc != 0 ) {
73                 *err = g_strdup_printf("can't convert data to mpi (size %d):%s", len, gcry_strerror(rc));
74                 return 0;
75         }
76
77         /* put the data into a simple list */
78         rc = gcry_sexp_build(&s_data, NULL, "(enc-val(rsa(a%m)))", encr_mpi);
79         if (rc != 0) {
80                 *err = g_strdup_printf("can't build encr_sexp:%s", gcry_strerror(rc));
81                 decr_len = 0;
82                 goto out;
83         }
84
85         /* pass it to libgcrypt */
86         rc = gcry_pk_decrypt(&s_plain, s_data, pk);
87         if (rc != 0)
88         {
89                 *err = g_strdup_printf("can't decrypt key:%s", gcry_strerror(rc));
90                 decr_len = 0;
91                 goto out;
92         }
93
94         /* convert plain text sexp to mpi format */
95         text = gcry_sexp_nth_mpi(s_plain, 0, 0);
96         if (! text) {
97                 *err = g_strdup("can't convert sexp to mpi");
98                 decr_len = 0;
99                 goto out;
100         }
101
102         /* compute size requested for plaintext buffer */
103         rc = gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &decr_len, text);
104         if (rc != 0) {
105                 *err = g_strdup_printf("can't compute decr size:%s", gcry_strerror(rc));
106                 decr_len = 0;
107                 goto out;
108         }
109
110         /* sanity check on out buffer */
111         if (decr_len > len) {
112                 *err = g_strdup_printf("decrypted data is too long ?!? (%" G_GSIZE_MODIFIER "u max %d)", decr_len, len);
113                 decr_len = 0;
114                 goto out;
115         }
116
117         /* write plain text to newly allocated buffer */
118         rc = gcry_mpi_print(GCRYMPI_FMT_USG, data, len, &decr_len, text);
119         if (rc != 0) {
120                 *err = g_strdup_printf("can't print decr data to mpi (size %" G_GSIZE_MODIFIER "u):%s", decr_len, gcry_strerror(rc));
121                 decr_len = 0;
122                 goto out;
123         }
124
125         if (pkcs1_padding) {
126                 /* strip the padding*/
127                 rc = 0;
128                 for (i = 1; i < decr_len; i++) {
129                         if (data[i] == 0) {
130                                 rc = (gint) i+1;
131                                 break;
132                         }
133                 }
134
135                 decr_len -= rc;
136                 memmove(data, data+rc, decr_len);
137         }
138
139 out:
140         gcry_sexp_release(s_data);
141         gcry_sexp_release(s_plain);
142         gcry_mpi_release(encr_mpi);
143         gcry_mpi_release(text);
144         return decr_len;
145 }
146
147 gcry_error_t
148 hkdf_expand(int hashalgo, const guint8 *prk, guint prk_len, const guint8 *info, guint info_len,
149             guint8 *out, guint out_len)
150 {
151         // Current maximum hash output size: 48 bytes for SHA-384.
152         guchar          lastoutput[48];
153         gcry_md_hd_t    h;
154         gcry_error_t    err;
155         const guint     hash_len = gcry_md_get_algo_dlen(hashalgo);
156
157         /* Some sanity checks */
158         if (!(out_len > 0 && out_len <= 255 * hash_len) ||
159             !(hash_len > 0 && hash_len <= sizeof(lastoutput))) {
160                 return GPG_ERR_INV_ARG;
161         }
162
163         err = gcry_md_open(&h, hashalgo, GCRY_MD_FLAG_HMAC);
164         if (err) {
165                 return err;
166         }
167
168         for (guint offset = 0; offset < out_len; offset += hash_len) {
169                 gcry_md_reset(h);
170                 gcry_md_setkey(h, prk, prk_len);                    /* Set PRK */
171                 if (offset > 0) {
172                         gcry_md_write(h, lastoutput, hash_len);     /* T(1..N) */
173                 }
174                 gcry_md_write(h, info, info_len);                   /* info */
175                 gcry_md_putc(h, (guint8) (offset / hash_len + 1));  /* constant 0x01..N */
176
177                 memcpy(lastoutput, gcry_md_read(h, hashalgo), hash_len);
178                 memcpy(out + offset, lastoutput, MIN(hash_len, out_len - offset));
179         }
180
181         gcry_md_close(h);
182         return 0;
183 }
184
185 /*
186  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
187  *
188  * Local variables:
189  * c-basic-offset: 8
190  * tab-width: 8
191  * indent-tabs-mode: t
192  * End:
193  *
194  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
195  * :indentSize=8:tabSize=8:noTabs=false:
196  */