aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_hkdf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/crypto_hkdf.c')
-rw-r--r--src/util/crypto_hkdf.c341
1 files changed, 0 insertions, 341 deletions
diff --git a/src/util/crypto_hkdf.c b/src/util/crypto_hkdf.c
deleted file mode 100644
index 7270b87b6..000000000
--- a/src/util/crypto_hkdf.c
+++ /dev/null
@@ -1,341 +0,0 @@
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
23/**
24 * @file src/util/crypto_hkdf.c
25 * @brief Hash-based KDF as defined in RFC 5869
26 * @see http://www.rfc-editor.org/rfc/rfc5869.txt
27 * @todo remove GNUNET references
28 * @author Nils Durner
29 *
30 * The following list of people have reviewed this code and considered
31 * it correct on the date given (if you reviewed it, please
32 * have your name added to the list):
33 *
34 * - Christian Grothoff (08.10.2010)
35 * - Nathan Evans (08.10.2010)
36 * - Matthias Wachs (08.10.2010)
37 */
38
39#define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-hkdf", __VA_ARGS__)
40
41/**
42 * Set this to 0 if you compile this code outside of GNUnet.
43 */
44#define GNUNET_BUILD 1
45
46/**
47 * Enable debugging.
48 */
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
66/**
67 * @brief Compute the HMAC
68 * @todo use chunked buffers
69 * @param mac gcrypt MAC handle
70 * @param key HMAC key
71 * @param key_len length of key
72 * @param buf message to be processed
73 * @param buf_len length of buf
74 * @return HMAC, freed by caller via gcry_md_close/_reset
75 */
76static const void *
77doHMAC (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
91/**
92 * @brief Generate pseudo-random key
93 * @param mac gcrypt HMAC handle
94 * @param xts salt
95 * @param xts_len length of the @a xts salt
96 * @param skm source key material
97 * @param skm_len length of @a skm
98 * @param prk result buffer (allocated by caller; at least gcry_md_dlen() bytes)
99 * @return #GNUNET_YES on success
100 */
101static int
102getPRK (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
117static void
118dump (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
134/**
135 * @brief Derive key
136 * @param result buffer for the derived key, allocated by caller
137 * @param out_len desired length of the derived key
138 * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_...
139 * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_...
140 * @param xts salt
141 * @param xts_len length of @a xts
142 * @param skm source key material
143 * @param skm_len length of @a skm
144 * @param argp va_list of void * & size_t pairs for context chunks
145 * @return #GNUNET_YES on success
146 */
147int
148GNUNET_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 }
301hkdf_error:
302 ret = GNUNET_SYSERR;
303hkdf_ok:
304 gcry_md_close (xtr);
305 gcry_md_close (prf);
306 BENCHMARK_END (hkdf);
307 return ret;
308}
309
310
311/**
312 * @brief Derive key
313 * @param result buffer for the derived key, allocated by caller
314 * @param out_len desired length of the derived key
315 * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_...
316 * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_...
317 * @param xts salt
318 * @param xts_len length of @a xts
319 * @param skm source key material
320 * @param skm_len length of @a skm
321 * @return #GNUNET_YES on success
322 */
323int
324GNUNET_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 */