GNUnet  0.10.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 
53 #if GNUNET_BUILD
54 #include "platform.h"
55 #include "gnunet_crypto_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 
77 static const void *
78 doHMAC (gcry_md_hd_t mac, const void *key, size_t key_len, const void *buf,
79  size_t buf_len)
80 {
81  gcry_md_setkey (mac, key, key_len);
82  gcry_md_write (mac, buf, buf_len);
83 
84  return (const void *) gcry_md_read (mac, 0);
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 #endif
126 
127 
141 int
142 GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo,
143  const void *xts, size_t xts_len, const void *skm,
144  size_t skm_len, va_list argp)
145 {
146  gcry_md_hd_t xtr;
147  gcry_md_hd_t prf;
148  const void *hc;
149  unsigned long i;
150  unsigned long t;
151  unsigned long d;
152  unsigned int k = gcry_md_get_algo_dlen (prf_algo);
153  unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo);
154  char prk[xtr_len];
155  int ret;
156  size_t ctx_len;
157  va_list args;
158 
159  BENCHMARK_START (hkdf);
160 
161  if (0 == k)
162  return GNUNET_SYSERR;
163  if (GPG_ERR_NO_ERROR !=
164  gcry_md_open (&xtr, xtr_algo, GCRY_MD_FLAG_HMAC))
165  return GNUNET_SYSERR;
166  if (GPG_ERR_NO_ERROR !=
167  gcry_md_open (&prf, prf_algo, GCRY_MD_FLAG_HMAC))
168  {
169  gcry_md_close (xtr);
170  return GNUNET_SYSERR;
171  }
172  va_copy (args, argp);
173 
174  ctx_len = 0;
175  while (NULL != va_arg (args, void *))
176  ctx_len += va_arg (args, size_t);
177 
178  va_end (args);
179 
180  memset (result, 0, out_len);
181  if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES)
182  goto hkdf_error;
183 #if DEBUG_HKDF
184  dump ("PRK", prk, xtr_len);
185 #endif
186 
187  t = out_len / k;
188  d = out_len % k;
189 
190  /* K(1) */
191  {
192  size_t plain_len = k + ctx_len + 1;
193  char plain[plain_len];
194  const void *ctx;
195  char *dst;
196 
197  dst = plain + k;
198  va_copy (args, argp);
199  while ((ctx = va_arg (args, void *)))
200  {
201  size_t len;
202 
203  len = va_arg (args, size_t);
204  GNUNET_memcpy (dst, ctx, len);
205  dst += len;
206  }
207  va_end (args);
208 
209  if (t > 0)
210  {
211  memset (plain + k + ctx_len, 1, 1);
212 #if DEBUG_HKDF
213  dump ("K(1)", plain, plain_len);
214 #endif
215  hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1);
216  if (hc == NULL)
217  goto hkdf_error;
218  GNUNET_memcpy (result, hc, k);
219  result += k;
220  }
221 
222  /* K(i+1) */
223  for (i = 1; i < t; i++)
224  {
225  GNUNET_memcpy (plain, result - k, k);
226  memset (plain + k + ctx_len, i + 1, 1);
227  gcry_md_reset (prf);
228 #if DEBUG_HKDF
229  dump ("K(i+1)", plain, plain_len);
230 #endif
231  hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
232  if (hc == NULL)
233  goto hkdf_error;
234  GNUNET_memcpy (result, hc, k);
235  result += k;
236  }
237 
238  /* K(t):d */
239  if (d > 0)
240  {
241  if (t > 0)
242  {
243  GNUNET_memcpy (plain, result - k, k);
244  i++;
245  }
246  memset (plain + k + ctx_len, i, 1);
247  gcry_md_reset (prf);
248 #if DEBUG_HKDF
249  dump ("K(t):d", plain, plain_len);
250 #endif
251  if (t > 0)
252  hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
253  else
254  hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k);
255  if (hc == NULL)
256  goto hkdf_error;
257  GNUNET_memcpy (result, hc, d);
258  }
259 #if DEBUG_HKDF
260  dump ("result", result - k, out_len);
261 #endif
262 
263  ret = GNUNET_YES;
264  goto hkdf_ok;
265  }
266 hkdf_error:
267  ret = GNUNET_SYSERR;
268 hkdf_ok:
269  gcry_md_close (xtr);
270  gcry_md_close (prf);
271  BENCHMARK_END (hkdf);
272  return ret;
273 }
274 
275 
288 int
289 GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo,
290  const void *xts, size_t xts_len, const void *skm,
291  size_t skm_len, ...)
292 {
293  va_list argp;
294  int ret;
295 
296  va_start (argp, skm_len);
297  ret =
298  GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, xts_len,
299  skm, skm_len, argp);
300  va_end (argp);
301 
302  return ret;
303 }
304 
305 /* 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:142
#define BENCHMARK_START(opname)
Definition: benchmark.h:53
#define BENCHMARK_END(opname)
Definition: benchmark.h:54
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:289
static struct GNUNET_SCHEDULER_Task * t
Main task.
static int ret
Final status code.
Definition: gnunet-arm.c:89
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
static struct LoggingHandle * l
cryptographic primitives for GNUnet
#define GNUNET_memcpy(dst, src, n)
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:79
#define GNUNET_YES
Definition: gnunet_common.h:80
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
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...