GNUnet 0.21.0
crypto_hkdf.c
Go to the documentation of this file.
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
39#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-hkdf", __VA_ARGS__)
40
44#define GNUNET_BUILD 1
45
49#define DEBUG_HKDF 0
50
51
52#if GNUNET_BUILD
53
54#include "platform.h"
55#include "gnunet_util_lib.h"
56#include "benchmark.h"
57#else
58#define GNUNET_NO 0
59#define GNUNET_YES 1
60#define GNUNET_SYSERR -1
61#include <stdlib.h>
62#endif
63
64#include <gcrypt.h>
65
66
77static const void *
78doHMAC (gcry_md_hd_t mac,
79 const void *key,
80 size_t key_len,
81 const void *buf,
82 size_t buf_len)
83{
84 if (GPG_ERR_NO_ERROR !=
85 gcry_md_setkey (mac, key, key_len))
86 {
87 GNUNET_break (0);
88 return NULL;
89 }
90 gcry_md_write (mac,
91 buf,
92 buf_len);
93 return (const void *) gcry_md_read (mac, 0);
94}
95
96
108getPRK (gcry_md_hd_t mac,
109 const void *xts,
110 size_t xts_len,
111 const void *skm,
112 size_t skm_len,
113 void *prk)
114{
115 const void *ret;
116 size_t dlen;
117
118 dlen = gcry_md_get_algo_dlen (gcry_md_get_algo (mac));
119
120 /* sanity check to bound stack allocation */
121 GNUNET_assert (dlen <= 512);
122
123 /* From RFC 5869:
124 * salt - optional salt value (a non-secret random value);
125 * if not provided, it is set to a string of HashLen zeros. */
126
127 if (0 == xts_len)
128 {
129 char zero_salt[dlen];
130
131 memset (zero_salt, 0, dlen);
132 ret = doHMAC (mac, zero_salt, dlen, skm, skm_len);
133 }
134 else
135 {
136 ret = doHMAC (mac, xts, xts_len, skm, skm_len);
137 }
138 if (NULL == ret)
139 return GNUNET_SYSERR;
140 GNUNET_memcpy (prk,
141 ret,
142 dlen);
143 return GNUNET_YES;
144}
145
146
147#if DEBUG_HKDF
148static void
149dump (const char *src,
150 const void *p,
151 unsigned int l)
152{
153 printf ("\n%s: ", src);
154 for (unsigned int i = 0; i < l; i++)
155 {
156 printf ("%2x", (int) ((const unsigned char *) p)[i]);
157 }
158 printf ("\n");
159}
160
161
162#endif
163
164
167 size_t out_len,
168 int xtr_algo,
169 int prf_algo,
170 const void *xts,
171 size_t xts_len,
172 const void *skm,
173 size_t skm_len,
174 va_list argp)
175{
176 gcry_md_hd_t xtr;
177 gcry_md_hd_t prf;
178 const void *hc;
179 unsigned long i;
180 unsigned long t;
181 unsigned long d;
182 unsigned int k = gcry_md_get_algo_dlen (prf_algo);
183 unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo);
184 char prk[xtr_len];
185 int ret;
186 size_t ctx_len;
187 va_list args;
188
189 BENCHMARK_START (hkdf);
190
191 if (0 == k)
192 return GNUNET_SYSERR;
193 if (GPG_ERR_NO_ERROR !=
194 gcry_md_open (&xtr,
195 xtr_algo,
196 GCRY_MD_FLAG_HMAC))
197 return GNUNET_SYSERR;
198 if (GPG_ERR_NO_ERROR !=
199 gcry_md_open (&prf,
200 prf_algo,
201 GCRY_MD_FLAG_HMAC))
202 {
203 gcry_md_close (xtr);
204 return GNUNET_SYSERR;
205 }
206 va_copy (args, argp);
207
208 ctx_len = 0;
209 while (NULL != va_arg (args, void *))
210 {
211 size_t nxt = va_arg (args, size_t);
212 if (nxt + ctx_len < nxt)
213 {
214 /* integer overflow */
215 GNUNET_break (0);
216 va_end (args);
217 goto hkdf_error;
218 }
219 ctx_len += nxt;
220 }
221
222 va_end (args);
223
224 if ( (k + ctx_len < ctx_len) ||
225 (k + ctx_len + 1 < ctx_len) )
226 {
227 /* integer overflow */
228 GNUNET_break (0);
229 goto hkdf_error;
230 }
231
232 memset (result, 0, out_len);
233 if (GNUNET_YES !=
234 getPRK (xtr, xts, xts_len, skm, skm_len, prk))
235 goto hkdf_error;
236#if DEBUG_HKDF
237 dump ("PRK", prk, xtr_len);
238#endif
239
240 t = out_len / k;
241 d = out_len % k;
242
243 /* K(1) */
244 {
245 size_t plain_len = k + ctx_len + 1;
246 char *plain;
247 const void *ctx;
248 char *dst;
249
250 plain = GNUNET_malloc (plain_len);
251 dst = plain + k;
252 va_copy (args, argp);
253 while ((ctx = va_arg (args, void *)))
254 {
255 size_t len;
256
257 len = va_arg (args, size_t);
258 GNUNET_memcpy (dst, ctx, len);
259 dst += len;
260 }
261 va_end (args);
262
263 if (t > 0)
264 {
265 plain[k + ctx_len] = (char) 1;
266#if DEBUG_HKDF
267 dump ("K(1)", plain, plain_len);
268#endif
269 hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1);
270 if (hc == NULL)
271 {
272 GNUNET_free (plain);
273 goto hkdf_error;
274 }
275 GNUNET_memcpy (result, hc, k);
276 result += k;
277 }
278
279 /* K(i+1) */
280 for (i = 1; i < t; i++)
281 {
282 GNUNET_memcpy (plain, result - k, k);
283 plain[k + ctx_len] = (char) (i + 1);
284 gcry_md_reset (prf);
285#if DEBUG_HKDF
286 dump ("K(i+1)", plain, plain_len);
287#endif
288 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
289 if (NULL == hc)
290 {
291 GNUNET_free (plain);
292 goto hkdf_error;
293 }
294 GNUNET_memcpy (result, hc, k);
295 result += k;
296 }
297
298 /* K(t):d */
299 if (d > 0)
300 {
301 if (t > 0)
302 {
303 GNUNET_memcpy (plain, result - k, k);
304 i++;
305 }
306 plain[k + ctx_len] = (char) i;
307 gcry_md_reset (prf);
308#if DEBUG_HKDF
309 dump ("K(t):d", plain, plain_len);
310#endif
311 if (t > 0)
312 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
313 else
314 hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k);
315 if (hc == NULL)
316 {
317 GNUNET_free (plain);
318 goto hkdf_error;
319 }
320 GNUNET_memcpy (result, hc, d);
321 }
322#if DEBUG_HKDF
323 dump ("result", result - k, out_len);
324#endif
325
326 ret = GNUNET_YES;
327 GNUNET_free (plain);
328 goto hkdf_ok;
329 }
330hkdf_error:
332hkdf_ok:
333 gcry_md_close (xtr);
334 gcry_md_close (prf);
335 BENCHMARK_END (hkdf);
336 return ret;
337}
338
339
342 size_t out_len,
343 int xtr_algo,
344 int prf_algo,
345 const void *xts,
346 size_t xts_len,
347 const void *skm,
348 size_t skm_len, ...)
349{
350 va_list argp;
352
353 va_start (argp, skm_len);
354 ret =
356 out_len,
357 xtr_algo,
358 prf_algo,
359 xts,
360 xts_len,
361 skm,
362 skm_len,
363 argp);
364 va_end (argp);
365 return ret;
366}
367
368
369/* end of crypto_hkdf.c */
benchmarking for various operations
#define BENCHMARK_START(opname)
Definition: benchmark.h:57
#define BENCHMARK_END(opname)
Definition: benchmark.h:58
static mp_limb_t d[(((256)+GMP_NUMB_BITS - 1)/GMP_NUMB_BITS)]
static const void * doHMAC(gcry_md_hd_t mac, const void *key, size_t key_len, const void *buf, size_t buf_len)
Compute the HMAC.
Definition: crypto_hkdf.c:78
static enum GNUNET_GenericReturnValue getPRK(gcry_md_hd_t mac, const void *xts, size_t xts_len, const void *skm, size_t skm_len, void *prk)
Generate pseudo-random key.
Definition: crypto_hkdf.c:108
static int ret
Final status code.
Definition: gnunet-arm.c:94
static int dump
Dump the database.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_FS_Handle * ctx
static int result
Global testing status.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:38
static struct GNUNET_SCHEDULER_Task * t
Main task.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hkdf_v(void *result, size_t out_len, int xtr_algo, int prf_algo, const void *xts, size_t xts_len, const void *skm, size_t skm_len, va_list argp)
Derive key.
Definition: crypto_hkdf.c:166
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_hkdf(void *result, size_t out_len, int xtr_algo, int prf_algo, const void *xts, size_t xts_len, const void *skm, size_t skm_len,...)
Derive key.
Definition: crypto_hkdf.c:341
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_YES
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.