2 Copyright (c) 2010 Nils Durner
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:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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
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
33 #include "gnunet_crypto_lib.h"
35 #define DEBUG_HKDF GNUNET_NO
38 * @brief Compute the HMAC
39 * @param mac gcrypt MAC handle
41 * @param key_len length of key
42 * @param buf message to be processed
43 * @param buf_len length of buf
44 * @return HMAC, freed by caller via gcry_md_close/_reset
47 doHMAC (gcry_md_hd_t mac,
48 const void *key, size_t key_len,
49 const void *buf, size_t buf_len)
51 gcry_md_setkey (mac, key, key_len);
52 gcry_md_write (mac, buf, buf_len);
54 return (void *) gcry_md_read (mac, 0);
58 * @brief Generate pseudo-random key
59 * @param mac gcrypt HMAC handle
61 * @param xts_len length of the salt
62 * @param skm source key material
63 * @param skm_len length of skm
64 * @param prk result buffer (allocated by caller; at least gcry_md_dlen() bytes)
65 * @return GNUNET_YES on success
68 getPRK (gcry_md_hd_t mac,
69 const void *xts, unsigned long long xts_len, /* FIXME: size_t? */
70 const void *skm, unsigned long long skm_len,
75 ret = doHMAC (mac, xts, xts_len, skm, skm_len);
78 memcpy (prk, ret, gcry_md_get_algo_dlen (gcry_md_get_algo (mac)));
92 printf("\n%s: ", src);
93 for (i = 0; i < l; i++)
95 printf("%2x", (int) ((const unsigned char *) p)[i]);
104 * @param result buffer for the derived key, allocated by caller
105 * @param out_len desired length of the derived key
106 * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_...
107 * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_...
109 * @param xts_len length of xts
110 * @param skm source key material
111 * @param skm_len length of skm
112 * @param argp va_list of void * & size_t pairs for context chunks
113 * @return GNUNET_YES on success
116 GNUNET_CRYPTO_hkdf_v (void *result, unsigned long long out_len,
117 int xtr_algo, int prf_algo,
118 const void *xts, size_t xts_len,
119 const void *skm, size_t skm_len,
122 void *prk, *hc, *plain;
123 unsigned long long plain_len;
124 unsigned long i, t, d;
125 unsigned int k, xtr_len;
127 gcry_md_hd_t xtr, prf;
132 xtr_len = gcry_md_get_algo_dlen (xtr_algo);
133 k = gcry_md_get_algo_dlen (prf_algo);
134 gcry_md_open(&xtr, xtr_algo, GCRY_MD_FLAG_HMAC);
135 gcry_md_open(&prf, prf_algo, GCRY_MD_FLAG_HMAC);
137 if (out_len > (2 ^ 32 * k) || !xtr_algo || !prf_algo)
138 return GNUNET_SYSERR;
140 va_copy (args, argp);
141 for (ctx_len = 0; va_arg (args, void *);)
142 ctx_len += va_arg (args, size_t);
145 prk = GNUNET_malloc (xtr_len);
147 memset (result, 0, out_len);
149 if (getPRK (xtr, xts, xts_len, skm, skm_len, prk)
153 dump("PRK", prk, xtr_len);
160 plain_len = k + ctx_len + 1;
161 plain = GNUNET_malloc (plain_len);
167 va_copy (args, argp);
168 while ((ctx = va_arg (args, void *)))
172 len = va_arg (args, size_t);
173 memcpy (dst, ctx, len);
181 dump("K(1)", plain, plain_len);
183 hc = doHMAC (prf, prk, xtr_len, plain, ctx_len + 1);
186 memcpy (result, hc, k);
195 va_copy (args, argp);
196 while ((ctx = va_arg (args, void *)))
200 len = va_arg (args, size_t);
201 memcpy (dst, ctx, len);
208 for (i = 1; i < t; i++)
210 memcpy (plain, result - k, k);
211 memset (plain + k + ctx_len, i + 1, 1);
214 dump("K(i+1)", plain, plain_len);
216 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
219 memcpy (result, hc, k);
227 memcpy (plain, result - k, k);
228 memset (plain + k + ctx_len, i + 1, 1);
231 dump("K(t):d", plain, plain_len);
233 hc = doHMAC (prf, prk, xtr_len, plain, plain_len);
236 memcpy (result, hc, d);
239 dump("result", result - k, out_len);
249 GNUNET_free_non_null (plain);
259 * @param result buffer for the derived key, allocated by caller
260 * @param out_len desired length of the derived key
261 * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_...
262 * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_...
264 * @param xts_len length of xts
265 * @param skm source key material
266 * @param skm_len length of skm
267 * @param ctx context info
268 * @param ctx_len length of ctx
269 * @return GNUNET_YES on success
272 GNUNET_CRYPTO_hkdf (void *result, unsigned long long out_len,
273 int xtr_algo, int prf_algo,
274 const void *xts, size_t xts_len,
275 const void *skm, size_t skm_len,
281 va_start(argp, skm_len);
282 ret = GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts,
283 xts_len, skm, skm_len, argp);
289 /* end of crypto_hkdf.c */