diff options
Diffstat (limited to 'wsutil/wsgcrypt.c')
-rw-r--r-- | wsutil/wsgcrypt.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/wsutil/wsgcrypt.c b/wsutil/wsgcrypt.c index 9e3a86055c..eef943c272 100644 --- a/wsutil/wsgcrypt.c +++ b/wsutil/wsgcrypt.c @@ -144,6 +144,44 @@ out: return decr_len; } +gcry_error_t +hkdf_expand(int hashalgo, const guint8 *prk, guint prk_len, const guint8 *info, guint info_len, + guint8 *out, guint out_len) +{ + // Current maximum hash output size: 48 bytes for SHA-384. + guchar lastoutput[48]; + gcry_md_hd_t h; + gcry_error_t err; + const guint hash_len = gcry_md_get_algo_dlen(hashalgo); + + /* Some sanity checks */ + if (!(out_len > 0 && out_len <= 255 * hash_len) || + !(hash_len > 0 && hash_len <= sizeof(lastoutput))) { + return GPG_ERR_INV_ARG; + } + + err = gcry_md_open(&h, hashalgo, GCRY_MD_FLAG_HMAC); + if (err) { + return err; + } + + for (guint offset = 0; offset < out_len; offset += hash_len) { + gcry_md_reset(h); + gcry_md_setkey(h, prk, prk_len); /* Set PRK */ + if (offset > 0) { + gcry_md_write(h, lastoutput, hash_len); /* T(1..N) */ + } + gcry_md_write(h, info, info_len); /* info */ + gcry_md_putc(h, (guint8) (offset / hash_len + 1)); /* constant 0x01..N */ + + memcpy(lastoutput, gcry_md_read(h, hashalgo), hash_len); + memcpy(out + offset, lastoutput, MIN(hash_len, out_len - offset)); + } + + gcry_md_close(h); + return 0; +} + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * |