diff options
Diffstat (limited to 'src/util/crypto_hkdf.c')
-rw-r--r-- | src/util/crypto_hkdf.c | 360 |
1 files changed, 0 insertions, 360 deletions
diff --git a/src/util/crypto_hkdf.c b/src/util/crypto_hkdf.c deleted file mode 100644 index 4e4496819..000000000 --- a/src/util/crypto_hkdf.c +++ /dev/null | |||
@@ -1,360 +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 | */ | ||
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 | |||
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 | */ | ||
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 | size_t dlen; | ||
107 | |||
108 | dlen = gcry_md_get_algo_dlen (gcry_md_get_algo (mac)); | ||
109 | |||
110 | /* sanity check to bound stack allocation */ | ||
111 | GNUNET_assert (dlen <= 512); | ||
112 | |||
113 | /* From RFC 5869: | ||
114 | * salt - optional salt value (a non-secret random value); | ||
115 | * if not provided, it is set to a string of HashLen zeros. */ | ||
116 | |||
117 | if (xts_len == 0) | ||
118 | { | ||
119 | char zero_salt[dlen]; | ||
120 | memset (zero_salt, 0, dlen); | ||
121 | ret = doHMAC (mac, zero_salt, dlen, skm, skm_len); | ||
122 | } | ||
123 | else | ||
124 | { | ||
125 | ret = doHMAC (mac, xts, xts_len, skm, skm_len); | ||
126 | } | ||
127 | if (ret == NULL) | ||
128 | return GNUNET_SYSERR; | ||
129 | GNUNET_memcpy (prk, ret, dlen); | ||
130 | |||
131 | return GNUNET_YES; | ||
132 | } | ||
133 | |||
134 | |||
135 | #if DEBUG_HKDF | ||
136 | static void | ||
137 | dump (const char *src, const void *p, unsigned int l) | ||
138 | { | ||
139 | unsigned int i; | ||
140 | |||
141 | printf ("\n%s: ", src); | ||
142 | for (i = 0; i < l; i++) | ||
143 | { | ||
144 | printf ("%2x", (int) ((const unsigned char *) p)[i]); | ||
145 | } | ||
146 | printf ("\n"); | ||
147 | } | ||
148 | |||
149 | |||
150 | #endif | ||
151 | |||
152 | |||
153 | /** | ||
154 | * @brief Derive key | ||
155 | * @param result buffer for the derived key, allocated by caller | ||
156 | * @param out_len desired length of the derived key | ||
157 | * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... | ||
158 | * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... | ||
159 | * @param xts salt | ||
160 | * @param xts_len length of @a xts | ||
161 | * @param skm source key material | ||
162 | * @param skm_len length of @a skm | ||
163 | * @param argp va_list of void * & size_t pairs for context chunks | ||
164 | * @return #GNUNET_YES on success | ||
165 | */ | ||
166 | int | ||
167 | GNUNET_CRYPTO_hkdf_v (void *result, size_t out_len, int xtr_algo, int prf_algo, | ||
168 | const void *xts, size_t xts_len, const void *skm, | ||
169 | size_t skm_len, va_list argp) | ||
170 | { | ||
171 | gcry_md_hd_t xtr; | ||
172 | gcry_md_hd_t prf; | ||
173 | const void *hc; | ||
174 | unsigned long i; | ||
175 | unsigned long t; | ||
176 | unsigned long d; | ||
177 | unsigned int k = gcry_md_get_algo_dlen (prf_algo); | ||
178 | unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo); | ||
179 | char prk[xtr_len]; | ||
180 | int ret; | ||
181 | size_t ctx_len; | ||
182 | va_list args; | ||
183 | |||
184 | BENCHMARK_START (hkdf); | ||
185 | |||
186 | if (0 == k) | ||
187 | return GNUNET_SYSERR; | ||
188 | if (GPG_ERR_NO_ERROR != | ||
189 | gcry_md_open (&xtr, xtr_algo, GCRY_MD_FLAG_HMAC)) | ||
190 | return GNUNET_SYSERR; | ||
191 | if (GPG_ERR_NO_ERROR != | ||
192 | gcry_md_open (&prf, prf_algo, GCRY_MD_FLAG_HMAC)) | ||
193 | { | ||
194 | gcry_md_close (xtr); | ||
195 | return GNUNET_SYSERR; | ||
196 | } | ||
197 | va_copy (args, argp); | ||
198 | |||
199 | ctx_len = 0; | ||
200 | while (NULL != va_arg (args, void *)) | ||
201 | { | ||
202 | size_t nxt = va_arg (args, size_t); | ||
203 | if (nxt + ctx_len < nxt) | ||
204 | { | ||
205 | /* integer overflow */ | ||
206 | GNUNET_break (0); | ||
207 | va_end (args); | ||
208 | goto hkdf_error; | ||
209 | } | ||
210 | ctx_len += nxt; | ||
211 | } | ||
212 | |||
213 | va_end (args); | ||
214 | |||
215 | if ( (k + ctx_len < ctx_len) || | ||
216 | (k + ctx_len + 1 < ctx_len) ) | ||
217 | { | ||
218 | /* integer overflow */ | ||
219 | GNUNET_break (0); | ||
220 | goto hkdf_error; | ||
221 | } | ||
222 | |||
223 | memset (result, 0, out_len); | ||
224 | if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES) | ||
225 | goto hkdf_error; | ||
226 | #if DEBUG_HKDF | ||
227 | dump ("PRK", prk, xtr_len); | ||
228 | #endif | ||
229 | |||
230 | t = out_len / k; | ||
231 | d = out_len % k; | ||
232 | |||
233 | /* K(1) */ | ||
234 | { | ||
235 | size_t plain_len = k + ctx_len + 1; | ||
236 | char *plain; | ||
237 | const void *ctx; | ||
238 | char *dst; | ||
239 | |||
240 | plain = GNUNET_malloc (plain_len); | ||
241 | dst = plain + k; | ||
242 | va_copy (args, argp); | ||
243 | while ((ctx = va_arg (args, void *))) | ||
244 | { | ||
245 | size_t len; | ||
246 | |||
247 | len = va_arg (args, size_t); | ||
248 | GNUNET_memcpy (dst, ctx, len); | ||
249 | dst += len; | ||
250 | } | ||
251 | va_end (args); | ||
252 | |||
253 | if (t > 0) | ||
254 | { | ||
255 | plain[k + ctx_len] = (char) 1; | ||
256 | #if DEBUG_HKDF | ||
257 | dump ("K(1)", plain, plain_len); | ||
258 | #endif | ||
259 | hc = doHMAC (prf, prk, xtr_len, &plain[k], ctx_len + 1); | ||
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(i+1) */ | ||
270 | for (i = 1; i < t; i++) | ||
271 | { | ||
272 | GNUNET_memcpy (plain, result - k, k); | ||
273 | plain[k + ctx_len] = (char) (i + 1); | ||
274 | gcry_md_reset (prf); | ||
275 | #if DEBUG_HKDF | ||
276 | dump ("K(i+1)", plain, plain_len); | ||
277 | #endif | ||
278 | hc = doHMAC (prf, prk, xtr_len, plain, plain_len); | ||
279 | if (hc == NULL) | ||
280 | { | ||
281 | GNUNET_free (plain); | ||
282 | goto hkdf_error; | ||
283 | } | ||
284 | GNUNET_memcpy (result, hc, k); | ||
285 | result += k; | ||
286 | } | ||
287 | |||
288 | /* K(t):d */ | ||
289 | if (d > 0) | ||
290 | { | ||
291 | if (t > 0) | ||
292 | { | ||
293 | GNUNET_memcpy (plain, result - k, k); | ||
294 | i++; | ||
295 | } | ||
296 | plain[k + ctx_len] = (char) i; | ||
297 | gcry_md_reset (prf); | ||
298 | #if DEBUG_HKDF | ||
299 | dump ("K(t):d", plain, plain_len); | ||
300 | #endif | ||
301 | if (t > 0) | ||
302 | hc = doHMAC (prf, prk, xtr_len, plain, plain_len); | ||
303 | else | ||
304 | hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k); | ||
305 | if (hc == NULL) | ||
306 | { | ||
307 | GNUNET_free (plain); | ||
308 | goto hkdf_error; | ||
309 | } | ||
310 | GNUNET_memcpy (result, hc, d); | ||
311 | } | ||
312 | #if DEBUG_HKDF | ||
313 | dump ("result", result - k, out_len); | ||
314 | #endif | ||
315 | |||
316 | ret = GNUNET_YES; | ||
317 | GNUNET_free (plain); | ||
318 | goto hkdf_ok; | ||
319 | } | ||
320 | hkdf_error: | ||
321 | ret = GNUNET_SYSERR; | ||
322 | hkdf_ok: | ||
323 | gcry_md_close (xtr); | ||
324 | gcry_md_close (prf); | ||
325 | BENCHMARK_END (hkdf); | ||
326 | return ret; | ||
327 | } | ||
328 | |||
329 | |||
330 | /** | ||
331 | * @brief Derive key | ||
332 | * @param result buffer for the derived key, allocated by caller | ||
333 | * @param out_len desired length of the derived key | ||
334 | * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... | ||
335 | * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... | ||
336 | * @param xts salt | ||
337 | * @param xts_len length of @a xts | ||
338 | * @param skm source key material | ||
339 | * @param skm_len length of @a skm | ||
340 | * @return #GNUNET_YES on success | ||
341 | */ | ||
342 | int | ||
343 | GNUNET_CRYPTO_hkdf (void *result, size_t out_len, int xtr_algo, int prf_algo, | ||
344 | const void *xts, size_t xts_len, const void *skm, | ||
345 | size_t skm_len, ...) | ||
346 | { | ||
347 | va_list argp; | ||
348 | int ret; | ||
349 | |||
350 | va_start (argp, skm_len); | ||
351 | ret = | ||
352 | GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, xts_len, | ||
353 | skm, skm_len, argp); | ||
354 | va_end (argp); | ||
355 | |||
356 | return ret; | ||
357 | } | ||
358 | |||
359 | |||
360 | /* end of crypto_hkdf.c */ | ||