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  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 
101 static int
102 getPRK (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 
107  ret = doHMAC (mac, xts, xts_len, skm, skm_len);
108  if (ret == NULL)
109  return GNUNET_SYSERR;
110  GNUNET_memcpy (prk, ret, gcry_md_get_algo_dlen (gcry_md_get_algo (mac)));
111 
112  return GNUNET_YES;
113 }
114 
115 
116 #if DEBUG_HKDF
117 static void
118 dump (const char *src, const void *p, unsigned int l)
119 {
120  unsigned int i;
121 
122  printf ("\n%s: ", src);
123  for (i = 0; i < l; i++)
124  {
125  printf ("%2x", (int) ((const unsigned char *) p)[i]);
126  }
127  printf ("\n");
128 }
129 
130 
131 #endif
132 
133 
147 int
148 GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo,
149  const void *xts, size_t xts_len, const void *skm,
150  size_t skm_len, va_list argp)
151 {
152  gcry_md_hd_t xtr;
153  gcry_md_hd_t prf;
154  const void *hc;
155  unsigned long i;
156  unsigned long t;
157  unsigned long d;
158  unsigned int k = gcry_md_get_algo_dlen (prf_algo);
159  unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo);
160  char prk[xtr_len];
161  int ret;
162  size_t ctx_len;
163  va_list args;
164 
165  BENCHMARK_START (hkdf);
166 
167  if (0 == k)
168  return GNUNET_SYSERR;
169  if (GPG_ERR_NO_ERROR !=
170  gcry_md_open (&xtr, xtr_algo, GCRY_MD_FLAG_HMAC))
171  return GNUNET_SYSERR;
172  if (GPG_ERR_NO_ERROR !=
173  gcry_md_open (&prf, prf_algo, GCRY_MD_FLAG_HMAC))
174  {
175  gcry_md_close (xtr);
176  return GNUNET_SYSERR;
177  }
178  va_copy (args, argp);
179 
180  ctx_len = 0;
181  while (NULL != va_arg (args, void *))
182  {
183  size_t nxt = va_arg (args, size_t);
184  if (nxt + ctx_len < nxt)
185  {
186  /* integer overflow */
187  GNUNET_break (0);
188  va_end (args);
189  goto hkdf_error;
190  }
191  ctx_len += nxt;
192  }
193 
194  va_end (args);
195 
196  if ( (k + ctx_len < ctx_len) ||
197  (k + ctx_len + 1 < ctx_len) )
198  {
199  /* integer overflow */
200  GNUNET_break (0);
201  goto hkdf_error;
202  }
203 
204  memset (result, 0, out_len);
205  if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES)
206  goto hkdf_error;
207 #if DEBUG_HKDF
208  dump ("PRK", prk, xtr_len);
209 #endif
210 
211  t = out_len / k;
212  d = out_len % k;
213 
214  /* K(1) */
215  {
216  size_t plain_len = k + ctx_len + 1;
217  char *plain;
218  const void *ctx;
219  char *dst;
220 
221  plain = GNUNET_malloc (plain_len);
222  dst = plain + k;
223  va_copy (args, argp);
224  while ((ctx = va_arg (args, void *)))
225  {
226  size_t len;
227 
228  len = va_arg (args, size_t);
229  GNUNET_memcpy (dst, ctx, len);
230  dst += len;
231  }
232  va_end (args);
233 
234  if (t > 0)
235  {
236  plain[k + ctx_len] = (char) 1;
237 #if DEBUG_HKDF
238  dump ("K(1)", plain, plain_len);
239 #endif
240  hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1);
241  if (hc == NULL)
242  {
243  GNUNET_free (plain);
244  goto hkdf_error;
245  }
246  GNUNET_memcpy (result, hc, k);
247  result += k;
248  }
249 
250  /* K(i+1) */
251  for (i = 1; i < t; i++)
252  {
253  GNUNET_memcpy (plain, result - k, k);
254  plain[k + ctx_len] = (char) (i + 1);
255  gcry_md_reset (prf);
256 #if DEBUG_HKDF
257  dump ("K(i+1)", plain, plain_len);
258 #endif
259  hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
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(t):d */
270  if (d > 0)
271  {
272  if (t > 0)
273  {
274  GNUNET_memcpy (plain, result - k, k);
275  i++;
276  }
277  plain[k + ctx_len] = (char) i;
278  gcry_md_reset (prf);
279 #if DEBUG_HKDF
280  dump ("K(t):d", plain, plain_len);
281 #endif
282  if (t > 0)
283  hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
284  else
285  hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k);
286  if (hc == NULL)
287  {
288  GNUNET_free (plain);
289  goto hkdf_error;
290  }
291  GNUNET_memcpy (result, hc, d);
292  }
293 #if DEBUG_HKDF
294  dump ("result", result - k, out_len);
295 #endif
296 
297  ret = GNUNET_YES;
298  GNUNET_free (plain);
299  goto hkdf_ok;
300  }
301 hkdf_error:
302  ret = GNUNET_SYSERR;
303 hkdf_ok:
304  gcry_md_close (xtr);
305  gcry_md_close (prf);
306  BENCHMARK_END (hkdf);
307  return ret;
308 }
309 
310 
323 int
324 GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo,
325  const void *xts, size_t xts_len, const void *skm,
326  size_t skm_len, ...)
327 {
328  va_list argp;
329  int ret;
330 
331  va_start (argp, skm_len);
332  ret =
333  GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, xts_len,
334  skm, skm_len, argp);
335  va_end (argp);
336 
337  return ret;
338 }
339 
340 
341 /* 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 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:102
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 struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
static int result
Global testing status.
static char buf[2048]
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
static struct GNUNET_SCHEDULER_Task * t
Main task.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_YES
Definition: gnunet_common.h:97
@ GNUNET_SYSERR
Definition: gnunet_common.h:93
cryptographic primitives for GNUnet
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:148
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:324
#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.