@@ -236,6 +236,79 @@ kdf_hkdf(int argc, VALUE *argv, VALUE self)
236236 return str ;
237237}
238238
239+ #ifdef HAVE_TYPE_EVP_KDF_P
240+ /*
241+ * call-seq:
242+ * KDF.derive(algo, length, params) -> String
243+ *
244+ * Derives _length_ bytes of key material from _params_ using the \KDF algorithm
245+ * specified by the String _algo_.
246+ *
247+ * _params_ is an Enumerable that lists the parameters and their values to be
248+ * passed to the \KDF algorithm. Consult the respective EVP_KDF-* documentation
249+ * for the available parameters.
250+ *
251+ * See the man page EVP_KDF_derive(3) for more information. Available when
252+ * compiled with \OpenSSL 3.0 or later.
253+ *
254+ * === Example
255+ * # See the man page EVP_KDF-PBKDF2(7).
256+ * # RFC 6070 PBKDF2 HMAC-SHA1 Test Vectors, 3rd example
257+ * # https://www.rfc-editor.org/rfc/rfc6070
258+ * ret = OpenSSL::KDF.derive("PBKDF2", 20, {
259+ * "pass" => "password",
260+ * "salt" => "salt",
261+ * "iter" => 4096,
262+ * "digest" => "SHA1",
263+ * })
264+ * p ret.unpack1("H*")
265+ * #=> "4b007901b765489abead49d926f721d065a429c1"
266+ */
267+ static VALUE
268+ kdf_derive (int argc , VALUE * argv , VALUE self )
269+ {
270+ VALUE algo , keylen , hash , out ;
271+ int state ;
272+
273+ rb_scan_args (argc , argv , "21" , & algo , & keylen , & hash );
274+ out = rb_str_new (NULL , NUM2LONG (keylen ));
275+
276+ EVP_KDF * kdf = EVP_KDF_fetch (NULL , StringValueCStr (algo ), NULL );
277+ if (!kdf )
278+ ossl_raise (eKDF , "EVP_KDF_fetch" );
279+
280+ EVP_KDF_CTX * ctx = EVP_KDF_CTX_new (kdf );
281+ if (!ctx ) {
282+ EVP_KDF_free (kdf );
283+ ossl_raise (eKDF , "EVP_KDF_CTX_new" );
284+ }
285+
286+ const OSSL_PARAM * settable = EVP_KDF_CTX_settable_params (ctx );
287+ if (!settable ) {
288+ EVP_KDF_CTX_free (ctx );
289+ EVP_KDF_free (kdf );
290+ ossl_raise (eKDF , "EVP_KDF_CTX_settable_params" );
291+ }
292+
293+ OSSL_PARAM * params = ossl_build_params (settable , hash , & state );
294+ if (state ) {
295+ EVP_KDF_CTX_free (ctx );
296+ EVP_KDF_free (kdf );
297+ rb_jump_tag (state );
298+ }
299+
300+ int ret = EVP_KDF_derive (ctx , (unsigned char * )RSTRING_PTR (out ),
301+ RSTRING_LEN (out ), params );
302+ OSSL_PARAM_free (params );
303+ EVP_KDF_CTX_free (ctx );
304+ EVP_KDF_free (kdf );
305+ if (ret != 1 )
306+ ossl_raise (eKDF , "EVP_KDF_derive" );
307+
308+ return out ;
309+ }
310+ #endif
311+
239312void
240313Init_ossl_kdf (void )
241314{
@@ -302,4 +375,7 @@ Init_ossl_kdf(void)
302375 rb_define_module_function (mKDF , "scrypt" , kdf_scrypt , -1 );
303376#endif
304377 rb_define_module_function (mKDF , "hkdf" , kdf_hkdf , -1 );
378+ #ifdef HAVE_TYPE_EVP_KDF_P
379+ rb_define_module_function (mKDF , "derive" , kdf_derive , -1 );
380+ #endif
305381}
0 commit comments