Skip to content

Commit dd2f6ba

Browse files
committed
kdf: release GVL in OpenSSL::KDF.scrypt
scrypt is another password hashing algorithm, so releasing the GVL is useful.
1 parent 2a24966 commit dd2f6ba

1 file changed

Lines changed: 50 additions & 15 deletions

File tree

ext/openssl/ossl_kdf.c

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,32 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
9999
}
100100

101101
#if defined(HAVE_EVP_PBE_SCRYPT)
102+
struct scrypt_args {
103+
char *pass;
104+
size_t passlen;
105+
unsigned char *salt;
106+
size_t saltlen;
107+
uint64_t N, r, p;
108+
size_t len;
109+
unsigned char *out;
110+
};
111+
112+
static void *
113+
scrypt_nogvl(void *args_)
114+
{
115+
struct scrypt_args *args = (struct scrypt_args *)args_;
116+
/*
117+
* OpenSSL uses 32MB by default (if zero is specified), which is too
118+
* small. Let's not limit memory consumption but just let malloc() fail
119+
* inside OpenSSL. The amount is controllable by other parameters.
120+
*/
121+
uint64_t maxmem = UINT64_MAX;
122+
int ret = EVP_PBE_scrypt(args->pass, args->passlen,
123+
args->salt, args->saltlen, args->N, args->r,
124+
args->p, maxmem, args->out, args->len);
125+
return (void *)(uintptr_t)ret;
126+
}
127+
102128
/*
103129
* call-seq:
104130
* KDF.scrypt(pass, salt:, N:, r:, p:, length:) -> aString
@@ -134,10 +160,11 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
134160
static VALUE
135161
kdf_scrypt(int argc, VALUE *argv, VALUE self)
136162
{
137-
VALUE pass, salt, opts, kwargs[5], str;
163+
VALUE pass, salt, opts, kwargs[5], str, pass_tmp, salt_tmp;
138164
static ID kwargs_ids[5];
139-
size_t len;
140-
uint64_t N, r, p, maxmem;
165+
size_t passlen, saltlen;
166+
long len;
167+
uint64_t N, r, p;
141168

142169
if (!kwargs_ids[0]) {
143170
kwargs_ids[0] = rb_intern_const("salt");
@@ -155,19 +182,27 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
155182
r = NUM2UINT64T(kwargs[2]);
156183
p = NUM2UINT64T(kwargs[3]);
157184
len = NUM2LONG(kwargs[4]);
158-
/*
159-
* OpenSSL uses 32MB by default (if zero is specified), which is too small.
160-
* Let's not limit memory consumption but just let malloc() fail inside
161-
* OpenSSL. The amount is controllable by other parameters.
162-
*/
163-
maxmem = SIZE_MAX;
164-
165-
str = rb_str_new(0, len);
166-
if (!EVP_PBE_scrypt(RSTRING_PTR(pass), RSTRING_LEN(pass),
167-
(unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
168-
N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len))
185+
passlen = RSTRING_LEN(pass);
186+
saltlen = RSTRING_LEN(salt);
187+
str = rb_str_new(NULL, len);
188+
struct scrypt_args args = {
189+
.pass = ALLOCV(pass_tmp, passlen),
190+
.passlen = passlen,
191+
.salt = ALLOCV(salt_tmp, saltlen),
192+
.saltlen = saltlen,
193+
.N = N,
194+
.r = r,
195+
.p = p,
196+
.len = len,
197+
.out = (unsigned char *)RSTRING_PTR(str),
198+
};
199+
memcpy(args.pass, RSTRING_PTR(pass), passlen);
200+
memcpy(args.salt, RSTRING_PTR(salt), saltlen);
201+
if (!rb_thread_call_without_gvl(scrypt_nogvl, &args, NULL, NULL))
169202
ossl_raise(eKDF, "EVP_PBE_scrypt");
170-
203+
OPENSSL_cleanse(&args.pass, passlen);
204+
ALLOCV_END(pass_tmp);
205+
ALLOCV_END(salt_tmp);
171206
return str;
172207
}
173208
#endif

0 commit comments

Comments
 (0)