Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
6 changes: 6 additions & 0 deletions doc/api/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -2587,6 +2587,9 @@ request.
<!-- YAML
added: v10.5.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/28799
description: The `maxmem` value can now be any safe integer.
- version: v10.9.0
pr-url: https://github.com/nodejs/node/pull/21525
description: The `cost`, `blockSize` and `parallelization` option names
Expand Down Expand Up @@ -2641,6 +2644,9 @@ crypto.scrypt('secret', 'salt', 64, { N: 1024 }, (err, derivedKey) => {
<!-- YAML
added: v10.5.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/28799
description: The `maxmem` value can now be any safe integer.
- version: v10.9.0
pr-url: https://github.com/nodejs/node/pull/21525
description: The `cost`, `blockSize` and `parallelization` option names
Expand Down
10 changes: 9 additions & 1 deletion lib/internal/crypto/scrypt.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
'use strict';

const { Number } = primordials;
const { AsyncWrap, Providers } = internalBinding('async_wrap');
const { Buffer } = require('buffer');
const { scrypt: _scrypt } = internalBinding('crypto');
const { validateUint32 } = require('internal/validators');
const {
ERR_CRYPTO_SCRYPT_INVALID_PARAMETER,
ERR_CRYPTO_SCRYPT_NOT_SUPPORTED,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_CALLBACK,
ERR_OUT_OF_RANGE
} = require('internal/errors').codes;
const {
getDefaultEncoding,
Expand Down Expand Up @@ -107,8 +110,13 @@ function check(password, salt, keylen, options) {
p = options.parallelization;
}
if (options.maxmem !== undefined) {
validateUint32(options.maxmem, 'maxmem');
maxmem = options.maxmem;
if (typeof maxmem !== 'number')
throw new ERR_INVALID_ARG_TYPE('maxmem', 'number', maxmem);
if (!Number.isInteger(maxmem))
throw new ERR_OUT_OF_RANGE('maxmem', 'an integer', maxmem);
if (maxmem < 0 || maxmem > Number.MAX_SAFE_INTEGER)
throw new ERR_OUT_OF_RANGE('maxmem', `>= 0 && < ${2 ** 53}`, maxmem);
}
if (N === 0) N = defaults.N;
if (r === 0) r = defaults.r;
Expand Down
7 changes: 4 additions & 3 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6015,7 +6015,7 @@ struct ScryptJob : public CryptoJob {
uint32_t N;
uint32_t r;
uint32_t p;
uint32_t maxmem;
uint64_t maxmem;
CryptoErrorVector errors;

inline explicit ScryptJob(Environment* env) : CryptoJob(env) {}
Expand Down Expand Up @@ -6070,7 +6070,7 @@ void Scrypt(const FunctionCallbackInfo<Value>& args) {
CHECK(args[3]->IsUint32()); // N
CHECK(args[4]->IsUint32()); // r
CHECK(args[5]->IsUint32()); // p
CHECK(args[6]->IsUint32()); // maxmem
CHECK(args[6]->IsNumber()); // maxmem
CHECK(args[7]->IsObject() || args[7]->IsUndefined()); // wrap object
std::unique_ptr<ScryptJob> job(new ScryptJob(env));
job->keybuf_data = reinterpret_cast<unsigned char*>(Buffer::Data(args[0]));
Expand All @@ -6080,7 +6080,8 @@ void Scrypt(const FunctionCallbackInfo<Value>& args) {
job->N = args[3].As<Uint32>()->Value();
job->r = args[4].As<Uint32>()->Value();
job->p = args[5].As<Uint32>()->Value();
job->maxmem = args[6].As<Uint32>()->Value();
Local<Context> ctx = env->isolate()->GetCurrentContext();
job->maxmem = static_cast<uint64_t>(args[6]->IntegerValue(ctx).ToChecked());
if (!job->Validate()) {
// EVP_PBE_scrypt() does not always put errors on the error stack
// and therefore ToResult() may or may not return an exception
Expand Down
15 changes: 15 additions & 0 deletions test/parallel/test-crypto-scrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,18 @@ for (const { args, expected } of badargs) {
common.expectsError(() => crypto.scrypt('', '', 42, {}), expected);
common.expectsError(() => crypto.scrypt('', '', 42, {}, {}), expected);
}

{
// Values for maxmem that do not fit in 32 bits but that are still safe
// integers should be allowed.
crypto.scrypt('', '', 4, { maxmem: 2 ** 52 },
common.mustCall((err, actual) => {
assert.ifError(err);
assert.strictEqual(actual.toString('hex'), 'd72c87d0');
}));

// Values that exceed Number.isSafeInteger should not be allowed.
common.expectsError(() => crypto.scryptSync('', '', 0, { maxmem: 2 ** 53 }), {
code: 'ERR_OUT_OF_RANGE'
});
}