aboutsummaryrefslogtreecommitdiffstats
path: root/wsutil/wsgcrypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'wsutil/wsgcrypt.c')
-rw-r--r--wsutil/wsgcrypt.c38
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
*