Research
Security News
Threat Actor Exposes Playbook for Exploiting npm to Build Blockchain-Powered Botnets
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
The scrypt password-based key derivation function with asynchronous operation and ablility to be cancelled.
The scrypt-js npm package is a JavaScript implementation of the scrypt key derivation function. It is used primarily for securely hashing passwords and generating cryptographic keys.
Password Hashing
This feature allows you to hash a password using the scrypt key derivation function. The code sample demonstrates how to derive a key from a password and salt with specific parameters.
const scrypt = require('scrypt-js');
const password = Buffer.from('password');
const salt = Buffer.from('salt');
const N = 16384, r = 8, p = 1, dkLen = 32;
scrypt(password, salt, N, r, p, dkLen, (error, progress, key) => {
if (error) {
console.error(error);
} else if (key) {
console.log('Derived key:', key.toString('hex'));
}
});
Key Derivation
This feature allows you to derive a cryptographic key from a secret and salt. The code sample shows how to generate a 64-byte key using the scrypt function.
const scrypt = require('scrypt-js');
const secret = Buffer.from('secret');
const salt = Buffer.from('salt');
const N = 16384, r = 8, p = 1, dkLen = 64;
scrypt(secret, salt, N, r, p, dkLen, (error, progress, key) => {
if (error) {
console.error(error);
} else if (key) {
console.log('Derived key:', key.toString('hex'));
}
});
bcrypt is a popular library for hashing passwords. It is known for its simplicity and security. Unlike scrypt-js, bcrypt is specifically designed for password hashing and does not offer general key derivation functionality.
pbkdf2 is another key derivation function available in the crypto module of Node.js. It is widely used for password hashing and key derivation. Compared to scrypt-js, pbkdf2 is generally faster but considered less secure against certain types of attacks.
argon2 is a modern key derivation function that won the Password Hashing Competition in 2015. It is designed to be highly secure and resistant to various types of attacks. Argon2 offers similar functionalities to scrypt-js but is considered more secure and efficient.
The scrypt password-base key derivation function (pbkdf) is an algorithm designed to be brute-force resistant that converts human readable passwords into fixed length arrays of bytes, which can then be used as a key for symmetric block ciphers, private keys, et cetera.
The scrypt algorithm is, by design, expensive to execute, which increases the amount of time an attacker requires in order to brute force guess a password, adjustable by several parameters which can be tuned:
node.js
You should likely not use this module for node.js as there are many faster alternatives, but if you so wish to do so:
npm install scrypt-js
browser
<script src="https://raw.githubusercontent.com/ricmoo/scrypt-js/master/scrypt.js" type="text/javascript"></script>
<html>
<body>
<!-- These two libraries are highly recommended for encoding password/salt -->
<script src="libs/buffer.js" type="text/javascript"></script>
<script src="libs/unorm.js" type="text/javascript"></script>
<!-- This shim library greatly improves performance of the scrypt algorithm -->
<script src="libs/setImmediate.js" type="text/javascript"></script>
<script src="index.js" type="text/javascript"></script>
<script type="text/javascript">
// See the section below: "Encoding Notes"
var password = new buffer.SlowBuffer("anyPassword".normalize('NFKC'));
var salt = new buffer.SlowBuffer("someSalt".normalize('NFKC'));
var N = 1024, r = 8, p = 1;
var dkLen = 32;
scrypt(password, salt, N, r, p, dkLen, function(error, progress, key) {
if (error) {
console.log("Error: " + error);
} else if (key) {
console.log("Found: " + key);
} else {
// update UI with progress complete
updateInterface(progress);
}
});
</script>
</body>
</html>
TL;DR - either only allow ASCII characters in passwords, or use
String.prototype.normalize('NFKC') on any password
It is HIGHLY recommended that you do NOT pass strings into this (or any password-base key derivation function) library without careful consideration; you should convert your strings to a canonical format that you will use consistently across all platforms.
When encoding passwords with UTF-8, it is important to realize that there may be multiple UTF-8 representations of a given string. Since the key generated by a password-base key derivation function is dependent on the specific bytes, this matters a great deal.
Composed vs. Decomposed
Certain UTF-8 code points can be combined with other characters to create composed characters. For example, the letter a with the umlaut diacritic mark (two dots over it) can be expressed two ways; as its composed form, U+00FC; or its decomposed form, which is the letter "u" followed by U+0308 (which basically means modify the previous character by adding an umlaut to it).
// In the following two cases, a "u" with an umlaut would be seen
> '\u00fc'
> 'u\u0308'
// In its composed form, it is 2 bytes long
> new Buffer('u\u0308'.normalize('NFKC'))
<Buffer c3 bc>
> new Buffer('\u00fc')
<Buffer c3 bc>
// Whereas the decomposed form is 3 bytes, the letter u followed by U+0308
> new Buffer('\u00fc'.normalize('NFKD'))
<Buffer 75 cc 88>
> new Buffer('u\u0308')
<Buffer 75 cc 88>
Compatibility equivalence mode
Certain strings are often displayed the same, even though they may have different semantic means. For example, UTF-8 provides a code point for the roman number for one, which appears as the letter I, in most fonts identically. Compatibility equivalence will fold these two cases into simply the capital letter I.
> '\u2160'
'I'
> 'I'
'I'
> '\u2160' === 'I'
false
> '\u2160'.normalize('NFKC') === 'I'
true
Normalizing
The normalize()
method of a string can be used to convert a string to a specific form. Without going into too much detail, I generally recommend NFKC
, however if you wish to dive deeper into this, a nice short summary can be found in Pythons unicodedata module's documentation.
For browsers without normalize()
support, the npm unorm module can be used to polyfill strings.
Another example of encoding woes
One quick story I will share is a project which used the SHA256(encodeURI(password))
as a key, which (ignoring rainbow table attacks) had an unfortunate consequence of old web browsers replacing spaces with +
while on new web browsers, replacing it with a %20
, causing issues for anyone who used spaces in their password.
/^[A-Za-z0-9!@#$%^&*()]+$/
.See: Unicode Equivalence
The test cases from the scrypt whitepaper are included in test/test-vectors.json
and can be run using:
npm test
I would like to thank @dchest for his scrypt-async library and for his assistance providing feedback and optimization suggestions.
MIT license.
Obviously, it's all licensed under the MIT license, so use it as you wish; but if you'd like to buy me a coffee, I won't complain. =)
1LsxZkCZpQXyiGsoAnAW9nRRfck3Nvv7QS
DF1VMTgyPsew619hwq5tT2RP8BNh2ZpzWA
muf7Vak4ZCVgtYZCnGStDXuoEdmZuo2nhA
FAQs
The scrypt password-based key derivation function with sync and cancellable async.
We found that scrypt-js demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.