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.c368
1 files changed, 0 insertions, 368 deletions
diff --git a/src/util/crypto_hkdf.c b/src/util/crypto_hkdf.c
deleted file mode 100644
index 838e37d8d..000000000
--- a/src/util/crypto_hkdf.c
+++ /dev/null
@@ -1,368 +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,
78 const void *key,
79 size_t key_len,
80 const void *buf,
81 size_t buf_len)
82{
83 if (GPG_ERR_NO_ERROR !=
84 gcry_md_setkey (mac, key, key_len))
85 {
86 GNUNET_break (0);
87 return NULL;
88 }
89 gcry_md_write (mac,
90 buf,
91 buf_len);
92 return (const void *) gcry_md_read (mac, 0);
93}
94
95
96/**
97 * @brief Generate pseudo-random key
98 * @param mac gcrypt HMAC handle
99 * @param xts salt
100 * @param xts_len length of the @a xts salt
101 * @param skm source key material
102 * @param skm_len length of @a skm
103 * @param prk result buffer (allocated by caller; at least gcry_md_dlen() bytes)
104 * @return #GNUNET_YES on success
105 */
106static enum GNUNET_GenericReturnValue
107getPRK (gcry_md_hd_t mac,
108 const void *xts,
109 size_t xts_len,
110 const void *skm,
111 size_t skm_len,
112 void *prk)
113{
114 const void *ret;
115 size_t dlen;
116
117 dlen = gcry_md_get_algo_dlen (gcry_md_get_algo (mac));
118
119 /* sanity check to bound stack allocation */
120 GNUNET_assert (dlen <= 512);
121
122 /* From RFC 5869:
123 * salt - optional salt value (a non-secret random value);
124 * if not provided, it is set to a string of HashLen zeros. */
125
126 if (0 == xts_len)
127 {
128 char zero_salt[dlen];
129
130 memset (zero_salt, 0, dlen);
131 ret = doHMAC (mac, zero_salt, dlen, skm, skm_len);
132 }
133 else
134 {
135 ret = doHMAC (mac, xts, xts_len, skm, skm_len);
136 }
137 if (NULL == ret)
138 return GNUNET_SYSERR;
139 GNUNET_memcpy (prk,
140 ret,
141 dlen);
142 return GNUNET_YES;
143}
144
145
146#if DEBUG_HKDF
147static void
148dump (const char *src,
149 const void *p,
150 unsigned int l)
151{
152 printf ("\n%s: ", src);
153 for (unsigned int i = 0; i < l; i++)
154 {
155 printf ("%2x", (int) ((const unsigned char *) p)[i]);
156 }
157 printf ("\n");
158}
159
160
161#endif
162
163
164enum GNUNET_GenericReturnValue
165GNUNET_CRYPTO_hkdf_v (void *result,
166 size_t out_len,
167 int xtr_algo,
168 int prf_algo,
169 const void *xts,
170 size_t xts_len,
171 const void *skm,
172 size_t skm_len,
173 va_list argp)
174{
175 gcry_md_hd_t xtr;
176 gcry_md_hd_t prf;
177 const void *hc;
178 unsigned long i;
179 unsigned long t;
180 unsigned long d;
181 unsigned int k = gcry_md_get_algo_dlen (prf_algo);
182 unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo);
183 char prk[xtr_len];
184 int ret;
185 size_t ctx_len;
186 va_list args;
187
188 BENCHMARK_START (hkdf);
189
190 if (0 == k)
191 return GNUNET_SYSERR;
192 if (GPG_ERR_NO_ERROR !=
193 gcry_md_open (&xtr,
194 xtr_algo,
195 GCRY_MD_FLAG_HMAC))
196 return GNUNET_SYSERR;
197 if (GPG_ERR_NO_ERROR !=
198 gcry_md_open (&prf,
199 prf_algo,
200 GCRY_MD_FLAG_HMAC))
201 {
202 gcry_md_close (xtr);
203 return GNUNET_SYSERR;
204 }
205 va_copy (args, argp);
206
207 ctx_len = 0;
208 while (NULL != va_arg (args, void *))
209 {
210 size_t nxt = va_arg (args, size_t);
211 if (nxt + ctx_len < nxt)
212 {
213 /* integer overflow */
214 GNUNET_break (0);
215 va_end (args);
216 goto hkdf_error;
217 }
218 ctx_len += nxt;
219 }
220
221 va_end (args);
222
223 if ( (k + ctx_len < ctx_len) ||
224 (k + ctx_len + 1 < ctx_len) )
225 {
226 /* integer overflow */
227 GNUNET_break (0);
228 goto hkdf_error;
229 }
230
231 memset (result, 0, out_len);
232 if (GNUNET_YES !=
233 getPRK (xtr, xts, xts_len, skm, skm_len, prk))
234 goto hkdf_error;
235#if DEBUG_HKDF
236 dump ("PRK", prk, xtr_len);
237#endif
238
239 t = out_len / k;
240 d = out_len % k;
241
242 /* K(1) */
243 {
244 size_t plain_len = k + ctx_len + 1;
245 char *plain;
246 const void *ctx;
247 char *dst;
248
249 plain = GNUNET_malloc (plain_len);
250 dst = plain + k;
251 va_copy (args, argp);
252 while ((ctx = va_arg (args, void *)))
253 {
254 size_t len;
255
256 len = va_arg (args, size_t);
257 GNUNET_memcpy (dst, ctx, len);
258 dst += len;
259 }
260 va_end (args);
261
262 if (t > 0)
263 {
264 plain[k + ctx_len] = (char) 1;
265#if DEBUG_HKDF
266 dump ("K(1)", plain, plain_len);
267#endif
268 hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1);
269 if (hc == NULL)
270 {
271 GNUNET_free (plain);
272 goto hkdf_error;
273 }
274 GNUNET_memcpy (result, hc, k);
275 result += k;
276 }
277
278 /* K(i+1) */
279 for (i = 1; i < t; i++)
280 {
281 GNUNET_memcpy (plain, result - k, k);
282 plain[k + ctx_len] = (char) (i + 1);
283 gcry_md_reset (prf);
284#if DEBUG_HKDF
285 dump ("K(i+1)", plain, plain_len);
286#endif
287 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
288 if (NULL == hc)
289 {
290 GNUNET_free (plain);
291 goto hkdf_error;
292 }
293 GNUNET_memcpy (result, hc, k);
294 result += k;
295 }
296
297 /* K(t):d */
298 if (d > 0)
299 {
300 if (t > 0)
301 {
302 GNUNET_memcpy (plain, result - k, k);
303 i++;
304 }
305 plain[k + ctx_len] = (char) i;
306 gcry_md_reset (prf);
307#if DEBUG_HKDF
308 dump ("K(t):d", plain, plain_len);
309#endif
310 if (t > 0)
311 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
312 else
313 hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k);
314 if (hc == NULL)
315 {
316 GNUNET_free (plain);
317 goto hkdf_error;
318 }
319 GNUNET_memcpy (result, hc, d);
320 }
321#if DEBUG_HKDF
322 dump ("result", result - k, out_len);
323#endif
324
325 ret = GNUNET_YES;
326 GNUNET_free (plain);
327 goto hkdf_ok;
328 }
329hkdf_error:
330 ret = GNUNET_SYSERR;
331hkdf_ok:
332 gcry_md_close (xtr);
333 gcry_md_close (prf);
334 BENCHMARK_END (hkdf);
335 return ret;
336}
337
338
339enum GNUNET_GenericReturnValue
340GNUNET_CRYPTO_hkdf (void *result,
341 size_t out_len,
342 int xtr_algo,
343 int prf_algo,
344 const void *xts,
345 size_t xts_len,
346 const void *skm,
347 size_t skm_len, ...)
348{
349 va_list argp;
350 enum GNUNET_GenericReturnValue ret;
351
352 va_start (argp, skm_len);
353 ret =
354 GNUNET_CRYPTO_hkdf_v (result,
355 out_len,
356 xtr_algo,
357 prf_algo,
358 xts,
359 xts_len,
360 skm,
361 skm_len,
362 argp);
363 va_end (argp);
364 return ret;
365}
366
367
368/* end of crypto_hkdf.c */