Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
@noble/hashes
Advanced tools
Audited & minimal 0-dependency JS implementation of SHA, RIPEMD, BLAKE, HMAC, HKDF, PBKDF & Scrypt
The @noble/hashes npm package provides a collection of cryptographic hash functions implemented in pure JavaScript with a focus on security and performance. It is part of the noble family of packages, which are designed to be secure, efficient, and easy to use.
SHA-256 Hashing
This feature allows you to compute the SHA-256 hash of an input. The code sample demonstrates how to hash a Uint8Array of bytes and print the resulting hash as a hex string.
"use strict";
const { sha256 } = require('@noble/hashes/sha256');
const hash = sha256(new Uint8Array([1, 2, 3]));
console.log(Buffer.from(hash).toString('hex'));
SHA-1 Hashing
This feature enables SHA-1 hashing. The code sample shows how to hash a Uint8Array and output the hash in hexadecimal format.
"use strict";
const { sha1 } = require('@noble/hashes/sha1');
const hash = sha1(new Uint8Array([1, 2, 3]));
console.log(Buffer.from(hash).toString('hex'));
RIPEMD-160 Hashing
This feature provides RIPEMD-160 hashing capability. The code sample illustrates hashing a byte array and converting the hash to a hex string.
"use strict";
const { ripemd160 } = require('@noble/hashes/ripemd160');
const hash = ripemd160(new Uint8Array([1, 2, 3]));
console.log(Buffer.from(hash).toString('hex'));
HMAC
This feature allows for the creation of HMACs (Hash-based Message Authentication Codes) using a specified hash function. The code sample demonstrates creating an HMAC with SHA-256.
"use strict";
const { hmac } = require('@noble/hashes/hmac');
const { sha256 } = require('@noble/hashes/sha256');
const key = new Uint8Array([1, 2, 3, 4, 5]);
const message = new Uint8Array([6, 7, 8, 9, 0]);
const signature = hmac(sha256, key, message);
console.log(Buffer.from(signature).toString('hex'));
Crypto-js is a popular package that provides a variety of cryptographic algorithms including hash functions, HMAC, and encryption. It is similar to @noble/hashes but has a broader scope, including encryption and decryption methods.
Hash.js is a lightweight library of hash functions that includes implementations of SHA-1, SHA-256, and RIPEMD. It is similar to @noble/hashes in providing hash functions but is not as focused on security and performance.
Sha.js is a simple module that only implements SHA hash functions. It is similar to @noble/hashes in providing SHA hashing but does not include other hash functions like RIPEMD-160 or HMAC capabilities.
Audited & minimal JS implementation of hash functions, MACs and KDFs.
Take a glance at GitHub Discussions for questions and support. The library's initial development was funded by Ethereum Foundation.
noble cryptography — high-security, easily auditable set of contained cryptographic libraries and tools.
npm install @noble/hashes
deno add jsr:@noble/hashes
deno doc jsr:@noble/hashes
# command-line documentation
We support all major platforms and runtimes. For React Native, you may need a polyfill for getRandomValues. A standalone file noble-hashes.js is also available.
// import * from '@noble/hashes'; // Error: use sub-imports, to ensure small app size
import { sha256 } from '@noble/hashes/sha2'; // ECMAScript modules (ESM) and Common.js
// u8a is accepted
console.log(sha256(new Uint8Array([1, 2, 3]))); // Uint8Array(32) [3, 144, 88, 198, 242...]
// strings are also accepted and auto-encoded into u8a
console.log(sha256('abc')); // == sha256(new TextEncoder().encode('abc'))
// function hash(message: Uint8Array | string): Uint8Array;
hash(new Uint8Array([1, 3]));
hash('string'); // == hash(new TextEncoder().encode('string'));
// prettier-ignore
hash.create().update(new Uint8Array([1, 3])).digest();
Hash functions:
Uint8Array
string
(not hex), which is automatically utf8-encoded to Uint8Array
hash.create()
method
Hash
subclass instance, which has update()
and digest()
methodsdigest()
finalizes the hash and makes it no longer usableoptions
:
blake3('abc', { key: 'd', dkLen: 32 })
blake3.create({ context: 'e', dkLen: 32 })
import { sha256, sha384, sha512, sha224, sha512_256, sha512_384 } from '@noble/hashes/sha2';
// also available as aliases:
// import ... from '@noble/hashes/sha256'
// import ... from '@noble/hashes/sha512'
// Variant A:
const h1a = sha256('abc');
// Variant B:
const h1b = sha256
.create()
.update(Uint8Array.from([1, 2, 3]))
.digest();
for (let hash of [sha384, sha512, sha224, sha512_256, sha512_384]) {
const res1 = hash('abc');
const res2 = hash
.create()
.update('def')
.update(Uint8Array.from([1, 2, 3]))
.digest();
}
See RFC 4634 and the paper on truncated SHA512/256.
// prettier-ignore
import {
sha3_224, sha3_256, sha3_384, sha3_512,
keccak_224, keccak_256, keccak_384, keccak_512,
shake128, shake256,
} from '@noble/hashes/sha3';
const h5a = sha3_256('abc');
const h5b = sha3_256
.create()
.update(Uint8Array.from([1, 2, 3]))
.digest();
const h6a = keccak_256('abc');
const h7a = shake128('abc', { dkLen: 512 });
const h7b = shake256('abc', { dkLen: 512 });
Check out the differences between SHA-3 and Keccak
// prettier-ignore
import {
cshake128, cshake256,
turboshake128, turboshake256,
kmac128, kmac256,
tuplehash256, parallelhash256,
k12, m14, keccakprg
} from '@noble/hashes/sha3-addons';
const h7c = cshake128('abc', { personalization: 'def' });
const h7d = cshake256('abc', { personalization: 'def' });
const h7e = kmac128('key', 'message');
const h7f = kmac256('key', 'message');
const h7h = k12('abc');
const h7g = m14('abc');
const h7t1 = turboshake128('abc');
const h7t2 = turboshake256('def', { D: 0x05 });
const h7i = tuplehash256(['ab', 'c']); // tuplehash(['ab', 'c']) !== tuplehash(['a', 'bc']) !== tuplehash(['abc'])
// Same as k12/blake3, but without reduced number of rounds. Doesn't speedup anything due lack of SIMD and threading,
// added for compatibility.
const h7j = parallelhash256('abc', { blockLen: 8 });
// pseudo-random generator, first argument is capacity. XKCP recommends 254 bits capacity for 128-bit security strength.
// * with a capacity of 254 bits.
const p = keccakprg(254);
p.feed('test');
const rand1b = p.fetch(1);
import { ripemd160 } from '@noble/hashes/ripemd160';
// function ripemd160(data: Uint8Array): Uint8Array;
const hash8 = ripemd160('abc');
const hash9 = ripemd160
.create()
.update(Uint8Array.from([1, 2, 3]))
.digest();
import { blake224, blake256, blake384, blake512 } from '@noble/hashes/blake1';
import { blake2b } from '@noble/hashes/blake2b';
import { blake2s } from '@noble/hashes/blake2s';
import { blake3 } from '@noble/hashes/blake3';
const h_b1_224 = blake224('abc');
const h_b1_256 = blake256('abc');
const h_b1_384 = blake384('abc');
const h_b1_512 = blake512('abc');
const h10a = blake2s('abc');
const b2params = { key: new Uint8Array([1]), personalization: t, salt: t, dkLen: 32 };
const h10b = blake2s('abc', b2params);
const h10c = blake2s
.create(b2params)
.update(Uint8Array.from([1, 2, 3]))
.digest();
// All params are optional
const h11 = blake3('abc', { dkLen: 256 });
const h11_mac = blake3('abc', { key: new Uint8Array(32) });
const h11_kdf = blake3('abc', { context: 'application name' });
SHA1 was cryptographically broken, however, it was not broken for cases like HMAC.
See RFC4226 B.2.
Don't use it for a new protocol.
import { sha1 } from '@noble/hashes/sha1';
const h12 = sha1('def');
import { hmac } from '@noble/hashes/hmac';
import { sha256 } from '@noble/hashes/sha2';
const mac1 = hmac(sha256, 'key', 'message');
const mac2 = hmac
.create(sha256, Uint8Array.from([1, 2, 3]))
.update(Uint8Array.from([4, 5, 6]))
.digest();
Matches RFC 2104.
import { hkdf } from '@noble/hashes/hkdf';
import { sha256 } from '@noble/hashes/sha2';
import { randomBytes } from '@noble/hashes/utils';
const inputKey = randomBytes(32);
const salt = randomBytes(32);
const info = 'application-key';
const hk1 = hkdf(sha256, inputKey, salt, info, 32);
// == same as
import * as hkdf from '@noble/hashes/hkdf';
import { sha256 } from '@noble/hashes/sha2';
const prk = hkdf.extract(sha256, inputKey, salt);
const hk2 = hkdf.expand(sha256, prk, info, dkLen);
Matches RFC 5869.
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
import { sha256 } from '@noble/hashes/sha2';
const pbkey1 = pbkdf2(sha256, 'password', 'salt', { c: 32, dkLen: 32 });
const pbkey2 = await pbkdf2Async(sha256, 'password', 'salt', { c: 32, dkLen: 32 });
const pbkey3 = await pbkdf2Async(sha256, Uint8Array.from([1, 2, 3]), Uint8Array.from([4, 5, 6]), {
c: 32,
dkLen: 32,
});
Matches RFC 2898.
import { scrypt, scryptAsync } from '@noble/hashes/scrypt';
const scr1 = scrypt('password', 'salt', { N: 2 ** 16, r: 8, p: 1, dkLen: 32 });
const scr2 = await scryptAsync('password', 'salt', { N: 2 ** 16, r: 8, p: 1, dkLen: 32 });
const scr3 = await scryptAsync(Uint8Array.from([1, 2, 3]), Uint8Array.from([4, 5, 6]), {
N: 2 ** 17,
r: 8,
p: 1,
dkLen: 32,
onProgress(percentage) {
console.log('progress', percentage);
},
maxmem: 2 ** 32 + 128 * 8 * 1, // N * r * p * 128 + (128*r*p)
});
N, r, p
are work factors. To understand them, see the blog post.
r: 8, p: 1
are common. JS doesn't support parallelization, making increasing p meaningless.dkLen
is the length of output bytes e.g. 32
or 64
onProgress
can be used with async version of the function to report progress to a user.maxmem
prevents DoS and is limited to 1GB + 1KB
(2**30 + 2**10
), but can be adjusted using formula: N * r * p * 128 + (128 * r * p)
Time it takes to derive Scrypt key under different values of N (2**N) on Apple M2 (mobile phones can be 1x-4x slower):
N pow | Time |
---|---|
16 | 0.17s |
17 | 0.35s |
18 | 0.7s |
19 | 1.4s |
20 | 2.9s |
21 | 5.6s |
22 | 11s |
23 | 26s |
24 | 56s |
[!NOTE] We support N larger than
2**20
where available, however, not all JS engines support >= 2GB ArrayBuffer-s. When using such N, you'll need to manually adjustmaxmem
, using formula above. Other JS implementations don't support large N-s.
import { argon2d, argon2i, argon2id } from '@noble/hashes/argon2';
const result = argon2id('password', 'saltsalt', { t: 2, m: 65536, p: 1, maxmem: 2 ** 32 - 1 });
Argon2 RFC 9106 implementation.
[!WARNING] Argon2 can't be fast in JS, because there is no fast Uint64Array. It is suggested to use Scrypt instead. Being 5x slower than native code means brute-forcing attackers have bigger advantage.
import { bytesToHex as toHex, randomBytes } from '@noble/hashes/utils';
console.log(toHex(randomBytes(32)));
bytesToHex
will convert Uint8Array
to a hex stringrandomBytes(bytes)
will produce cryptographically secure random Uint8Array
of length bytes
import { sha256, sha384, sha512, sha224, sha512_256, sha512_384 } from '@noble/hashes/sha2';
// prettier-ignore
import {
sha3_224, sha3_256, sha3_384, sha3_512,
keccak_224, keccak_256, keccak_384, keccak_512,
shake128, shake256
} from '@noble/hashes/sha3';
// prettier-ignore
import {
cshake128, cshake256,
turboshake128, turboshake256,
kmac128, kmac256,
tuplehash256, parallelhash256,
k12, m14, keccakprg
} from '@noble/hashes/sha3-addons';
import { ripemd160 } from '@noble/hashes/ripemd160';
import { blake3 } from '@noble/hashes/blake3';
import { blake2b } from '@noble/hashes/blake2b';
import { blake2s } from '@noble/hashes/blake2s';
import { hmac } from '@noble/hashes/hmac';
import { hkdf } from '@noble/hashes/hkdf';
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
import { scrypt, scryptAsync } from '@noble/hashes/scrypt';
import { sha1 } from '@noble/hashes/sha1'; // legacy
// small utility method that converts bytes to hex
import { bytesToHex as toHex } from '@noble/hashes/utils';
console.log(toHex(sha256('abc'))); // ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
The library has been independently audited:
blake3
, sha3-addons
, sha1
and argon2
, which have not been auditedIt is tested against property-based, cross-library and Wycheproof vectors, and has fuzzing by Guido Vranken's cryptofuzz.
If you see anything unusual: investigate and report.
JIT-compiler and Garbage Collector make "constant time" extremely hard to achieve timing attack resistance in a scripting language. Which means any other JS library can't have constant-timeness. Even statically typed Rust, a language without GC, makes it harder to achieve constant-time for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones. Use low-level libraries & languages. Nonetheless we're targetting algorithmic constant time.
The library shares state buffers between hash function calls. The buffers are zeroed-out after each call. However, if an attacker can read application memory, you are doomed in any case:
scrypt(password, salt)
where password and salt are stringsawait anything()
will always write all internal variables (including numbers)
to memory. With async functions / Promises there are no guarantees when the code
chunk would be executed. Which means attacker can have plenty of time to read data from memorynpm-diff
We're deferring to built-in crypto.getRandomValues which is considered cryptographically secure (CSPRNG).
In the past, browsers had bugs that made it weak: it may happen again. Implementing a userspace CSPRNG to get resilient to the weakness is even worse: there is no reliable userspace source of quality entropy.
Cryptographically relevant quantum computer, if built, will allow to utilize Grover's algorithm to break hashes in 2^n/2 operations, instead of 2^n.
This means SHA256 should be replaced with SHA512, SHA3-256 with SHA3-512, SHAKE128 with SHAKE256 etc.
Australian ASD prohibits SHA256 and similar hashes after 2030.
npm run bench
Benchmarks measured on Apple M2 with node v22.
32B
sha256 x 1,377,410 ops/sec @ 726ns/op
sha384 x 518,403 ops/sec @ 1μs/op
sha512 x 518,941 ops/sec @ 1μs/op
sha3_256 x 188,608 ops/sec @ 5μs/op
sha3_512 x 190,114 ops/sec @ 5μs/op
k12 x 324,254 ops/sec @ 3μs/op
m14 x 286,204 ops/sec @ 3μs/op
blake2b x 352,236 ops/sec @ 2μs/op
blake2s x 586,510 ops/sec @ 1μs/op
blake3 x 681,198 ops/sec @ 1μs/op
ripemd160 x 1,275,510 ops/sec @ 784ns/op
1MB
sha256 x 197 ops/sec @ 5ms/op
sha384 x 86 ops/sec @ 11ms/op
sha512 x 86 ops/sec @ 11ms/op
sha3_256 x 25 ops/sec @ 39ms/op
sha3_512 x 13 ops/sec @ 74ms/op
k12 x 58 ops/sec @ 17ms/op
m14 x 41 ops/sec @ 24ms/op
blake2b x 50 ops/sec @ 19ms/op
blake2s x 44 ops/sec @ 22ms/op
blake3 x 57 ops/sec @ 17ms/op
ripemd160 x 193 ops/sec @ 5ms/op
# MAC
hmac(sha256) x 404,203 ops/sec @ 2μs/op
hmac(sha512) x 137,136 ops/sec @ 7μs/op
kmac256 x 58,799 ops/sec @ 17μs/op
blake3(key) x 619,962 ops/sec @ 1μs/op
# KDF
hkdf(sha256) x 180,538 ops/sec @ 5μs/op
blake3(context) x 336,247 ops/sec @ 2μs/op
pbkdf2(sha256, c: 2 ** 18) x 3 ops/sec @ 292ms/op
pbkdf2(sha512, c: 2 ** 18) x 1 ops/sec @ 920ms/op
scrypt(n: 2 ** 18, r: 8, p: 1) x 1 ops/sec @ 605ms/op
argon2id(t: 1, m: 256MB) x 0 ops/sec @ 4021ms/op
Compare to native node.js implementation that uses C bindings instead of pure-js code:
SHA256 32B node x 1,302,083 ops/sec @ 768ns/op
SHA384 32B node x 975,609 ops/sec @ 1μs/op
SHA512 32B node x 983,284 ops/sec @ 1μs/op
SHA3-256 32B node x 910,746 ops/sec @ 1μs/op
# keccak, k12, m14 are not implemented
BLAKE2b 32B node x 967,117 ops/sec @ 1μs/op
BLAKE2s 32B node x 1,055,966 ops/sec @ 947ns/op
# BLAKE3 is not implemented
RIPEMD160 32B node x 1,002,004 ops/sec @ 998ns/op
HMAC-SHA256 32B node x 919,963 ops/sec @ 1μs/op
HKDF-SHA256 32 node x 369,276 ops/sec @ 2μs/op
PBKDF2-HMAC-SHA256 262144 node x 25 ops/sec @ 39ms/op
PBKDF2-HMAC-SHA512 262144 node x 7 ops/sec @ 132ms/op
Scrypt r: 8, p: 1, n: 262144 node x 1 ops/sec @ 523ms/op
It is possible to make this library 4x+ faster by doing code generation of full loop unrolls. We've decided against it. Reasons:
The current performance is good enough when compared to other projects; SHA256 takes only 900 nanoseconds to run.
test/misc
directory contains implementations of loop unrolling and md5.
npm install && npm run build && npm test
will build the code and run tests.npm run lint
/ npm run format
will run linter / fix linter issues.npm run bench
will run benchmarks, which may need their deps first (npm run bench:install
)cd build && npm install && npm run build:release
will build single filenpm run test:dos
and 2-hour "big" multicore test npm run test:big
.
See our approach to testingCheck out github.com/paulmillr/guidelines for general coding practices and rules.
See paulmillr.com/noble for useful resources, articles, documentation and demos related to the library.
The MIT License (MIT)
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
See LICENSE file.
FAQs
Audited & minimal 0-dependency JS implementation of SHA, RIPEMD, BLAKE, HMAC, HKDF, PBKDF & Scrypt
The npm package @noble/hashes receives a total of 5,005,677 weekly downloads. As such, @noble/hashes popularity was classified as popular.
We found that @noble/hashes demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers 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.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.