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  ctx_len += va_arg (args, size_t);
179 
180  va_end (args);
181 
182  memset (result, 0, out_len);
183  if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES)
184  goto hkdf_error;
185 #if DEBUG_HKDF
186  dump ("PRK", prk, xtr_len);
187 #endif
188 
189  t = out_len / k;
190  d = out_len % k;
191 
192  /* K(1) */
193  {
194  size_t plain_len = k + ctx_len + 1;
195  char plain[plain_len];
196  const void *ctx;
197  char *dst;
198 
199  dst = plain + k;
200  va_copy (args, argp);
201  while ((ctx = va_arg (args, void *)))
202  {
203  size_t len;
204 
205  len = va_arg (args, size_t);
206  GNUNET_memcpy (dst, ctx, len);
207  dst += len;
208  }
209  va_end (args);
210 
211  if (t > 0)
212  {
213  memset (plain + k + ctx_len, 1, 1);
214 #if DEBUG_HKDF
215  dump ("K(1)", plain, plain_len);
216 #endif
217  hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1);
218  if (hc == NULL)
219  goto hkdf_error;
220  GNUNET_memcpy (result, hc, k);
221  result += k;
222  }
223 
224  /* K(i+1) */
225  for (i = 1; i < t; i++)
226  {
227  GNUNET_memcpy (plain, result - k, k);
228  memset (plain + k + ctx_len, i + 1, 1);
229  gcry_md_reset (prf);
230 #if DEBUG_HKDF
231  dump ("K(i+1)", plain, plain_len);
232 #endif
233  hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
234  if (hc == NULL)
235  goto hkdf_error;
236  GNUNET_memcpy (result, hc, k);
237  result += k;
238  }
239 
240  /* K(t):d */
241  if (d > 0)
242  {
243  if (t > 0)
244  {
245  GNUNET_memcpy (plain, result - k, k);
246  i++;
247  }
248  memset (plain + k + ctx_len, i, 1);
249  gcry_md_reset (prf);
250 #if DEBUG_HKDF
251  dump ("K(t):d", plain, plain_len);
252 #endif
253  if (t > 0)
254  hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
255  else
256  hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k);
257  if (hc == NULL)
258  goto hkdf_error;
259  GNUNET_memcpy (result, hc, d);
260  }
261 #if DEBUG_HKDF
262  dump ("result", result - k, out_len);
263 #endif
264 
265  ret = GNUNET_YES;
266  goto hkdf_ok;
267  }
268 hkdf_error:
269  ret = GNUNET_SYSERR;
270 hkdf_ok:
271  gcry_md_close (xtr);
272  gcry_md_close (prf);
273  BENCHMARK_END (hkdf);
274  return ret;
275 }
276 
277 
290 int
291 GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo,
292  const void *xts, size_t xts_len, const void *skm,
293  size_t skm_len, ...)
294 {
295  va_list argp;
296  int ret;
297 
298  va_start (argp, skm_len);
299  ret =
300  GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, xts_len,
301  skm, skm_len, argp);
302  va_end (argp);
303 
304  return ret;
305 }
306 
307 
308 /* 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:291
static struct GNUNET_SCHEDULER_Task * t
Main task.
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.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
#define GNUNET_YES
Definition: gnunet_common.h:77
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.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...