GNUnet  0.11.x
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, const void *key, size_t key_len, const void *buf,
78  size_t buf_len)
79 {
80  gcry_md_setkey (mac, key, key_len);
81  gcry_md_write (mac, buf, buf_len);
82 
83  return (const void *) gcry_md_read (mac, 0);
84 }
85 
86 
97 static int
98 getPRK (gcry_md_hd_t mac, const void *xts, size_t xts_len, const void *skm,
99  size_t skm_len, void *prk)
100 {
101  const void *ret;
102 
103  ret = doHMAC (mac, xts, xts_len, skm, skm_len);
104  if (ret == NULL)
105  return GNUNET_SYSERR;
106  GNUNET_memcpy (prk, ret, gcry_md_get_algo_dlen (gcry_md_get_algo (mac)));
107 
108  return GNUNET_YES;
109 }
110 
111 
112 #if DEBUG_HKDF
113 static void
114 dump (const char *src, const void *p, unsigned int l)
115 {
116  unsigned int i;
117 
118  printf ("\n%s: ", src);
119  for (i = 0; i < l; i++)
120  {
121  printf ("%2x", (int) ((const unsigned char *) p)[i]);
122  }
123  printf ("\n");
124 }
125 
126 
127 #endif
128 
129 
143 int
144 GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo,
145  const void *xts, size_t xts_len, const void *skm,
146  size_t skm_len, va_list argp)
147 {
148  gcry_md_hd_t xtr;
149  gcry_md_hd_t prf;
150  const void *hc;
151  unsigned long i;
152  unsigned long t;
153  unsigned long d;
154  unsigned int k = gcry_md_get_algo_dlen (prf_algo);
155  unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo);
156  char prk[xtr_len];
157  int ret;
158  size_t ctx_len;
159  va_list args;
160 
161  BENCHMARK_START (hkdf);
162 
163  if (0 == k)
164  return GNUNET_SYSERR;
165  if (GPG_ERR_NO_ERROR !=
166  gcry_md_open (&xtr, xtr_algo, GCRY_MD_FLAG_HMAC))
167  return GNUNET_SYSERR;
168  if (GPG_ERR_NO_ERROR !=
169  gcry_md_open (&prf, prf_algo, GCRY_MD_FLAG_HMAC))
170  {
171  gcry_md_close (xtr);
172  return GNUNET_SYSERR;
173  }
174  va_copy (args, argp);
175 
176  ctx_len = 0;
177  while (NULL != va_arg (args, void *))
178  {
179  size_t nxt = va_arg (args, size_t);
180  if (nxt + ctx_len < nxt)
181  {
182  /* integer overflow */
183  GNUNET_break (0);
184  va_end (args);
185  goto hkdf_error;
186  }
187  ctx_len += nxt;
188  }
189 
190  va_end (args);
191 
192  if ( (k + ctx_len < ctx_len) ||
193  (k + ctx_len + 1 < ctx_len) )
194  {
195  /* integer overflow */
196  GNUNET_break (0);
197  goto hkdf_error;
198  }
199 
200  memset (result, 0, out_len);
201  if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES)
202  goto hkdf_error;
203 #if DEBUG_HKDF
204  dump ("PRK", prk, xtr_len);
205 #endif
206 
207  t = out_len / k;
208  d = out_len % k;
209 
210  /* K(1) */
211  {
212  size_t plain_len = k + ctx_len + 1;
213  char *plain;
214  const void *ctx;
215  char *dst;
216 
217  plain = GNUNET_malloc (plain_len);
218  dst = plain + k;
219  va_copy (args, argp);
220  while ((ctx = va_arg (args, void *)))
221  {
222  size_t len;
223 
224  len = va_arg (args, size_t);
225  GNUNET_memcpy (dst, ctx, len);
226  dst += len;
227  }
228  va_end (args);
229 
230  if (t > 0)
231  {
232  plain[k + ctx_len] = (char) 1;
233 #if DEBUG_HKDF
234  dump ("K(1)", plain, plain_len);
235 #endif
236  hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1);
237  if (hc == NULL)
238  {
239  GNUNET_free (plain);
240  goto hkdf_error;
241  }
242  GNUNET_memcpy (result, hc, k);
243  result += k;
244  }
245 
246  /* K(i+1) */
247  for (i = 1; i < t; i++)
248  {
249  GNUNET_memcpy (plain, result - k, k);
250  plain[k + ctx_len] = (char) (i + 1);
251  gcry_md_reset (prf);
252 #if DEBUG_HKDF
253  dump ("K(i+1)", plain, plain_len);
254 #endif
255  hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
256  if (hc == NULL)
257  {
258  GNUNET_free (plain);
259  goto hkdf_error;
260  }
261  GNUNET_memcpy (result, hc, k);
262  result += k;
263  }
264 
265  /* K(t):d */
266  if (d > 0)
267  {
268  if (t > 0)
269  {
270  GNUNET_memcpy (plain, result - k, k);
271  i++;
272  }
273  plain[k + ctx_len] = (char) i;
274  gcry_md_reset (prf);
275 #if DEBUG_HKDF
276  dump ("K(t):d", plain, plain_len);
277 #endif
278  if (t > 0)
279  hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
280  else
281  hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k);
282  if (hc == NULL)
283  {
284  GNUNET_free (plain);
285  goto hkdf_error;
286  }
287  GNUNET_memcpy (result, hc, d);
288  }
289 #if DEBUG_HKDF
290  dump ("result", result - k, out_len);
291 #endif
292 
293  ret = GNUNET_YES;
294  GNUNET_free (plain);
295  goto hkdf_ok;
296  }
297 hkdf_error:
298  ret = GNUNET_SYSERR;
299 hkdf_ok:
300  gcry_md_close (xtr);
301  gcry_md_close (prf);
302  BENCHMARK_END (hkdf);
303  return ret;
304 }
305 
306 
319 int
320 GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo,
321  const void *xts, size_t xts_len, const void *skm,
322  size_t skm_len, ...)
323 {
324  va_list argp;
325  int ret;
326 
327  va_start (argp, skm_len);
328  ret =
329  GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, xts_len,
330  skm, skm_len, argp);
331  va_end (argp);
332 
333  return ret;
334 }
335 
336 
337 /* end of crypto_hkdf.c */
int 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:144
#define BENCHMARK_START(opname)
Definition: benchmark.h:57
#define BENCHMARK_END(opname)
Definition: benchmark.h:58
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
int 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:320
static struct GNUNET_SCHEDULER_Task * t
Main task.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
static struct LoggingHandle * l
cryptographic primitives for GNUnet
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
static char buf[2048]
static int result
Global testing status.
struct GNUNET_HashCode key
The key used in the DHT.
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
benchmarking for various operations
static int 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:98
static int dump
Dump the database.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...