33 * Copyright (C) 2007, 2017 Ruby/OpenSSL Project Authors
44 */
55#include "ossl.h"
6+ #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER )
7+ # include <openssl/kdf.h>
8+ #endif
69
710static VALUE mKDF , eKDF ;
811
@@ -138,6 +141,97 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
138141}
139142#endif
140143
144+ #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER )
145+ /*
146+ * call-seq:
147+ * KDF.hkdf(ikm, salt:, info:, length:, hash:) -> String
148+ *
149+ * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) as specified in
150+ * {RFC 5869}[https://tools.ietf.org/html/rfc5869].
151+ *
152+ * New in OpenSSL 1.1.0.
153+ *
154+ * === Parameters
155+ * _ikm_::
156+ * The input keying material.
157+ * _salt_::
158+ * The salt.
159+ * _info_::
160+ * The context and application specific information.
161+ * _length_::
162+ * The output length in octets. Must be <= <tt>255 * HashLen</tt>, where
163+ * HashLen is the length of the hash function output in octets.
164+ * _hash_::
165+ * The hash function.
166+ */
167+ static VALUE
168+ kdf_hkdf (int argc , VALUE * argv , VALUE self )
169+ {
170+ VALUE ikm , salt , info , opts , kwargs [4 ], str ;
171+ static ID kwargs_ids [4 ];
172+ int saltlen , ikmlen , infolen ;
173+ size_t len ;
174+ const EVP_MD * md ;
175+ EVP_PKEY_CTX * pctx ;
176+
177+ if (!kwargs_ids [0 ]) {
178+ kwargs_ids [0 ] = rb_intern_const ("salt" );
179+ kwargs_ids [1 ] = rb_intern_const ("info" );
180+ kwargs_ids [2 ] = rb_intern_const ("length" );
181+ kwargs_ids [3 ] = rb_intern_const ("hash" );
182+ }
183+ rb_scan_args (argc , argv , "1:" , & ikm , & opts );
184+ rb_get_kwargs (opts , kwargs_ids , 4 , 0 , kwargs );
185+
186+ StringValue (ikm );
187+ ikmlen = RSTRING_LENINT (ikm );
188+ salt = StringValue (kwargs [0 ]);
189+ saltlen = RSTRING_LENINT (salt );
190+ info = StringValue (kwargs [1 ]);
191+ infolen = RSTRING_LENINT (info );
192+ len = (size_t )NUM2LONG (kwargs [2 ]);
193+ if (len > LONG_MAX )
194+ rb_raise (rb_eArgError , "length must be non-negative" );
195+ md = ossl_evp_get_digestbyname (kwargs [3 ]);
196+
197+ str = rb_str_new (NULL , (long )len );
198+ pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF , NULL );
199+ if (!pctx )
200+ ossl_raise (eKDF , "EVP_PKEY_CTX_new_id" );
201+ if (EVP_PKEY_derive_init (pctx ) <= 0 ) {
202+ EVP_PKEY_CTX_free (pctx );
203+ ossl_raise (eKDF , "EVP_PKEY_derive_init" );
204+ }
205+ if (EVP_PKEY_CTX_set_hkdf_md (pctx , md ) <= 0 ) {
206+ EVP_PKEY_CTX_free (pctx );
207+ ossl_raise (eKDF , "EVP_PKEY_CTX_set_hkdf_md" );
208+ }
209+ if (EVP_PKEY_CTX_set1_hkdf_salt (pctx , (unsigned char * )RSTRING_PTR (salt ),
210+ saltlen ) <= 0 ) {
211+ EVP_PKEY_CTX_free (pctx );
212+ ossl_raise (eKDF , "EVP_PKEY_CTX_set_hkdf_salt" );
213+ }
214+ if (EVP_PKEY_CTX_set1_hkdf_key (pctx , (unsigned char * )RSTRING_PTR (ikm ),
215+ ikmlen ) <= 0 ) {
216+ EVP_PKEY_CTX_free (pctx );
217+ ossl_raise (eKDF , "EVP_PKEY_CTX_set_hkdf_key" );
218+ }
219+ if (EVP_PKEY_CTX_add1_hkdf_info (pctx , (unsigned char * )RSTRING_PTR (info ),
220+ infolen ) <= 0 ) {
221+ EVP_PKEY_CTX_free (pctx );
222+ ossl_raise (eKDF , "EVP_PKEY_CTX_set_hkdf_info" );
223+ }
224+ if (EVP_PKEY_derive (pctx , (unsigned char * )RSTRING_PTR (str ), & len ) <= 0 ) {
225+ EVP_PKEY_CTX_free (pctx );
226+ ossl_raise (eKDF , "EVP_PKEY_derive" );
227+ }
228+ rb_str_set_len (str , (long )len );
229+ EVP_PKEY_CTX_free (pctx );
230+
231+ return str ;
232+ }
233+ #endif
234+
141235void
142236Init_ossl_kdf (void )
143237{
@@ -162,6 +256,7 @@ Init_ossl_kdf(void)
162256 * * PKCS #5 PBKDF2 (Password-Based Key Derivation Function 2) in
163257 * combination with HMAC
164258 * * scrypt
259+ * * HKDF
165260 *
166261 * == Examples
167262 * === Generating a 128 bit key for a Cipher (e.g. AES)
@@ -218,4 +313,7 @@ Init_ossl_kdf(void)
218313#if defined(HAVE_EVP_PBE_SCRYPT )
219314 rb_define_module_function (mKDF , "scrypt" , kdf_scrypt , -1 );
220315#endif
316+ #if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER )
317+ rb_define_module_function (mKDF , "hkdf" , kdf_hkdf , -1 );
318+ #endif
221319}
0 commit comments