X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Futil%2Fcrypto_hkdf.c;h=494f3d0ab9efcda76f4fc560bfb3ccbecefde1de;hb=bb83cd2d04ff5a3f7a8d05fc9a724b0246e958b6;hp=1d0deeacbedb4d76d249f66f5ab9b707f3c426b8;hpb=c75af8bb6df74bfcba1e7b1a3123babf066a1939;p=oweals%2Fgnunet.git diff --git a/src/util/crypto_hkdf.c b/src/util/crypto_hkdf.c index 1d0deeacb..494f3d0ab 100644 --- a/src/util/crypto_hkdf.c +++ b/src/util/crypto_hkdf.c @@ -22,18 +22,47 @@ /** * @file src/util/crypto_hkdf.c - * @brief Hash-based KDF as defined in draft-krawczyk-hkdf-01 - * @see http://tools.ietf.org/html/draft-krawczyk-hkdf-01 + * @brief Hash-based KDF as defined in RFC 5869 + * @see http://www.rfc-editor.org/rfc/rfc5869.txt + * @todo remove GNUNET references * @author Nils Durner + * + * The following list of people have reviewed this code and considered + * it correct on the date given (if you reviewed it, please + * have your name added to the list): + * + * - Christian Grothoff (08.10.2010) + * - Nathan Evans (08.10.2010) + * - Matthias Wachs (08.10.2010) */ -#include +/** + * Set this to 0 if you compile this code outside of GNUnet. + */ +#define GNUNET_BUILD 1 + +/** + * Enable debugging. + */ +#define DEBUG_HKDF 0 + +#if GNUNET_BUILD #include "platform.h" #include "gnunet_crypto_lib.h" +#else +#define GNUNET_NO 0 +#define GNUNET_YES 1 +#define GNUNET_SYSERR -1 +#include +#endif + +#include + /** * @brief Compute the HMAC + * @todo use chunked buffers * @param mac gcrypt MAC handle * @param key HMAC key * @param key_len length of key @@ -41,14 +70,15 @@ * @param buf_len length of buf * @return HMAC, freed by caller via gcry_md_close/_reset */ -static void * -doHMAC (gcry_md_hd_t mac, const void *key, const size_t key_len, - const void *buf, const size_t buf_len) +static const void * +doHMAC (gcry_md_hd_t mac, + const void *key, size_t key_len, + const void *buf, size_t buf_len) { gcry_md_setkey (mac, key, key_len); gcry_md_write (mac, buf, buf_len); - return (void *) gcry_md_read (mac, 0); + return (const void *) gcry_md_read (mac, 0); } /** @@ -62,87 +92,130 @@ doHMAC (gcry_md_hd_t mac, const void *key, const size_t key_len, * @return GNUNET_YES on success */ static int -getPRK (gcry_md_hd_t mac, const void *xts, const unsigned long long xts_len, - const void *skm, const unsigned long long skm_len, void *prk) +getPRK (gcry_md_hd_t mac, + const void *xts, size_t xts_len, + const void *skm, size_t skm_len, + void *prk) { - void *ret; + const void *ret; ret = doHMAC (mac, xts, xts_len, skm, skm_len); if (ret == NULL) return GNUNET_SYSERR; - memcpy (prk, ret, gcry_md_get_algo_dlen (gcry_md_get_algo (mac))); + memcpy (prk, + ret, + gcry_md_get_algo_dlen (gcry_md_get_algo (mac))); return GNUNET_YES; } -static void dump(void *p, unsigned int l) + +#if DEBUG_HKDF +static void +dump(const char *src, + const void *p, + unsigned int l) { unsigned int i; - printf("\n"); + printf("\n%s: ", src); for (i = 0; i < l; i++) { - printf("%2x", ((char *) p)[i]); + printf("%2x", (int) ((const unsigned char *) p)[i]); } printf("\n"); } +#endif + /** * @brief Derive key + * @param result buffer for the derived key, allocated by caller + * @param out_len desired length of the derived key * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... * @param xts salt * @param xts_len length of xts * @param skm source key material * @param skm_len length of skm - * @param ctx context info - * @param ctx_len length of ctx - * @param out_len desired length of the derived key - * @param result buffer for the derived key, allocated by caller + * @param argp va_list of void * & size_t pairs for context chunks * @return GNUNET_YES on success */ int -GNUNET_CRYPTO_hkdf (int xtr_algo, int prf_algo, const void *xts, - const size_t xts_len, const void *skm, const size_t skm_len, - const void *ctx, const size_t ctx_len, const unsigned long long out_len, - void *result) +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) { - void *prk, *hc, *plain; - unsigned long long plain_len; + const void *hc; unsigned long i, t, d; - unsigned int k, xtr_len; + unsigned int k = gcry_md_get_algo_dlen (prf_algo); + unsigned int xtr_len = gcry_md_get_algo_dlen (xtr_algo); + char prk[xtr_len]; int ret; gcry_md_hd_t xtr, prf; + size_t ctx_len; + va_list args; - prk = plain = NULL; - xtr_len = gcry_md_get_algo_dlen (xtr_algo); - k = gcry_md_get_algo_dlen (prf_algo); - gcry_md_open(&xtr, xtr_algo, GCRY_MD_FLAG_HMAC); - gcry_md_open(&prf, prf_algo, GCRY_MD_FLAG_HMAC); + if (k == 0) + return GNUNET_SYSERR; + + if (gcry_md_open(&xtr, xtr_algo, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR) + return GNUNET_SYSERR; - if (out_len > (2 ^ 32 * k) || !xtr_algo || !prf_algo) + if (gcry_md_open(&prf, prf_algo, GCRY_MD_FLAG_HMAC) != GPG_ERR_NO_ERROR) + { + gcry_md_close (xtr); return GNUNET_SYSERR; + } - prk = GNUNET_malloc (xtr_len); + va_copy (args, argp); + + ctx_len = 0; + while (NULL != va_arg (args, void *)) + ctx_len += va_arg (args, size_t); + va_end(args); memset (result, 0, out_len); - gcry_md_reset (xtr); if (getPRK (xtr, xts, xts_len, skm, skm_len, prk) != GNUNET_YES) goto hkdf_error; -dump(prk, xtr_len); +#if DEBUG_HKDF + dump("PRK", prk, xtr_len); +#endif - /* K(1) */ - plain_len = k + ctx_len + 4; - plain = GNUNET_malloc (plain_len); - memset (plain, 0, k); - memcpy (plain + k, ctx, ctx_len); t = out_len / k; + d = out_len % k; + + /* K(1) */ + { + size_t plain_len = k + ctx_len + 1; + char plain[plain_len]; + const void *ctx; + char *dst; + + dst = plain + k; + va_copy (args, argp); + while ((ctx = va_arg (args, void *))) + { + size_t len; + + len = va_arg (args, size_t); + memcpy (dst, ctx, len); + dst += len; + } + va_end (args); + if (t > 0) { - memset (plain + k + ctx_len, 0, 4); - gcry_md_reset (prf); - hc = doHMAC (prf, prk, k, plain, plain_len); + memset (plain + k + ctx_len, 1, 1); +#if DEBUG_HKDF + dump("K(1)", plain, plain_len); +#endif + hc = doHMAC (prf, + prk, + xtr_len, &plain[k], ctx_len + 1); if (hc == NULL) goto hkdf_error; memcpy (result, hc, k); @@ -153,9 +226,12 @@ dump(prk, xtr_len); for (i = 1; i < t; i++) { memcpy (plain, result - k, k); - memcpy (plain + k + ctx_len, &i, 4); + memset (plain + k + ctx_len, i + 1, 1); gcry_md_reset (prf); - hc = doHMAC (prf, prk, k, plain, plain_len); +#if DEBUG_HKDF + dump("K(i+1)", plain, plain_len); +#endif + hc = doHMAC (prf, prk, xtr_len, plain, plain_len); if (hc == NULL) goto hkdf_error; memcpy (result, hc, k); @@ -163,27 +239,36 @@ dump(prk, xtr_len); } /* K(t):d */ - d = out_len % k; if (d > 0) { if (t > 0) - memcpy (plain, result - k, k); - memcpy (plain + k + ctx_len, &i, 4); + { + memcpy (plain, result - k, k); + i++; + } + memset (plain + k + ctx_len, i, 1); gcry_md_reset (prf); - hc = doHMAC (prf, prk, k, plain, plain_len); +#if DEBUG_HKDF + dump("K(t):d", plain, plain_len); +#endif + if (t > 0) + hc = doHMAC (prf, prk, xtr_len, plain, plain_len); + else + hc = doHMAC (prf, prk, xtr_len, plain + k, plain_len - k); if (hc == NULL) goto hkdf_error; memcpy (result, hc, d); } +#if DEBUG_HKDF + dump("result", result - k, out_len); +#endif ret = GNUNET_YES; goto hkdf_ok; - + } hkdf_error: ret = GNUNET_SYSERR; hkdf_ok: - GNUNET_free (prk); - GNUNET_free_non_null (plain); gcry_md_close (prf); gcry_md_close (xtr); @@ -191,4 +276,34 @@ hkdf_ok: } +/** + * @brief Derive key + * @param result buffer for the derived key, allocated by caller + * @param out_len desired length of the derived key + * @param xtr_algo hash algorithm for the extraction phase, GCRY_MD_... + * @param prf_algo hash algorithm for the expansion phase, GCRY_MD_... + * @param xts salt + * @param xts_len length of xts + * @param skm source key material + * @param skm_len length of skm + * @return GNUNET_YES on success + */ +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, + ...) +{ + va_list argp; + int ret; + + va_start(argp, skm_len); + ret = GNUNET_CRYPTO_hkdf_v (result, out_len, xtr_algo, prf_algo, xts, + xts_len, skm, skm_len, argp); + va_end(argp); + + return ret; +} + /* end of crypto_hkdf.c */