npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

node-scrypt2

v1.0.1

Published

A known, battle tested implementation of the scrypt crypto library for Node.js

Downloads

5

Readme

node-scrypt2

NOTICE

This module is an updated, modernized, and maintained fork of the node-scrypt library, which is unmaintained and deprecated.

node-scrypt2 is a native Node.js C++ wrapper for Colin Percival's scrypt cryptographic hash utility.

As should be the case with any security tool, this library should be scrutinized by anyone using it. If you find or suspect an issue with the code - please bring it to my attention and I'll spend some time trying to make sure that this tool is as secure as possible.

Features

  • Scrypt version 1.2.0 is being used (a modern version of Scrypt)
  • Using Node's internal cryptographic libraries - for windows users, there is no need to use an external OpenSSL library anymore.
  • Using Node's OS module to check for freemem, meaning no need to use any system calls and therefore no external dependencies

Table Of Contents

Scrypt

Scrypt is an advanced crypto library used mainly for key derivation: More information can be found here:

Installation Instructions

Pre-Requisistes

Windows

Linux/MacOS

Node-gyp is needed to build this module. It should be installed globally, that is, with the -g switch:

npm install -g node-gyp

Install From NPM

npm install node-scrypt2

Install From Source

git clone https://github.com/jkantr/node-scrypt2.git
cd node-scrypt
npm install
node-gyp configure build

Testing

To test, go to the folder where scrypt was installed, and type:

npm test

API

params

Translates human understandable parameters to scrypt's internal parameters.

scrypt.paramsSync scrypt.params(maxtime, [maxmem, [max_memfrac]], [function(err, obj) {}])

  • maxtime - [REQUIRED] - a decimal (double) representing the maximum amount of time in seconds scrypt will spend when computing the derived key.
  • maxmem - [OPTIONAL] - an integer, specifying the maximum number of bytes of RAM used when computing the derived encryption key. If not present, will default to 0.
  • maxmemfrac - [OPTIONAL only if maxmem is present] - a double value between 0.0 and 1.0, representing the fraction (normalized percentage value) of the available RAM used when computing the derived key. If not present, will default to 0.5.
  • callback_function - [OPTIONAL] - not applicable to synchronous function. If present in async function, then it will be treated as a normal async callback. If not present, a Promise will be returned if ES6 promises are available. If not present and ES6 promises are not present, a SyntaxError will be thrown.

kdf

Produces a key derivation function that uses the scrypt hash function. This should be used for hashing and checking passwords as it incorporates salt as well as HMAC into its format. It is based on a design by Colin Percival, the author of scrypt. The format can be seen here.

scrypt.kdfSync scrypt.kdf(key, paramsObject, [function(err, obj){}])

  • key - [REQUIRED] - a string (or buffer) representing the key (password) that is to be hashed.
  • paramsObject - [REQUIRED] - parameters to control scrypt hashing (see params above).
  • callback_function - [OPTIONAL] - not applicable to synchronous function. If present in async function, then it will be treated as a normal async callback. If not present, a Promise will be returned if ES6 promises are available. If not present and ES6 promises are not present, a SyntaxError will be thrown.

verifyKdf

Checks if a key (password) matches a kdf.

scrypt.verifyKdfSync scrypt.verifyKdf(kdf, key, [function(err, result){}])

  • kdf [REQUIRED] - see kdf above.
  • key - [REQUIRED] - a string (or buffer) representing the key (password) that is to be checked.
  • callback_function - [OPTIONAL] - not applicable to synchronous function. If present in async function, then it will be treated as a normal async callback. If not present, a Promise will be returned if ES6 promises are available. If not present and ES6 promises are not present, a SyntaxError will be thrown.

hash

Note: In previous versions, this was called kdf.

This is the raw scrypt hash function.

scrypt.hashSync scrypt.hash(key, paramsObject, output_length, salt, function(err, obj){})

  • key - [REQUIRED] - a string (or buffer) representing the key (password) that is to be checked.
  • paramsObject - [REQUIRED] - parameters to control scrypt hashing (see params above).
  • output_length - [REQUIRED] - the length of the resulting hashed output.
  • salt - [REQUIRED] - a string (or buffer) used for salt. The string (or buffer) can be empty.
  • callback_function - [OPTIONAL] - not applicable to synchronous function. If present in async function, then it will be treated as a normal async callback. If not present, a Promise will be returned if ES6 promises are available. If not present and ES6 promises are not present, a SyntaxError will be thrown.

Example Usage

params

const scrypt = require("node-scrypt2");

//Synchronous
try {
  //Uses 0.1 for maxtime, and default values maxmem and maxmemfrac
  const scryptParameters = scrypt.paramsSync(0.1);
  console.log(scryptParameters);
} catch(err) {
  //handle error
}

//Asynchronous with callback
scrypt.params(0.1, function(err, scryptParameters) {
  console.log(scryptParameters);
});

//Asynchronous with promise
scrypt.params(0.1)
  .then(function(result) {
    console.log(result);
  })
  .catch(function(err) {
    console.log(err);
  });

kdf

const scrypt = require("node-scrypt2");
const scryptParameters = scrypt.paramsSync(0.1);
const key = Buffer.from("this is a key"); //could also be a string

//Synchronous example that will output in hexidecimal encoding
const kdfResult = scrypt.kdfSync(key, scryptParameters); //should be wrapped in try catch, but leaving it out for brevity
console.log("Synchronous result: ", kdfResult.toString("hex"));

//Asynchronous example that expects key to be ascii encoded
scrypt.kdf("ascii encoded key", {N: 1, r:1, p:1}, function(err, result) {
  //Note how scrypt parameters was passed as a JSON object
  console.log("Asynchronous result: ", result.toString("base64"));
});

//Asynchronous with promise
scrypt.kdf("ascii encoded key", {N: 1, r:1, p:1}).then(function(result) {
  console.log("Asynchronous result: ", result.toString("base64"));
};

verifyKdf

const scrypt = require("node-scrypt2");
const scryptParameters = scrypt.paramsSync(0.1);
const kdfResult = scrypt.kdfSync("password", scryptParameters);

//Synchronous
scrypt.verifyKdfSync(kdfResult, "password"); // returns true
scrypt.verifyKdfSync(kdfResult, "incorrect password"); // returns false

//Asynchronous
scrypt.verifyKdf(kdfResult, Buffer.from("password"), function(err, result) {
  //result will be true
});

//Asynchronous with promise
scrypt.verifyKdf(kdfResult, Buffer.from("incorrect password")).then(function(result) {
  //result will be false
});

hash

The scrypt paper lists four test vectors to test implementation. This example will show how to produce these test vectors from within this module.

Test Vector 1

const scrypt = require("node-scrypt2");
const key = Buffer.from("");

//Synchronous
const result = scrypt.hashSync(key, {"N":16,"r":1,"p":1}, 64, "");
console.log(result.toString("hex"));

//Asynchronous
scrypt.hash(key, {"N":16,"r":1,"p":1}, 64, "", function(err, res) {
  console.log(result.toString("hex"));
});

//Asynchronous with promise
scrypt.hash(key, {"N":16,"r":1,"p":1}, 64, "").then(function(result) {
  console.log(result.toString("hex"));
});

Test Vector 2

const scrypt = require("node-scrypt2");
const salt = Buffer.from("NaCl");

//Synchronous
const result = scrypt.hashSync("password", {"N":1024,"r":8,"p":16}, 64, salt);
console.log(result.toString("hex"));

scrypt.hash("password", {"N":1024,"r":8,"p":16},64,salt, function(err, result) {
  console.log(result.toString("hex"));
});

Test Vector 3

const scrypt = require("node-scrypt2");
const key = Buffer.from("pleaseletmein");
const salt = Buffer.from("SodiumChloride");

//Synchronous
const result = scrypt.hashSync(key, {"N":16384,"r":8,"p":1}, 64, salt);
console.log(result.toString("hex"));

//Asynchronous
scrypt.hash(key, {"N":16384,"r":8,"p":1}, 64, salt, function(err, result) {
  console.log(result.toString("hex"));
});

Test Vector 4

Note: This test vector is very taxing in terms of resources.

const scrypt = require("node-scrypt2");

//Synchronous
const result = scrypt.hashSync("pleaseletmein", {"N":1048576,"r":8,"p":1}, 64, "SodiumChloride");
console.log(result.toString("hex"));

//Asynchronous
scrypt.hash("pleaseletmein", {"N":1048576,"r":8,"p":1}, 64, "SodiumChloride", function(err, result) {
  console.log(result.toString("hex"));
});

FAQ

General

What Platforms Are Supported?

This module supports most posix platforms, as well as Microsoft Windows. It has been tested on the following platforms: Linux, MAC OS, SmartOS (so its ready for Joyent Cloud) and Microsoft Windows. It also works on FreeBSD, OpenBSD, SunOS etc.

Scrypt

Why Use Scrypt?

It is one of the most advanced key derivation functions available. This is is quote taken from a comment in hacker news:

Passwords hashed with scrypt with sufficiently-high strength values (there are 3 tweakable input numbers) are fundamentally impervious to being cracked. I use the word "fundamental" in the literal sense, here; even if you had the resources of a large country, you would not be able to design any hardware (whether it be GPU hardware, custom-designed hardware, or otherwise) which could crack these hashes. Ever. (For sufficiently-small definitions of "ever". At the very least "within your lifetime"; probably far longer.)

What Are The Pros And Cons For Using Scrypt?

Pros

  • The scrypt algorithm has been published by IETF as an Internet Draft and is thus on track to becoming a standard. See here for the draft.
  • It is being actively used in production at Tarsnap.
  • It is much more secure than bcrypt.
  • It is designed to be future proof against attacks with future (and more advanced) hardware.
  • It is designed to defend against large scale custom hardware attacks.
  • It is production ready.
  • It does not arbitrarily limit password length to 72 bytes (ahem, bcrypt)
  • There is a scrypt library for most general purpose languages (Python, Ruby etc).

I will end this section with a quote from Colin Percival (author of scrypt):

We estimate that on modern (2009) hardware, if 5 seconds are spent computing a derived key, the cost of a hardware brute-force attack against scrypt is roughly 4000 times greater than the cost of a similar attack against bcrypt (to find the same password), and 20000 times greater than a similar attack against PBKDF2.

Cons

There is just one con I can think of: It is a relatively new library (only been around since 2009, compare to 1999 for bcrypt). Cryptographers don't really like new libraries for production deployment as it has not been battle tested quite as much. That being said, the library that this module is based on (node-scrypt) has been in heavy use since 2014. So there's a lot of production use in the books.

Using Scrypt With Passwords

What Are The Essential Properties For Storing Passwords?

Storing passwords requires three essential properties

  • The password must not be stored in plaintext.
  • The password hash must be salted. (Making a rainbow table attack very difficult to pull off).
  • The salted hash function must not be fast. (If someone does get hold of the salted hashes, their only option will be brute force which will be very slow).

As an example of how storing passwords can be done badly, take LinkedIn. In 2012, they came under fire for using unsalted hashes to store their passwords. As most commentators at the time were focusing no salt being present, the big picture was missed. In fact, their biggest problem was that they used sha1, a very fast hash function.

If random salts are used, why do all resulting KDF's start with c2NyeXB0?

The kdf has a specific format: The word "scrypt" is added as a prefix. The reason for this is because I am sticking to Colin Percival's (the creator of scrypt) reference implementation, whereby he prefixes scrypt in this way. The base64 encoding of the ascii "scrypt" is c2NyeXB0. The scrypt parameters are then appended. Users of scrypt normally do not change this information once it is settled upon (hence this will also look the be identical).

To illustrate with an example, I have hashed two password: password1 and password2. Their Base64 outputs are as follows:

password1
c2NyeXB0AAwAAAAIAAAAAcQ0zwp7QNLklxCn14vB75AYWDIrrT9I/7F9+lVGBfKN/1TH2hs
/HboSy1ptzN0YzHJhC7PZIEPQzf2nuoaqVZg8VkKEJlo8/QaH7qjU2VwB

password2
c2NyeXB0AAwAAAAIAAAAAZ/+bp8gWcTZgEC7YQZeLLyxFeKRRdDkwbaGeFC0NkdUr/YFAWY
/UwdOH4i/PxW48fXeXBDOTvGWtS3lLUgzNM0PlJbXhMOGd2bke0PvTSnW

As one can see from the above example, both hashes start off by looking similar (they both start with c2NyeXB0AAwAAAAIAAAAA - as explained above), but after this, things change very rapidly. In fact, I hashed the password password1 again:

password1
c2NyeXB0AAwAAAAIAAAAATpP+fdQAryDiRmCmcoOrZa2mZ049KdbA/ofTTrATQQ+m
0L/gR811d0WQyip6p2skXVEMz2+8U+xGryFu2p0yzfCxYLUrAaIzaZELkN2M6k0

Compare this hash to the one above. Even though they start off looking similar, their outputs are vastly different (even though it is the same password being hashed). This is because of the random salt that has been added, ensuring that no two hashes will ever be identical, even if the password that is being hashed is the same.

For those that are curious or paranoid, please look at how the kdf is both produced and verified (you are going to need some knowledge of the C language for this).

Roadmap

See changelog.

Credits

The scrypt library is Colin Percival's scrypt project.

This module is largely a direct fork of the original node-scrypt library, developed by Barry Steyn.

Syed Beparey was instrumental in getting the Windows build working, with most of the Windows build based off the work done by Dinesh Shanbhag.