aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_hkdf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/crypto_hkdf.c')
-rw-r--r--src/util/crypto_hkdf.c360
1 files changed, 0 insertions, 360 deletions
diff --git a/src/util/crypto_hkdf.c b/src/util/crypto_hkdf.c
deleted file mode 100644
index 4e4496819..000000000
--- a/src/util/crypto_hkdf.c
+++ /dev/null
@@ -1,360 +0,0 @@
1/*
2 Copyright (c) 2010 Nils Durner
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23/**
24 * @file src/util/crypto_hkdf.c
25 * @brief Hash-based KDF as defined in RFC 5869
26 * @see http://www.rfc-editor.org/rfc/rfc5869.txt
27 * @todo remove GNUNET references
28 * @author Nils Durner
29 *
30 * The following list of people have reviewed this code and considered
31 * it correct on the date given (if you reviewed it, please
32 * have your name added to the list):
33 *
34 * - Christian Grothoff (08.10.2010)
35 * - Nathan Evans (08.10.2010)
36 * - Matthias Wachs (08.10.2010)
37 */
38
39#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-hkdf", __VA_ARGS__)
40
41/**
42 * Set this to 0 if you compile this code outside of GNUnet.
43 */
44#define GNUNET_BUILD 1
45
46/**
47 * Enable debugging.
48 */
49#define DEBUG_HKDF 0
50
51
52#if GNUNET_BUILD
53#include "platform.h"
54#include "gnunet_crypto_lib.h"
55#include "benchmark.h"
56#else
57#define GNUNET_NO 0
58#define GNUNET_YES 1
59#define GNUNET_SYSERR -1
60#include <stdlib.h>
61#endif
62
63#include <gcrypt.h>
64
65
66/**
67 * @brief Compute the HMAC
68 * @todo use chunked buffers
69 * @param mac gcrypt MAC handle
70 * @param key HMAC key
71 * @param key_len length of key
72 * @param buf message to be processed
73 * @param buf_len length of buf
74 * @return HMAC, freed by caller via gcry_md_close/_reset
75 */
76static const void *
77doHMAC (gcry_md_hd_t mac, const void *key, size_t key_len, const void *buf,
78 size_t buf_len)
79{
80 if (GPG_ERR_NO_ERROR != gcry_md_setkey (mac, key, key_len))
81 {
82 GNUNET_break (0);
83 return NULL;
84 }
85 gcry_md_write (mac, buf, buf_len);
86
87 return (const void *) gcry_md_read (mac, 0);
88}
89
90
91/**
92 * @brief Generate pseudo-random key
93 * @param mac gcrypt HMAC handle
94 * @param xts salt
95 * @param xts_len length of the @a xts salt
96 * @param skm source key material
97 * @param skm_len length of @a skm
98 * @param prk result buffer (allocated by caller; at least gcry_md_dlen() bytes)
99 * @return #GNUNET_YES on success
100 */
101static int
102getPRK (gcry_md_hd_t mac, const void *xts, size_t xts_len, const void *skm,
103 size_t skm_len, void *prk)
104{
105 const void *ret;
106 size_t dlen;
107
108 dlen = gcry_md_get_algo_dlen (gcry_md_get_algo (mac));
109
110 /* sanity check to bound stack allocation */
111 GNUNET_assert (dlen <= 512);
112
113 /* From RFC 5869:
114 * salt - optional salt value (a non-secret random value);
115 * if not provided, it is set to a string of HashLen zeros. */
116
117 if (xts_len == 0)
118 {
119 char zero_salt[dlen];
120 memset (zero_salt, 0, dlen);
121 ret = doHMAC (mac, zero_salt, dlen, skm, skm_len);
122 }
123 else
124 {
125 ret = doHMAC (mac, xts, xts_len, skm, skm_len);
126 }
127 if (ret == NULL)
128 return GNUNET_SYSERR;
129 GNUNET_memcpy (prk, ret, dlen);
130
131 return GNUNET_YES;
132}
133
134
135#if DEBUG_HKDF
136static void
137dump (const char *src, const void *p, unsigned int l)
138{
139 unsigned int i;
140
141 printf ("\n%s: ", src);
142 for (i = 0; i < l; i++)
143 {
144 printf ("%2x", (int) ((const unsigned char *) p)[i]);
145 }
146 printf ("\n");
147}
148
149
150#endif
151
152
153/**
154 * @brief Derive key
155 * @param result buffer for the derived key, allocated by caller
156 * @param out_len desired length of the derived key
157 * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_...
158 * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_...
159 * @param xts salt
160 * @param xts_len length of @a xts
161 * @param skm source key material
162 * @param skm_len length of @a skm
163 * @param argp va_list of void * & size_t pairs for context chunks
164 * @return #GNUNET_YES on success
165 */
166int
167GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo,
168 const void *xts, size_t xts_len, const void *skm,
169 size_t skm_len, va_list argp)
170{
171 gcry_md_hd_t xtr;
172 gcry_md_hd_t prf;
173 const void *hc;
174 unsigned long i;
175 unsigned long t;
176 unsigned long d;
177 unsigned int k = gcry_md_get_algo_dlen (prf_algo);
178 unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo);
179 char prk[xtr_len];
180 int ret;
181 size_t ctx_len;
182 va_list args;
183
184 BENCHMARK_START (hkdf);
185
186 if (0 == k)
187 return GNUNET_SYSERR;
188 if (GPG_ERR_NO_ERROR !=
189 gcry_md_open (&xtr, xtr_algo, GCRY_MD_FLAG_HMAC))
190 return GNUNET_SYSERR;
191 if (GPG_ERR_NO_ERROR !=
192 gcry_md_open (&prf, prf_algo, GCRY_MD_FLAG_HMAC))
193 {
194 gcry_md_close (xtr);
195 return GNUNET_SYSERR;
196 }
197 va_copy (args, argp);
198
199 ctx_len = 0;
200 while (NULL != va_arg (args, void *))
201 {
202 size_t nxt = va_arg (args, size_t);
203 if (nxt + ctx_len < nxt)
204 {
205 /* integer overflow */
206 GNUNET_break (0);
207 va_end (args);
208 goto hkdf_error;
209 }
210 ctx_len += nxt;
211 }
212
213 va_end (args);
214
215 if ( (k + ctx_len < ctx_len) ||
216 (k + ctx_len + 1 < ctx_len) )
217 {
218 /* integer overflow */
219 GNUNET_break (0);
220 goto hkdf_error;
221 }
222
223 memset (result, 0, out_len);
224 if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES)
225 goto hkdf_error;
226#if DEBUG_HKDF
227 dump ("PRK", prk, xtr_len);
228#endif
229
230 t = out_len / k;
231 d = out_len % k;
232
233 /* K(1) */
234 {
235 size_t plain_len = k + ctx_len + 1;
236 char *plain;
237 const void *ctx;
238 char *dst;
239
240 plain = GNUNET_malloc (plain_len);
241 dst = plain + k;
242 va_copy (args, argp);
243 while ((ctx = va_arg (args, void *)))
244 {
245 size_t len;
246
247 len = va_arg (args, size_t);
248 GNUNET_memcpy (dst, ctx, len);
249 dst += len;
250 }
251 va_end (args);
252
253 if (t > 0)
254 {
255 plain[k + ctx_len] = (char) 1;
256#if DEBUG_HKDF
257 dump ("K(1)", plain, plain_len);
258#endif
259 hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1);
260 if (hc == NULL)
261 {
262 GNUNET_free (plain);
263 goto hkdf_error;
264 }
265 GNUNET_memcpy (result, hc, k);
266 result += k;
267 }
268
269 /* K(i+1) */
270 for (i = 1; i < t; i++)
271 {
272 GNUNET_memcpy (plain, result - k, k);
273 plain[k + ctx_len] = (char) (i + 1);
274 gcry_md_reset (prf);
275#if DEBUG_HKDF
276 dump ("K(i+1)", plain, plain_len);
277#endif
278 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
279 if (hc == NULL)
280 {
281 GNUNET_free (plain);
282 goto hkdf_error;
283 }
284 GNUNET_memcpy (result, hc, k);
285 result += k;
286 }
287
288 /* K(t):d */
289 if (d > 0)
290 {
291 if (t > 0)
292 {
293 GNUNET_memcpy (plain, result - k, k);
294 i++;
295 }
296 plain[k + ctx_len] = (char) i;
297 gcry_md_reset (prf);
298#if DEBUG_HKDF
299 dump ("K(t):d", plain, plain_len);
300#endif
301 if (t > 0)
302 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
303 else
304 hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k);
305 if (hc == NULL)
306 {
307 GNUNET_free (plain);
308 goto hkdf_error;
309 }
310 GNUNET_memcpy (result, hc, d);
311 }
312#if DEBUG_HKDF
313 dump ("result", result - k, out_len);
314#endif
315
316 ret = GNUNET_YES;
317 GNUNET_free (plain);
318 goto hkdf_ok;
319 }
320hkdf_error:
321 ret = GNUNET_SYSERR;
322hkdf_ok:
323 gcry_md_close (xtr);
324 gcry_md_close (prf);
325 BENCHMARK_END (hkdf);
326 return ret;
327}
328
329
330/**
331 * @brief Derive key
332 * @param result buffer for the derived key, allocated by caller
333 * @param out_len desired length of the derived key
334 * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_...
335 * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_...
336 * @param xts salt
337 * @param xts_len length of @a xts
338 * @param skm source key material
339 * @param skm_len length of @a skm
340 * @return #GNUNET_YES on success
341 */
342int
343GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo,
344 const void *xts, size_t xts_len, const void *skm,
345 size_t skm_len, ...)
346{
347 va_list argp;
348 int ret;
349
350 va_start (argp, skm_len);
351 ret =
352 GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, xts_len,
353 skm, skm_len, argp);
354 va_end (argp);
355
356 return ret;
357}
358
359
360/* end of crypto_hkdf.c */