first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
# argon2id
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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
```ts
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
```ts
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`
```ts
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`.