5.0 KiB
argon2id
(no submodules)
Purpose
Provides Argon2id password hashing as specified in RFC 9106. Argon2id is the
current winner of the Password Hashing Competition and is recommended by OWASP
for new applications. It is resistant to both GPU-based brute force (via high
memory cost) and time-memory trade-off attacks (via the hybrid id variant).
This module enforces non-pathological lower bounds on all four tuning parameters
and produces a structured HashError with per-field context when they are
violated, making it safe for frameworks to call without a separate validation
layer.
Features
argon2id(password, options)— Argon2id key derivation- Exported constants:
ARGON2ID_MIN_MEMORY_COST_KIB,ARGON2ID_MIN_TIME_COST,ARGON2ID_MIN_PARALLELISM - Validates each parameter individually; error context includes
{ field, value, minimum } - Throws
HashError("HASH.KDF.INVALID_PARAMS")for any out-of-range parameter - Deterministic: same inputs always produce the same hash output
Usage: Basic Example
import { argon2id, ARGON2ID_MIN_MEMORY_COST_KIB } from "@suaveplan/crypto-hash/kdf";
const encoder = new TextEncoder();
const password = encoder.encode("hunter2");
const salt = new Uint8Array(16); // use crypto.getRandomValues in production
const hash = argon2id(password, {
salt,
timeCost: 3,
memoryCost: ARGON2ID_MIN_MEMORY_COST_KIB * 1024, // 8 MiB in KiB
parallelism: 1,
length: 32,
});
console.log(hash.length); // 32
Usage: Advanced Example
import {
argon2id,
ARGON2ID_MIN_MEMORY_COST_KIB,
ARGON2ID_MIN_TIME_COST,
ARGON2ID_MIN_PARALLELISM,
} from "@suaveplan/crypto-hash/kdf";
import { toHex } from "@suaveplan/crypto-hash/encoding";
import { HashError } from "@suaveplan/crypto-hash/errors";
interface PasswordHashConfig {
timeCost: number;
memoryCostKib: number;
parallelism: number;
outputBytes: number;
}
function hashPassword(password: string, salt: Uint8Array, cfg: PasswordHashConfig): string {
try {
const raw = argon2id(new TextEncoder().encode(password), {
salt,
timeCost: cfg.timeCost,
memoryCost: cfg.memoryCostKib,
parallelism: cfg.parallelism,
length: cfg.outputBytes,
});
return toHex(raw);
} catch (err) {
if (err instanceof HashError && err.context?.field) {
throw new RangeError(
`Argon2id parameter out of range: ${err.context.field} = ${err.context.value} ` +
`(minimum: ${err.context.minimum})`
);
}
throw err;
}
}
const salt = new Uint8Array(16);
const hex = hashPassword("secure-password", salt, {
timeCost: ARGON2ID_MIN_TIME_COST,
memoryCostKib: ARGON2ID_MIN_MEMORY_COST_KIB,
parallelism: ARGON2ID_MIN_PARALLELISM,
outputBytes: 32,
});
console.log(hex.length); // 64 hex chars = 32 bytes
API Reference
argon2id(password: Uint8Array, options: Argon2idOptions): Uint8Array
Derives options.length bytes from password using Argon2id.
| Parameter | Type | Description |
|---|---|---|
password |
Uint8Array |
User-supplied password bytes |
options.salt |
Uint8Array |
Per-credential random salt (≥ 16 bytes recommended) |
options.timeCost |
number |
Integer ≥ ARGON2ID_MIN_TIME_COST (number of iterations) |
options.memoryCost |
number |
Integer ≥ ARGON2ID_MIN_MEMORY_COST_KIB (in KiB) |
options.parallelism |
number |
Integer ≥ ARGON2ID_MIN_PARALLELISM (lane count) |
options.length |
number |
Positive integer byte count for derived output |
Returns: Uint8Array of options.length bytes.
Throws: HashError("HASH.KDF.INVALID_PARAMS") for any validation failure.
Error context contains { field: string, value: number, minimum: number }.
ARGON2ID_MIN_MEMORY_COST_KIB = 8
Minimum memory cost in KiB. Based on RFC 9106 §4 minimum recommendation.
ARGON2ID_MIN_TIME_COST = 1
Minimum number of Argon2id iterations. Lower values are pathological.
ARGON2ID_MIN_PARALLELISM = 1
Minimum lane count. Lower values are rejected as invalid.
Argon2idOptions
interface Argon2idOptions {
readonly salt: Uint8Array;
readonly timeCost: number;
readonly memoryCost: number;
readonly parallelism: number;
readonly length: number;
}
Implementation Notes
Parameters are validated in order: timeCost, memoryCost, parallelism,
length. The first failing field short-circuits and throws with that field's
context — no partial execution occurs. The implementation delegates to
@noble/hashes/argon2 which is a pure-JavaScript Argon2id implementation
reviewed by the cryptographic community. Argon2id does not use the HashAlgorithm
dispatch pattern used by hmac, hkdf, and pbkdf2 — Argon2id's internal
structure is fixed and parameterised by t, m, and p rather than a hash
constructor. For this reason, argon2id.ts does not import from mac/hmac.ts.