aboutsummaryrefslogtreecommitdiffstats
path: root/ext/openssl
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2017-11-22 14:14:54 +0900
committerKazuki Yamaguchi <k@rhe.jp>2017-11-22 14:14:54 +0900
commitd8e9c54ae448918217235df87aab8547b2f0738f (patch)
treedfe603781e943192d5764bb8aa733aefda12f7a4 /ext/openssl
parente72d960db2623b21ee001b5a7b9d9e6ff55bdf94 (diff)
downloadruby-openssl-d8e9c54ae448918217235df87aab8547b2f0738f.tar.gz
kdf: add HKDF supportky/kdf-hkdf
OpenSSL 1.1.0 supports HKDF through the EVP API. Add OpenSSL::KDF.hkdf as a wrapper around that. Reference: https://github.com/ruby/openssl/issues/172
Diffstat (limited to 'ext/openssl')
-rw-r--r--ext/openssl/ossl_kdf.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c
index 9fa42e17..ee124718 100644
--- a/ext/openssl/ossl_kdf.c
+++ b/ext/openssl/ossl_kdf.c
@@ -3,6 +3,9 @@
* Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors
*/
#include "ossl.h"
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
+# include <openssl/kdf.h>
+#endif
static VALUE mKDF, eKDF;
@@ -138,6 +141,97 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
}
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
+/*
+ * call-seq:
+ * KDF.hkdf(ikm, salt:, info:, length:, hash:) -> String
+ *
+ * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) as specified in
+ * {RFC 5869}[https://tools.ietf.org/html/rfc5869].
+ *
+ * New in OpenSSL 1.1.0.
+ *
+ * === Parameters
+ * _ikm_::
+ * The input keying material.
+ * _salt_::
+ * The salt.
+ * _info_::
+ * The context and application specific information.
+ * _length_::
+ * The output length in octets. Must be <= <tt>255 * HashLen</tt>, where
+ * HashLen is the length of the hash function output in octets.
+ * _hash_::
+ * The hash function.
+ */
+static VALUE
+kdf_hkdf(int argc, VALUE *argv, VALUE self)
+{
+ VALUE ikm, salt, info, opts, kwargs[4], str;
+ static ID kwargs_ids[4];
+ int saltlen, ikmlen, infolen;
+ size_t len;
+ const EVP_MD *md;
+ EVP_PKEY_CTX *pctx;
+
+ if (!kwargs_ids[0]) {
+ kwargs_ids[0] = rb_intern_const("salt");
+ kwargs_ids[1] = rb_intern_const("info");
+ kwargs_ids[2] = rb_intern_const("length");
+ kwargs_ids[3] = rb_intern_const("hash");
+ }
+ rb_scan_args(argc, argv, "1:", &ikm, &opts);
+ rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);
+
+ StringValue(ikm);
+ ikmlen = RSTRING_LENINT(ikm);
+ salt = StringValue(kwargs[0]);
+ saltlen = RSTRING_LENINT(salt);
+ info = StringValue(kwargs[1]);
+ infolen = RSTRING_LENINT(info);
+ len = (size_t)NUM2LONG(kwargs[2]);
+ if (len > LONG_MAX)
+ rb_raise(rb_eArgError, "length must be non-negative");
+ md = ossl_evp_get_digestbyname(kwargs[3]);
+
+ str = rb_str_new(NULL, (long)len);
+ pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
+ if (!pctx)
+ ossl_raise(eKDF, "EVP_PKEY_CTX_new_id");
+ if (EVP_PKEY_derive_init(pctx) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_derive_init");
+ }
+ if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_md");
+ }
+ if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, (unsigned char *)RSTRING_PTR(salt),
+ saltlen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_salt");
+ }
+ if (EVP_PKEY_CTX_set1_hkdf_key(pctx, (unsigned char *)RSTRING_PTR(ikm),
+ ikmlen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_key");
+ }
+ if (EVP_PKEY_CTX_add1_hkdf_info(pctx, (unsigned char *)RSTRING_PTR(info),
+ infolen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_CTX_set_hkdf_info");
+ }
+ if (EVP_PKEY_derive(pctx, (unsigned char *)RSTRING_PTR(str), &len) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ ossl_raise(eKDF, "EVP_PKEY_derive");
+ }
+ rb_str_set_len(str, (long)len);
+ EVP_PKEY_CTX_free(pctx);
+
+ return str;
+}
+#endif
+
void
Init_ossl_kdf(void)
{
@@ -162,6 +256,7 @@ Init_ossl_kdf(void)
* * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in
* combination with HMAC
* * scrypt
+ * * HKDF
*
* == Examples
* === Generating a 128 bit key for a Cipher (e.g. AES)
@@ -218,4 +313,7 @@ Init_ossl_kdf(void)
#if defined(HAVE_EVP_PBE_SCRYPT)
rb_define_module_function(mKDF, "scrypt", kdf_scrypt, -1);
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
+ rb_define_module_function(mKDF, "hkdf", kdf_hkdf, -1);
+#endif
}