@whi/argon2-wasm
v0.5.1
Published
Argon2 wasm bindings with all inputs exposed
Readme
Argon2 Wasm
Wasm bindings for Argon2 with all inputs exposed — password, salt, secret (the
keyed input K, e.g. a pepper), and associated_data (X). Backed by the
RustCrypto argon2 crate.
Output is a raw Argon2 hash, version 0x13 (v=19), fixed at 64 bytes. Inputs are
byte arrays (Buffer / Uint8Array).
Install
npm install @whi/argon2-wasmUsage
Node (CommonJS)
const crypto = require('crypto');
const { argon2, verify, HashType } = require('@whi/argon2-wasm');
const password = Buffer.from("password");
const salt = crypto.randomBytes( 16 );
const secret = crypto.randomBytes( 8 ); // keyed input (K); [] for none
const associated_data = new Uint8Array();
const hash = Buffer.from( argon2(
password,
salt,
secret,
associated_data,
2, // iterations
4, // parallelism
1 << 8, // memory_size (KiB), must be >= 8 * parallelism
HashType.Argon2id, // Argon2d | Argon2i | Argon2id
));
console.log( hash.toString('base64') );
verify(
hash,
password,
salt,
secret,
associated_data,
2, 4, 1 << 8, HashType.Argon2id,
);
// returns trueCloudflare Workers
import { argon2, verify, HashType } from '@whi/argon2-wasm';Works as-is in a Worker bundled by Wrangler: the package's exports map has a
workerd condition pointing at a Workers-specific entry, so no manual wasm
instantiation is needed. This is tested on every build (tests/e2e) by installing
the packed package into a fixture Worker, bundling it with Wrangler, and running it
in workerd.
Bundlers and Node (ESM)
import { argon2, verify, HashType } from '@whi/argon2-wasm';Outside Workers, import resolves to wasm-pack's bundler build, which imports the
wasm as an ES module. In Node that relies on Node's experimental wasm-module
support (Node prints an ExperimentalWarning); use require to avoid it.
API
argon2(password, salt, secret, associated_data, iterations, parallelism, memory_size, hash_type)→Uint8ArrayThe raw 64-byte Argon2 hash.
verify(hash, password, salt, secret, associated_data, iterations, parallelism, memory_size, hash_type)→booleanRecomputes the hash from the given inputs and compares it to
hash.HashType— enum:Argon2d,Argon2i,Argon2id.
secret is Argon2's keyed input K; pass an empty array for none. memory_size
is in KiB and must be at least 8 * parallelism.
Development
Requirements: rustup (the channel and wasm32 target are pinned in
rust-toolchain.toml), wasm-pack, node + npm, and jq.
make test # build the package and run the test suite
make pkg # build the publishable package into ./pkgmake test runs two layers, which can also be run on their own against an
existing build:
npm run test:integration # the built ./pkg in Node, incl. the reference vectors
npm run test:e2e # the packed tarball in a Wrangler-bundled Worker (workerd)Crypto invariant — read before changing the hashing dependency or parameters
The output bytes of argon2() are a frozen contract. Stored credentials are
verified by recomputing the hash and comparing (verify() in src/lib.rs),
so if the output for a given input ever changes, every existing stored credential
stops validating — a silent, account-wide breakage.
tests/vectors/reference-vectors.json pins that contract: a corpus of known-answer
vectors that tests/unit/test_vectors.js asserts the build reproduces byte-for-byte.
These are the canonical bytes stored credentials were created with — originally
produced by the argon2min crate that this
package used before, and reproduced exactly by the current RustCrypto argon2
backend (verified by a differential test during the migration).
Practical rules for a future change:
- Bumping the
argon2crate, or any change to hashing: keepmake testgreen. If the vectors still pass, output is unchanged and the change is safe. - Never regenerate
reference-vectors.jsonto make a failing suite pass — that rewrites the answers instead of the code and destroys the guarantee. The generator (tests/vectors/generate.cjs) refuses to overwrite the file without--forcefor exactly this reason. --forceregeneration is only for a deliberate migration that re-hashes every stored credential (e.g. moving to stronger Argon2 parameters) — not a routine bump.
