Skip to content

Commit a570408

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

File tree

1 file changed

+49
-18
lines changed

1 file changed

+49
-18
lines changed

ext/openssl/ossl_kdf.c

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,32 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
9696
}
9797

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

139165
if (!kwargs_ids[0]) {
140166
kwargs_ids[0] = rb_intern_const("salt");
@@ -147,24 +173,29 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
147173
rb_get_kwargs(opts, kwargs_ids, 5, 0, kwargs);
148174

149175
StringValue(pass);
176+
passlen = RSTRING_LEN(pass);
150177
salt = StringValue(kwargs[0]);
151-
N = NUM2UINT64T(kwargs[1]);
152-
r = NUM2UINT64T(kwargs[2]);
153-
p = NUM2UINT64T(kwargs[3]);
178+
saltlen = RSTRING_LEN(salt);
154179
len = NUM2LONG(kwargs[4]);
155-
/*
156-
* OpenSSL uses 32MB by default (if zero is specified), which is too small.
157-
* Let's not limit memory consumption but just let malloc() fail inside
158-
* OpenSSL. The amount is controllable by other parameters.
159-
*/
160-
maxmem = SIZE_MAX;
161-
162-
str = rb_str_new(0, len);
163-
if (!EVP_PBE_scrypt(RSTRING_PTR(pass), RSTRING_LEN(pass),
164-
(unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
165-
N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len))
180+
str = rb_str_new(NULL, len);
181+
struct scrypt_args args = {
182+
.pass = ALLOCV(pass_tmp, passlen),
183+
.passlen = passlen,
184+
.salt = ALLOCV(salt_tmp, saltlen),
185+
.saltlen = saltlen,
186+
.N = NUM2UINT64T(kwargs[1]),
187+
.r = NUM2UINT64T(kwargs[2]),
188+
.p = NUM2UINT64T(kwargs[3]),
189+
.len = len,
190+
.out = (unsigned char *)RSTRING_PTR(str),
191+
};
192+
memcpy(args.pass, RSTRING_PTR(pass), passlen);
193+
memcpy(args.salt, RSTRING_PTR(salt), saltlen);
194+
if (!rb_thread_call_without_gvl(scrypt_nogvl, &args, NULL, NULL))
166195
ossl_raise(eKDF, "EVP_PBE_scrypt");
167-
196+
OPENSSL_cleanse(&args.pass, passlen);
197+
ALLOCV_END(pass_tmp);
198+
ALLOCV_END(salt_tmp);
168199
return str;
169200
}
170201
#endif

0 commit comments

Comments
 (0)