GNUnet  0.17.5
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 #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 
76 static const void *
77 doHMAC (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 
106 static enum GNUNET_GenericReturnValue
107 getPRK (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
147 static void
148 dump (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 
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  }
329 hkdf_error:
330  ret = GNUNET_SYSERR;
331 hkdf_ok:
332  gcry_md_close (xtr);
333  gcry_md_close (prf);
334  BENCHMARK_END (hkdf);
335  return ret;
336 }
337 
338 
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;
351 
352  va_start (argp, skm_len);
353  ret =
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 */
benchmarking for various operations
#define BENCHMARK_START(opname)
Definition: benchmark.h:57
#define BENCHMARK_END(opname)
Definition: benchmark.h:58
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:107
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:77
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static struct LoggingHandle * l
static int dump
Dump the database.
struct GNUNET_HashCode key
The key used in the DHT.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
static int result
Global testing status.
static char buf[2048]
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:37
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
static struct GNUNET_SCHEDULER_Task * t
Main task.
cryptographic primitives for GNUnet
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:165
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:340
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
Definition: gnunet_common.h:96
@ GNUNET_YES
@ GNUNET_SYSERR
Definition: gnunet_common.h:97
#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.