Preview Ruby 4.1 is a preview. It can change before the final release. Switch to Ruby 4.0 →
OpenSSL::KDF.scrypt
static VALUE
kdf_scrypt(int argc, VALUE *argv, VALUE self)
{
VALUE pass, salt, opts, kwargs[5], str, pass_tmp, salt_tmp;
static ID kwargs_ids[5];
size_t passlen, saltlen;
rb_len_t len;
uint64_t N, r, p;
if (!kwargs_ids[0]) {
kwargs_ids[0] = rb_intern_const("salt");
kwargs_ids[1] = rb_intern_const("N");
kwargs_ids[2] = rb_intern_const("r");
kwargs_ids[3] = rb_intern_const("p");
kwargs_ids[4] = rb_intern_const("length");
}
rb_scan_args(argc, argv, "1:", &pass, &opts);
rb_get_kwargs(opts, kwargs_ids, 5, 0, kwargs);
StringValue(pass);
salt = StringValue(kwargs[0]);
N = NUM2UINT64T(kwargs[1]);
r = NUM2UINT64T(kwargs[2]);
p = NUM2UINT64T(kwargs[3]);
len = NUM2LEN(kwargs[4]);
passlen = RSTRING_LEN(pass);
saltlen = RSTRING_LEN(salt);
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 = N,
.r = r,
.p = p,
.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;
}
Derives a key from pass using given parameters with the scrypt password-based key derivation function. The result can be used for password storage.
scrypt is designed to be memory-hard and more secure against brute-force attacks using custom hardwares than alternative KDFs such as PBKDF2 or bcrypt.
The keyword arguments N, r and p can be used to tune scrypt. RFC 7914 (published on 2016-08, www.rfc-editor.org/rfc/rfc7914#section-2) states that using values r=8 and p=1 appears to yield good results.
See RFC 7914 (www.rfc-editor.org/rfc/rfc7914) for more information.
NOTE: This method cannot be interrupted by Timeout.timeout from the “timeout” library. Do not take parameters from untrusted sources without enforcing reasonable limits.
Parameters
- pass
-
Passphrase.
- salt
-
Salt.
- N
-
CPU/memory cost parameter. This must be a power of 2.
- r
-
Block size parameter.
- p
-
Parallelization parameter.
- length
-
Length in octets of the derived key.
Example
pass = "password" salt = SecureRandom.random_bytes(16) dk = OpenSSL::KDF.scrypt(pass, salt: salt, N: 2**14, r: 8, p: 1, length: 32) p dk #=> "\xDA\xE4\xE2...\x7F\xA1\x01T"