Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 91 additions & 30 deletions ext/openssl/ossl_kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@

static VALUE mKDF, eKDF;

struct pbkdf2_hmac_args {
char *pass;
int passlen;
unsigned char *salt;
int saltlen;
int iter;
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->iter, args->md,
args->len, args->out);
return (void *)(uintptr_t)ret;
}

/*
* call-seq:
* KDF.pbkdf2_hmac(pass, salt:, iterations:, length:, hash:) -> aString
Expand Down Expand Up @@ -35,10 +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;
const EVP_MD *md;
int passlen, saltlen, len;

if (!kwargs_ids[0]) {
kwargs_ids[0] = rb_intern_const("salt");
Expand All @@ -50,22 +70,58 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
rb_get_kwargs(opts, kwargs_ids, 4, 0, kwargs);

StringValue(pass);
passlen = RSTRING_LENINT(pass);
salt = StringValue(kwargs[0]);
iters = NUM2INT(kwargs[1]);
saltlen = RSTRING_LENINT(salt);
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)))
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,
.iter = NUM2INT(kwargs[1]),
.md = ossl_evp_md_fetch(kwargs[3], &md_holder),
.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;
}

#if defined(HAVE_EVP_PBE_SCRYPT)
struct scrypt_args {
char *pass;
size_t passlen;
unsigned char *salt;
size_t saltlen;
uint64_t N, r, p;
size_t len;
unsigned char *out;
};

static void *
scrypt_nogvl(void *args_)
{
struct scrypt_args *args = (struct scrypt_args *)args_;
/*
* OpenSSL uses 32MB by default (if zero is specified), which is too
* small. Let's not limit memory consumption but just let malloc() fail
* inside OpenSSL. The amount is controllable by other parameters.
*/
uint64_t maxmem = UINT64_MAX;
int ret = EVP_PBE_scrypt(args->pass, args->passlen,
args->salt, args->saltlen, args->N, args->r,
args->p, maxmem, args->out, args->len);
return (void *)(uintptr_t)ret;
}

/*
* call-seq:
* KDF.scrypt(pass, salt:, N:, r:, p:, length:) -> aString
Expand Down Expand Up @@ -101,10 +157,10 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
static VALUE
kdf_scrypt(int argc, VALUE *argv, VALUE self)
{
VALUE pass, salt, opts, kwargs[5], str;
VALUE pass, salt, opts, kwargs[5], str, pass_tmp, salt_tmp;
static ID kwargs_ids[5];
size_t len;
uint64_t N, r, p, maxmem;
size_t passlen, saltlen;
long len;

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

StringValue(pass);
passlen = RSTRING_LEN(pass);
salt = StringValue(kwargs[0]);
N = NUM2UINT64T(kwargs[1]);
r = NUM2UINT64T(kwargs[2]);
p = NUM2UINT64T(kwargs[3]);
saltlen = RSTRING_LEN(salt);
len = NUM2LONG(kwargs[4]);
/*
* OpenSSL uses 32MB by default (if zero is specified), which is too small.
* Let's not limit memory consumption but just let malloc() fail inside
* OpenSSL. The amount is controllable by other parameters.
*/
maxmem = SIZE_MAX;

str = rb_str_new(0, len);
if (!EVP_PBE_scrypt(RSTRING_PTR(pass), RSTRING_LEN(pass),
(unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len))
str = rb_str_new(NULL, len);
struct scrypt_args args = {
.pass = ALLOCV(pass_tmp, passlen),
.passlen = passlen,
.salt = ALLOCV(salt_tmp, saltlen),
.saltlen = saltlen,
.N = NUM2UINT64T(kwargs[1]),
.r = NUM2UINT64T(kwargs[2]),
.p = NUM2UINT64T(kwargs[3]),
.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(scrypt_nogvl, &args, NULL, NULL))
ossl_raise(eKDF, "EVP_PBE_scrypt");

OPENSSL_cleanse(&args.pass, passlen);
ALLOCV_END(pass_tmp);
ALLOCV_END(salt_tmp);
return str;
}
#endif
Expand Down