summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2025-08-05 17:36:05 +0900
committergit <svn-admin@ruby-lang.org>2026-04-08 11:08:25 +0000
commit5c7e3c202a74f7e39fa8f0d9cb66055ba7d57d43 (patch)
tree41a67330db32357d8d33aa072da032de346786d1
parentad82b7274a3efd2ad76e2c73a7474f9a74539e32 (diff)
[ruby/openssl] kdf: release GVL in OpenSSL::KDF.pbkdf2_hmac
Since PBKDF2 runs single-threaded and is typically configured to take several hundred milliseconds or longer, it is a perfect candidate to be run without the GVL. https://github.com/ruby/openssl/commit/2a24966414
-rw-r--r--ext/openssl/ossl_kdf.c51
1 files changed, 42 insertions, 9 deletions
diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c
index 1f28016440..7fb0540206 100644
--- a/ext/openssl/ossl_kdf.c
+++ b/ext/openssl/ossl_kdf.c
@@ -7,6 +7,27 @@
static VALUE mKDF, eKDF;
+struct pbkdf2_hmac_args {
+ char *pass;
+ int passlen;
+ unsigned char *salt;
+ int saltlen;
+ int iters;
+ const EVP_MD *md;
+ int len;
+ unsigned char *out;
+};
+
+static void *
+pbkdf2_hmac_nogvl(void *args_)
+{
+ struct pbkdf2_hmac_args *args = (struct pbkdf2_hmac_args *)args_;
+ int ret = PKCS5_PBKDF2_HMAC(args->pass, args->passlen, args->salt,
+ args->saltlen, args->iters, args->md,
+ args->len, args->out);
+ return (void *)(uintptr_t)ret;
+}
+
/*
* call-seq:
* KDF.pbkdf2_hmac(pass, salt:, iterations:, length:, hash:) -> aString
@@ -35,9 +56,9 @@ static VALUE mKDF, eKDF;
static VALUE
kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
{
- VALUE pass, salt, opts, kwargs[4], str, md_holder;
+ VALUE pass, salt, opts, kwargs[4], str, md_holder, pass_tmp, salt_tmp;
static ID kwargs_ids[4];
- int iters, len;
+ int passlen, saltlen, iters, len;
const EVP_MD *md;
if (!kwargs_ids[0]) {
@@ -54,14 +75,26 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
iters = NUM2INT(kwargs[1]);
len = NUM2INT(kwargs[2]);
md = ossl_evp_md_fetch(kwargs[3], &md_holder);
-
- str = rb_str_new(0, len);
- if (!PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LENINT(pass),
- (unsigned char *)RSTRING_PTR(salt),
- RSTRING_LENINT(salt), iters, md, len,
- (unsigned char *)RSTRING_PTR(str)))
+ passlen = RSTRING_LENINT(pass);
+ saltlen = RSTRING_LENINT(salt);
+ str = rb_str_new(NULL, len);
+ struct pbkdf2_hmac_args args = {
+ .pass = ALLOCV(pass_tmp, passlen),
+ .passlen = passlen,
+ .salt = ALLOCV(salt_tmp, saltlen),
+ .saltlen = saltlen,
+ .iters = iters,
+ .md = md,
+ .len = len,
+ .out = (unsigned char *)RSTRING_PTR(str),
+ };
+ memcpy(args.pass, RSTRING_PTR(pass), passlen);
+ memcpy(args.salt, RSTRING_PTR(salt), saltlen);
+ if (!rb_thread_call_without_gvl(pbkdf2_hmac_nogvl, &args, NULL, NULL))
ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC");
-
+ OPENSSL_cleanse(&args.pass, passlen);
+ ALLOCV_END(pass_tmp);
+ ALLOCV_END(salt_tmp);
return str;
}