@hallaxius/argon2w 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +177 -0
- package/dist/argon2w.wasm +0 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.js +383 -0
- package/dist/index.js.map +1 -0
- package/dist/wasm.d.ts +18 -0
- package/dist/wasm.js +124 -0
- package/dist/wasm.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# argon2w
|
|
2
|
+
|
|
3
|
+
Argon2id password hashing for Cloudflare Workers and Node.js, built on the official PHC Argon2 implementation compiled to a standalone SIMD WebAssembly module. It returns PHC strings for storage and verifies them without a native addon.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
bun add @hallaxius/argon2w
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Zero runtime dependencies. The compiled `.wasm` file ships inside the package; you do not need Emscripten or Bun to use it. The package is ESM only — there is no CommonJS build, so use `import` or a dynamic `import()` from CommonJS code.
|
|
12
|
+
|
|
13
|
+
## Hash and verify
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import { hash, verify } from "@hallaxius/argon2w";
|
|
17
|
+
|
|
18
|
+
const encoded = await hash("correct horse battery staple", { profile: "standard" });
|
|
19
|
+
|
|
20
|
+
const authenticated = await verify(encoded, "correct horse battery staple");
|
|
21
|
+
if (!authenticated) throw new Error("Invalid credentials");
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Store `encoded` as the password verifier, never the password itself.
|
|
25
|
+
|
|
26
|
+
`hash()` generates a fresh 16-byte salt unless you supply one. Its defaults are `m=19456` KiB, `t=3`, `p=1`, with a 32-byte tag. The result is an Argon2id v=19 (`0x13`) PHC string — store the entire string.
|
|
27
|
+
|
|
28
|
+
`verify()` returns `false` for a wrong password, a malformed PHC string, or one exceeding the configured cost limits. Invalid API arguments and internal failures can throw, so handle errors at your application boundary.
|
|
29
|
+
|
|
30
|
+
## Profiles
|
|
31
|
+
|
|
32
|
+
Pick a named profile instead of remembering the numbers:
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
import { createProfile, hash, profiles } from "@hallaxius/argon2w";
|
|
36
|
+
|
|
37
|
+
const encoded = await hash("password", { profile: "m16t2" });
|
|
38
|
+
const available = Object.keys(profiles);
|
|
39
|
+
|
|
40
|
+
const custom = createProfile({
|
|
41
|
+
memoryCost: 8192,
|
|
42
|
+
timeCost: 3,
|
|
43
|
+
parallelism: 2,
|
|
44
|
+
hashLength: 32,
|
|
45
|
+
});
|
|
46
|
+
const other = await hash("password", { ...custom });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
| Profile | Memory (KiB) | Passes (`t`) | Lanes (`p`) | Tag (bytes) |
|
|
50
|
+
| --- | ---: | ---: | ---: | ---: |
|
|
51
|
+
| `experimental` | 2048 | 1 | 1 | 32 |
|
|
52
|
+
| `m8t2` | 8192 | 2 | 1 | 32 |
|
|
53
|
+
| `m16t2` | 16384 | 2 | 1 | 32 |
|
|
54
|
+
| `standard` | 19456 | 3 | 1 | 32 |
|
|
55
|
+
| `m32t3` | 32768 | 3 | 1 | 32 |
|
|
56
|
+
| `m32t4` | 32768 | 4 | 1 | 32 |
|
|
57
|
+
|
|
58
|
+
Names describe costs. They are not a security certification or a CPU-time guarantee. Omitting `profile` uses the original defaults, and explicit `timeCost`, `memoryCost`, `parallelism` and `hashLength` still work. Do not combine a named profile with explicit cost fields — the call throws rather than silently overriding parameters. A custom profile is an immutable, validated cost object; spread it into `hash()` or `hashRaw()` and pass `salt`, `secret` or `associatedData` separately on each call.
|
|
59
|
+
|
|
60
|
+
## Rehash policy
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
import { assessRehash, needsRehash, verify } from "@hallaxius/argon2w";
|
|
64
|
+
|
|
65
|
+
const ok = await verify(encoded, password);
|
|
66
|
+
if (ok && needsRehash(encoded, { memoryCost: 19456, timeCost: 3, parallelism: 1 })) {
|
|
67
|
+
const upgraded = await hash(password, { profile: "standard" });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const assessment = assessRehash(encoded, "standard");
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`assessRehash(encoded, profileNameOrCustomProfile)` returns `"matches"`, `"below-target"`, `"above-target"`, `"different-parameters"` or `"unparseable"`. It compares encoded **m/t/p** costs and Argon2id version, not tag length or password validity. Call `verify()` first and migrate only a verified password. `above-target` means keep the stronger hash rather than downgrade it.
|
|
74
|
+
|
|
75
|
+
`needsRehash()` keeps its original exact-field comparison and can return `true` even for a hash that is above the target.
|
|
76
|
+
|
|
77
|
+
## Cloudflare Workers
|
|
78
|
+
|
|
79
|
+
Import the Wasm subpath and configure it once at startup. The subpath resolves to a `WebAssembly.Module`:
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
import argon2Wasm from "@hallaxius/argon2w/dist/argon2w.wasm";
|
|
83
|
+
import { configureWasm, hash, verify } from "@hallaxius/argon2w";
|
|
84
|
+
|
|
85
|
+
configureWasm(argon2Wasm);
|
|
86
|
+
|
|
87
|
+
export default {
|
|
88
|
+
async fetch(request) {
|
|
89
|
+
const ok = await verify(encodedFromYourDatabase, passwordFromRequest);
|
|
90
|
+
return new Response(ok ? "OK" : "FAIL", { status: ok ? 200 : 401 });
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
In TypeScript, add a module declaration for the `.wasm` subpath in your project, for example `src/wasm.d.ts`:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
declare module "*.wasm" {
|
|
99
|
+
const module: WebAssembly.Module;
|
|
100
|
+
export default module;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Hash when setting a password and verify a *stored* PHC string when authenticating. Do not hash on every request.
|
|
105
|
+
|
|
106
|
+
`configureWasm()` also accepts raw Wasm bytes (`Uint8Array`) and starts instantiation eagerly, so the first call does not pay compilation. Call it once during module initialization. `resetWasmCache()` discards a cached instance after an out-of-band trap; the normal entry points already reset themselves on trap-class failures.
|
|
107
|
+
|
|
108
|
+
On Node.js the `.wasm` file is loaded from disk automatically, so `configureWasm()` is only needed when that fallback is unavailable.
|
|
109
|
+
|
|
110
|
+
## Choosing costs
|
|
111
|
+
|
|
112
|
+
`parallelism` is the encoded Argon2 lane count, not a count of Worker threads. The official `ARGON2_NO_THREADS` build runs lanes serially but does **not** rewrite `p` to 1.
|
|
113
|
+
|
|
114
|
+
Costs are the main driver of CPU time. Test against your real traffic and your plan's CPU budget before committing to a profile. A Free-plan measurement at the `experimental` costs recorded one hash-concurrency event at 11 ms against a 10 ms ceiling, with no CPU-limit exceptions in that run. That is a measurement of one workload, not a guarantee for yours.
|
|
115
|
+
|
|
116
|
+
The library never silently lowers `m`, `t` or `p` in response to a plan limit, load, or an error. A request that does not fit your budget fails visibly rather than quietly hashing with weaker parameters.
|
|
117
|
+
|
|
118
|
+
## API reference
|
|
119
|
+
|
|
120
|
+
Memory sizes are in **KiB**. Passwords may be a string (UTF-8 encoded) or `Uint8Array`.
|
|
121
|
+
|
|
122
|
+
| API | Result | Details |
|
|
123
|
+
| --- | --- | --- |
|
|
124
|
+
| `hash(password, options?)` | `Promise<string>` | Encoded Argon2id PHC string; random salt unless `options.salt` is provided. |
|
|
125
|
+
| `hashRaw(password, options?)` | `Promise<Uint8Array>` | Raw tag. Pass an explicit salt if you need reproducibility; this format carries no costs or salt. |
|
|
126
|
+
| `profiles` | Frozen named configurations | Inspect available names and costs; `HashOptions.profile` selects one by name. |
|
|
127
|
+
| `createProfile(costs)` | Frozen cost object | Validates and copies custom m/t/p/tag length; spread into `hash()` or `hashRaw()`. |
|
|
128
|
+
| `assessRehash(encoded, target)` | Assessment string | Compares m/t/p without treating an above-target hash as an upgrade candidate. Throws `Argon2wError` for an invalid `target`; returns `"unparseable"` for any `encoded` that is not a well-formed Argon2id v1.3 string. |
|
|
129
|
+
| `verify(encoded, password, options?)` | `Promise<boolean>` | Enforces cost limits before expensive work. Supply the same `secret` and `associatedData` used at hash time. |
|
|
130
|
+
| `parsePHC(encoded)` | `{ type, version, memoryCost, timeCost, parallelism }` | Parses cost fields. Does not authenticate a password or validate the tag. Throws for malformed structure. |
|
|
131
|
+
| `needsRehash(encoded, policy)` | `boolean` | `true` for invalid, wrong-type or wrong-version strings, or a mismatch on the policy fields you supply. Does not verify a password. |
|
|
132
|
+
| `configureWasm(moduleOrBytes)` | `void` | Configure the Wasm source and start eager instantiation. |
|
|
133
|
+
| `resetWasmCache()` | `void` | Discard the cached instance for recovery. |
|
|
134
|
+
| `bytesToHex(bytes)` | `string` | Lowercase hex for raw tags. |
|
|
135
|
+
| `isVerifyInputFailure(code)` | `boolean` | Maps a C return code from `verify()`. **Inverted from the intuitive reading:** `true` means a benign input-driven failure, which `verify()` turns into `false`; `false` means an internal error, which `verify()` rethrows. Unknown codes default to `true`. |
|
|
136
|
+
|
|
137
|
+
Invalid arguments throw `Argon2wError` with a numeric `code`.
|
|
138
|
+
|
|
139
|
+
### HashOptions
|
|
140
|
+
|
|
141
|
+
| Field | Default | Range |
|
|
142
|
+
| --- | --- | --- |
|
|
143
|
+
| `profile` | — | One of the six profile names |
|
|
144
|
+
| `memoryCost` | 19456 | `max(8, 8 × parallelism)` to 32768 KiB |
|
|
145
|
+
| `timeCost` | 3 | 1 to 16 |
|
|
146
|
+
| `parallelism` | 1 | 1 to 16 |
|
|
147
|
+
| `hashLength` | 32 | 4 to 512 bytes |
|
|
148
|
+
| `salt` | random, 16 bytes | 8 to 1024 bytes |
|
|
149
|
+
| `secret` | — | up to 1024 bytes |
|
|
150
|
+
| `associatedData` | — | up to 1 MiB |
|
|
151
|
+
| `version` | 19 | 19 only |
|
|
152
|
+
|
|
153
|
+
Password input is limited to 1 MiB.
|
|
154
|
+
|
|
155
|
+
### VerifyOptions
|
|
156
|
+
|
|
157
|
+
| Field | Default | Notes |
|
|
158
|
+
| --- | --- | --- |
|
|
159
|
+
| `maxMemoryKib` | 32768 | Rejects a PHC above this before any allocation |
|
|
160
|
+
| `maxTimeCost` | 16 | `0` disables the check, making `verify()` return `false` for every PHC |
|
|
161
|
+
| `maxParallelism` | 16 | Same `0` behaviour |
|
|
162
|
+
| `secret` | — | Must match the value used at hash time |
|
|
163
|
+
| `associatedData` | — | Must match the value used at hash time |
|
|
164
|
+
|
|
165
|
+
Each limit accepts any integer from 0 to 4294967295. Keep these at or below the module's own boundary of 65536 if you need a stored hash with higher costs to remain verifiable — the module rejects anything above that as an ordinary `false`, indistinguishable from a wrong password. Choose limits appropriate to your request budget; never accept untrusted PHC costs without bounds.
|
|
166
|
+
|
|
167
|
+
### Rehash policy
|
|
168
|
+
|
|
169
|
+
`needsRehash()` takes optional `memoryCost`, `timeCost`, `parallelism` and `version` fields and compares only what you supply. Because a non-v1.3 string is already rejected, `version` never changes the result.
|
|
170
|
+
|
|
171
|
+
Neither `needsRehash()` nor `assessRehash()` inspects the tag length, so a hash stored with a dangerously short `hashLength` is reported as `matches`. Verify the password first, then apply your own minimum tag length before rehashing.
|
|
172
|
+
|
|
173
|
+
The exported `MIN_*` / `MAX_*` constants describe the JavaScript boundaries. The WebAssembly module additionally enforces 65536 on memory and time cost as a backstop, so those constants are not the module's absolute ceiling.
|
|
174
|
+
|
|
175
|
+
## Reporting issues
|
|
176
|
+
|
|
177
|
+
[Issues](https://github.com/Hallaxius/argon2w/issues) are the place for reproducible failures. Include your runtime, the parameters you used, and a minimal test case — without real passwords or stored PHC strings.
|
|
Binary file
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { configureWasm, resetWasmCache } from "./wasm.ts";
|
|
2
|
+
export { configureWasm, resetWasmCache };
|
|
3
|
+
export declare const ARGON2_VERSION_13 = 19;
|
|
4
|
+
export declare const MAX_PASSWORD_BYTES: number;
|
|
5
|
+
export declare const MIN_SALT_BYTES = 8;
|
|
6
|
+
export declare const MAX_SALT_BYTES = 1024;
|
|
7
|
+
export declare const MAX_SECRET_BYTES = 1024;
|
|
8
|
+
export declare const MAX_AD_BYTES: number;
|
|
9
|
+
export declare const MIN_TAG_BYTES = 4;
|
|
10
|
+
export declare const MAX_TAG_BYTES = 512;
|
|
11
|
+
export declare const MIN_TIMECOST = 1;
|
|
12
|
+
export declare const MAX_TIMECOST = 16;
|
|
13
|
+
export declare const MIN_PARALLELISM = 1;
|
|
14
|
+
export declare const MAX_PARALLELISM = 16;
|
|
15
|
+
export declare const MIN_MEMORY_KIB = 8;
|
|
16
|
+
export declare const MAX_MEMORY_KIB = 32768;
|
|
17
|
+
export declare const DEFAULT_SALT_BYTES = 16;
|
|
18
|
+
export declare const EXPERIMENTAL_FREE_LOGIN_COSTS: Readonly<{
|
|
19
|
+
memoryCost: number;
|
|
20
|
+
timeCost: number;
|
|
21
|
+
parallelism: number;
|
|
22
|
+
hashLength: number;
|
|
23
|
+
}>;
|
|
24
|
+
export declare const profiles: Readonly<{
|
|
25
|
+
experimental: Readonly<{
|
|
26
|
+
memoryCost: number;
|
|
27
|
+
timeCost: number;
|
|
28
|
+
parallelism: number;
|
|
29
|
+
hashLength: number;
|
|
30
|
+
}>;
|
|
31
|
+
m8t2: Readonly<{
|
|
32
|
+
memoryCost: 8192;
|
|
33
|
+
timeCost: 2;
|
|
34
|
+
parallelism: 1;
|
|
35
|
+
hashLength: 32;
|
|
36
|
+
}>;
|
|
37
|
+
m16t2: Readonly<{
|
|
38
|
+
memoryCost: 16384;
|
|
39
|
+
timeCost: 2;
|
|
40
|
+
parallelism: 1;
|
|
41
|
+
hashLength: 32;
|
|
42
|
+
}>;
|
|
43
|
+
standard: Readonly<{
|
|
44
|
+
memoryCost: 19456;
|
|
45
|
+
timeCost: 3;
|
|
46
|
+
parallelism: 1;
|
|
47
|
+
hashLength: 32;
|
|
48
|
+
}>;
|
|
49
|
+
m32t3: Readonly<{
|
|
50
|
+
memoryCost: 32768;
|
|
51
|
+
timeCost: 3;
|
|
52
|
+
parallelism: 1;
|
|
53
|
+
hashLength: 32;
|
|
54
|
+
}>;
|
|
55
|
+
m32t4: Readonly<{
|
|
56
|
+
memoryCost: 32768;
|
|
57
|
+
timeCost: 4;
|
|
58
|
+
parallelism: 1;
|
|
59
|
+
hashLength: 32;
|
|
60
|
+
}>;
|
|
61
|
+
}>;
|
|
62
|
+
export type ProfileName = keyof typeof profiles;
|
|
63
|
+
export interface PasswordProfile {
|
|
64
|
+
readonly memoryCost: number;
|
|
65
|
+
readonly timeCost: number;
|
|
66
|
+
readonly parallelism: number;
|
|
67
|
+
readonly hashLength: number;
|
|
68
|
+
}
|
|
69
|
+
export declare function createProfile(costs: PasswordProfile): Readonly<PasswordProfile>;
|
|
70
|
+
export type PasswordInput = string | Uint8Array;
|
|
71
|
+
export interface HashOptions {
|
|
72
|
+
profile?: ProfileName;
|
|
73
|
+
timeCost?: number;
|
|
74
|
+
memoryCost?: number;
|
|
75
|
+
parallelism?: number;
|
|
76
|
+
hashLength?: number;
|
|
77
|
+
salt?: Uint8Array;
|
|
78
|
+
secret?: Uint8Array;
|
|
79
|
+
associatedData?: Uint8Array;
|
|
80
|
+
version?: number;
|
|
81
|
+
}
|
|
82
|
+
export declare class Argon2wError extends Error {
|
|
83
|
+
readonly code: number;
|
|
84
|
+
constructor(code: number, message: string);
|
|
85
|
+
}
|
|
86
|
+
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
87
|
+
export declare function hash(password: PasswordInput, options?: HashOptions): Promise<string>;
|
|
88
|
+
export interface VerifyOptions {
|
|
89
|
+
secret?: Uint8Array;
|
|
90
|
+
associatedData?: Uint8Array;
|
|
91
|
+
maxMemoryKib?: number;
|
|
92
|
+
maxTimeCost?: number;
|
|
93
|
+
maxParallelism?: number;
|
|
94
|
+
}
|
|
95
|
+
export declare function isVerifyInputFailure(code: number): boolean;
|
|
96
|
+
export declare function verify(encoded: string, password: PasswordInput, options?: VerifyOptions): Promise<boolean>;
|
|
97
|
+
export interface ParsedPHC {
|
|
98
|
+
type: string;
|
|
99
|
+
version: number;
|
|
100
|
+
memoryCost: number;
|
|
101
|
+
timeCost: number;
|
|
102
|
+
parallelism: number;
|
|
103
|
+
}
|
|
104
|
+
export declare function parsePHC(encoded: string): ParsedPHC;
|
|
105
|
+
export interface Policy {
|
|
106
|
+
timeCost?: number;
|
|
107
|
+
memoryCost?: number;
|
|
108
|
+
parallelism?: number;
|
|
109
|
+
version?: number;
|
|
110
|
+
}
|
|
111
|
+
export declare function needsRehash(encoded: string, policy: Policy): boolean;
|
|
112
|
+
export type RehashAssessment = "matches" | "below-target" | "above-target" | "different-parameters" | "unparseable";
|
|
113
|
+
export declare function assessRehash(encoded: string, target: ProfileName | PasswordProfile): RehashAssessment;
|
|
114
|
+
export declare function hashRaw(password: PasswordInput, options?: HashOptions): Promise<Uint8Array>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import { configureWasm, getWasm, isTrapError, memoryBytes, readCString, resetWasmCache, toOwned, } from "./wasm.js";
|
|
2
|
+
export { configureWasm, resetWasmCache };
|
|
3
|
+
export const ARGON2_VERSION_13 = 19;
|
|
4
|
+
const ARGON2_TYPE_ID = 2;
|
|
5
|
+
export const MAX_PASSWORD_BYTES = 1 << 20;
|
|
6
|
+
export const MIN_SALT_BYTES = 8;
|
|
7
|
+
export const MAX_SALT_BYTES = 1024;
|
|
8
|
+
export const MAX_SECRET_BYTES = 1024;
|
|
9
|
+
export const MAX_AD_BYTES = 1 << 20;
|
|
10
|
+
export const MIN_TAG_BYTES = 4;
|
|
11
|
+
export const MAX_TAG_BYTES = 512;
|
|
12
|
+
export const MIN_TIMECOST = 1;
|
|
13
|
+
export const MAX_TIMECOST = 16;
|
|
14
|
+
export const MIN_PARALLELISM = 1;
|
|
15
|
+
export const MAX_PARALLELISM = 16;
|
|
16
|
+
export const MIN_MEMORY_KIB = 8;
|
|
17
|
+
export const MAX_MEMORY_KIB = 32768;
|
|
18
|
+
export const DEFAULT_SALT_BYTES = 16;
|
|
19
|
+
export const EXPERIMENTAL_FREE_LOGIN_COSTS = Object.freeze({
|
|
20
|
+
memoryCost: 2048,
|
|
21
|
+
timeCost: 1,
|
|
22
|
+
parallelism: 1,
|
|
23
|
+
hashLength: 32,
|
|
24
|
+
});
|
|
25
|
+
export const profiles = Object.freeze({
|
|
26
|
+
experimental: EXPERIMENTAL_FREE_LOGIN_COSTS,
|
|
27
|
+
m8t2: Object.freeze({ memoryCost: 8192, timeCost: 2, parallelism: 1, hashLength: 32 }),
|
|
28
|
+
m16t2: Object.freeze({ memoryCost: 16384, timeCost: 2, parallelism: 1, hashLength: 32 }),
|
|
29
|
+
standard: Object.freeze({ memoryCost: 19456, timeCost: 3, parallelism: 1, hashLength: 32 }),
|
|
30
|
+
m32t3: Object.freeze({ memoryCost: 32768, timeCost: 3, parallelism: 1, hashLength: 32 }),
|
|
31
|
+
m32t4: Object.freeze({ memoryCost: 32768, timeCost: 4, parallelism: 1, hashLength: 32 }),
|
|
32
|
+
});
|
|
33
|
+
export function createProfile(costs) {
|
|
34
|
+
if (costs === null || typeof costs !== "object") {
|
|
35
|
+
throw new Argon2wError(-30, "profile must be an object");
|
|
36
|
+
}
|
|
37
|
+
const parallelism = checkInt("parallelism", costs.parallelism, MIN_PARALLELISM, MAX_PARALLELISM);
|
|
38
|
+
const profile = {
|
|
39
|
+
memoryCost: checkInt("memoryCost", costs.memoryCost, Math.max(MIN_MEMORY_KIB, 8 * parallelism), MAX_MEMORY_KIB),
|
|
40
|
+
timeCost: checkInt("timeCost", costs.timeCost, MIN_TIMECOST, MAX_TIMECOST),
|
|
41
|
+
parallelism,
|
|
42
|
+
hashLength: checkInt("hashLength", costs.hashLength, MIN_TAG_BYTES, MAX_TAG_BYTES),
|
|
43
|
+
};
|
|
44
|
+
return Object.freeze(profile);
|
|
45
|
+
}
|
|
46
|
+
export class Argon2wError extends Error {
|
|
47
|
+
code;
|
|
48
|
+
constructor(code, message) {
|
|
49
|
+
super(`argon2w: ${message} (code ${code})`);
|
|
50
|
+
this.name = "Argon2wError";
|
|
51
|
+
this.code = code;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function bytesToHex(bytes) {
|
|
55
|
+
let out = "";
|
|
56
|
+
for (const b of bytes) {
|
|
57
|
+
out += b.toString(16).padStart(2, "0");
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
function toBytes(input, label, max) {
|
|
62
|
+
const bytes = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
63
|
+
if (!(bytes instanceof Uint8Array)) {
|
|
64
|
+
throw new Argon2wError(-30, `${label} must be a string or Uint8Array`);
|
|
65
|
+
}
|
|
66
|
+
if (bytes.length > max) {
|
|
67
|
+
throw new Argon2wError(-30, `${label} exceeds ${max} bytes`);
|
|
68
|
+
}
|
|
69
|
+
return toOwned(bytes);
|
|
70
|
+
}
|
|
71
|
+
function toOwnedOption(value, label, max) {
|
|
72
|
+
const bytes = value ?? new Uint8Array(0);
|
|
73
|
+
if (!(bytes instanceof Uint8Array)) {
|
|
74
|
+
throw new Argon2wError(-30, `${label} must be a Uint8Array`);
|
|
75
|
+
}
|
|
76
|
+
checkInt(`${label} length`, bytes.length, 0, max);
|
|
77
|
+
return toOwned(bytes);
|
|
78
|
+
}
|
|
79
|
+
function checkInt(name, value, min, max) {
|
|
80
|
+
if (!Number.isInteger(value) || value < min || value > max) {
|
|
81
|
+
throw new Argon2wError(-30, `${name} must be an integer in [${min}, ${max}]`);
|
|
82
|
+
}
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
function resolveParams(password, options = {}) {
|
|
86
|
+
if (options === null || typeof options !== "object") {
|
|
87
|
+
throw new Argon2wError(-30, "options must be an object");
|
|
88
|
+
}
|
|
89
|
+
let costs = options;
|
|
90
|
+
if (options.profile !== undefined) {
|
|
91
|
+
if (typeof options.profile !== "string" || !Object.hasOwn(profiles, options.profile)) {
|
|
92
|
+
throw new Argon2wError(-30, "unknown hash profile");
|
|
93
|
+
}
|
|
94
|
+
if ([options.memoryCost, options.timeCost, options.parallelism, options.hashLength].some((value) => value !== undefined)) {
|
|
95
|
+
throw new Argon2wError(-30, "profile cannot be combined with explicit costs");
|
|
96
|
+
}
|
|
97
|
+
costs = { ...options, ...profiles[options.profile] };
|
|
98
|
+
}
|
|
99
|
+
const pwd = toBytes(password, "password", MAX_PASSWORD_BYTES);
|
|
100
|
+
const rawSalt = options.salt === undefined
|
|
101
|
+
? crypto.getRandomValues(new Uint8Array(DEFAULT_SALT_BYTES))
|
|
102
|
+
: options.salt;
|
|
103
|
+
if (!(rawSalt instanceof Uint8Array)) {
|
|
104
|
+
throw new Argon2wError(-30, "salt must be a Uint8Array");
|
|
105
|
+
}
|
|
106
|
+
checkInt("salt length", rawSalt.length, MIN_SALT_BYTES, MAX_SALT_BYTES);
|
|
107
|
+
const salt = toOwned(rawSalt);
|
|
108
|
+
const secret = toOwnedOption(options.secret, "secret", MAX_SECRET_BYTES);
|
|
109
|
+
const ad = toOwnedOption(options.associatedData, "associatedData", MAX_AD_BYTES);
|
|
110
|
+
const version = options.version ?? ARGON2_VERSION_13;
|
|
111
|
+
if (version !== ARGON2_VERSION_13) {
|
|
112
|
+
throw new Argon2wError(-26, "only Argon2 version 19 (0x13) is supported");
|
|
113
|
+
}
|
|
114
|
+
const tCost = checkInt("timeCost", costs.timeCost ?? 3, MIN_TIMECOST, MAX_TIMECOST);
|
|
115
|
+
const lanes = checkInt("parallelism", costs.parallelism ?? 1, MIN_PARALLELISM, MAX_PARALLELISM);
|
|
116
|
+
const mCost = checkInt("memoryCost", costs.memoryCost ?? 19456, Math.max(MIN_MEMORY_KIB, 8 * lanes), MAX_MEMORY_KIB);
|
|
117
|
+
const outlen = checkInt("hashLength", costs.hashLength ?? 32, MIN_TAG_BYTES, MAX_TAG_BYTES);
|
|
118
|
+
return { pwd, salt, secret, ad, tCost, mCost, lanes, outlen };
|
|
119
|
+
}
|
|
120
|
+
function allocCopy(wasm, data, track) {
|
|
121
|
+
if (data.length === 0) {
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
const ptr = wasm.argon2w_alloc(data.length);
|
|
125
|
+
if (ptr === 0) {
|
|
126
|
+
throw new Argon2wError(-22, "wasm allocation failed");
|
|
127
|
+
}
|
|
128
|
+
track.ptrs.push({ ptr, size: data.length });
|
|
129
|
+
memoryBytes(wasm).set(data, ptr);
|
|
130
|
+
return ptr;
|
|
131
|
+
}
|
|
132
|
+
function freeAll(wasm, track) {
|
|
133
|
+
for (const { ptr, size } of track.ptrs) {
|
|
134
|
+
try {
|
|
135
|
+
wasm.argon2w_free(ptr, size);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
track.ptrs.length = 0;
|
|
141
|
+
}
|
|
142
|
+
function throwIfError(wasm, code) {
|
|
143
|
+
if (code !== 0) {
|
|
144
|
+
const ptr = wasm.argon2w_error_message(code);
|
|
145
|
+
throw new Argon2wError(code, readCString(wasm, ptr));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export async function hash(password, options = {}) {
|
|
149
|
+
const params = resolveParams(password, options);
|
|
150
|
+
const wasm = await getWasm();
|
|
151
|
+
const track = { ptrs: [] };
|
|
152
|
+
try {
|
|
153
|
+
const pwdPtr = allocCopy(wasm, params.pwd, track);
|
|
154
|
+
const saltPtr = allocCopy(wasm, params.salt, track);
|
|
155
|
+
const secretPtr = allocCopy(wasm, params.secret, track);
|
|
156
|
+
const adPtr = allocCopy(wasm, params.ad, track);
|
|
157
|
+
const outPtr = wasm.argon2w_alloc(params.outlen);
|
|
158
|
+
if (outPtr === 0) {
|
|
159
|
+
throw new Argon2wError(-22, "wasm allocation failed");
|
|
160
|
+
}
|
|
161
|
+
track.ptrs.push({ ptr: outPtr, size: params.outlen });
|
|
162
|
+
const encodedLen = wasm.argon2w_encoded_len(params.tCost, params.mCost, params.lanes, params.salt.length, params.outlen);
|
|
163
|
+
if (encodedLen <= 0 || encodedLen > 1 << 20) {
|
|
164
|
+
throw new Argon2wError(-30, "invalid encoded length");
|
|
165
|
+
}
|
|
166
|
+
const encodedPtr = wasm.argon2w_alloc(encodedLen);
|
|
167
|
+
if (encodedPtr === 0) {
|
|
168
|
+
throw new Argon2wError(-22, "wasm allocation failed");
|
|
169
|
+
}
|
|
170
|
+
track.ptrs.push({ ptr: encodedPtr, size: encodedLen });
|
|
171
|
+
const code = wasm.argon2w_hash_encoded(ARGON2_TYPE_ID, ARGON2_VERSION_13, pwdPtr, params.pwd.length, saltPtr, params.salt.length, secretPtr, params.secret.length, adPtr, params.ad.length, params.tCost, params.mCost, params.lanes, outPtr, params.outlen, encodedPtr, encodedLen);
|
|
172
|
+
throwIfError(wasm, code);
|
|
173
|
+
return readCString(wasm, encodedPtr);
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
if (isTrapError(error)) {
|
|
177
|
+
resetWasmCache();
|
|
178
|
+
}
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
params.pwd.fill(0);
|
|
183
|
+
params.salt.fill(0);
|
|
184
|
+
params.secret.fill(0);
|
|
185
|
+
params.ad.fill(0);
|
|
186
|
+
freeAll(wasm, track);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export function isVerifyInputFailure(code) {
|
|
190
|
+
switch (code) {
|
|
191
|
+
case -22:
|
|
192
|
+
case -31:
|
|
193
|
+
case -33:
|
|
194
|
+
case -1:
|
|
195
|
+
case -18:
|
|
196
|
+
case -19:
|
|
197
|
+
case -20:
|
|
198
|
+
case -21:
|
|
199
|
+
case -23:
|
|
200
|
+
case -24:
|
|
201
|
+
case -27:
|
|
202
|
+
return false;
|
|
203
|
+
default:
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
export async function verify(encoded, password, options = {}) {
|
|
208
|
+
if (typeof encoded !== "string" || encoded.length > 1 << 20) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
const maxMemoryKib = options.maxMemoryKib ?? MAX_MEMORY_KIB;
|
|
212
|
+
const maxTimeCost = options.maxTimeCost ?? MAX_TIMECOST;
|
|
213
|
+
const maxParallelism = options.maxParallelism ?? MAX_PARALLELISM;
|
|
214
|
+
checkInt("maxMemoryKib", maxMemoryKib, 0, 4294967295);
|
|
215
|
+
checkInt("maxTimeCost", maxTimeCost, 0, 4294967295);
|
|
216
|
+
checkInt("maxParallelism", maxParallelism, 0, 4294967295);
|
|
217
|
+
try {
|
|
218
|
+
const gate = parsePHC(encoded);
|
|
219
|
+
if (gate.memoryCost > maxMemoryKib ||
|
|
220
|
+
gate.timeCost > maxTimeCost ||
|
|
221
|
+
gate.parallelism > maxParallelism) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
}
|
|
227
|
+
const pwd = toBytes(password, "password", MAX_PASSWORD_BYTES);
|
|
228
|
+
const secret = toOwnedOption(options.secret, "secret", MAX_SECRET_BYTES);
|
|
229
|
+
const ad = toOwnedOption(options.associatedData, "associatedData", MAX_AD_BYTES);
|
|
230
|
+
const wasm = await getWasm();
|
|
231
|
+
const track = { ptrs: [] };
|
|
232
|
+
const encodedBytes = new TextEncoder().encode(encoded);
|
|
233
|
+
const encodedNul = new Uint8Array(encodedBytes.length + 1);
|
|
234
|
+
encodedNul.set(encodedBytes, 0);
|
|
235
|
+
encodedBytes.fill(0);
|
|
236
|
+
try {
|
|
237
|
+
const encodedPtr = allocCopy(wasm, encodedNul, track);
|
|
238
|
+
const pwdPtr = allocCopy(wasm, pwd, track);
|
|
239
|
+
const secretPtr = allocCopy(wasm, secret, track);
|
|
240
|
+
const adPtr = allocCopy(wasm, ad, track);
|
|
241
|
+
const code = wasm.argon2w_verify(encodedPtr, pwdPtr, pwd.length, secretPtr, secret.length, adPtr, ad.length);
|
|
242
|
+
if (!isVerifyInputFailure(code)) {
|
|
243
|
+
throwIfError(wasm, code);
|
|
244
|
+
}
|
|
245
|
+
return code === 0;
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
if (isTrapError(error)) {
|
|
249
|
+
resetWasmCache();
|
|
250
|
+
}
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
pwd.fill(0);
|
|
255
|
+
secret.fill(0);
|
|
256
|
+
ad.fill(0);
|
|
257
|
+
encodedNul.fill(0);
|
|
258
|
+
freeAll(wasm, track);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const PHC_RE = /^\$(argon2(?:d|i|id))\$v=(\d+)\$m=(\d+),t=(\d+),p=(\d+)\$([^$]+)\$([^$]+)$/;
|
|
262
|
+
function parseDecimalU32(text, label) {
|
|
263
|
+
if (text === undefined || !/^(0|[1-9][0-9]*)$/.test(text)) {
|
|
264
|
+
throw new Argon2wError(-32, `malformed PHC ${label}`);
|
|
265
|
+
}
|
|
266
|
+
if (text.length > 10) {
|
|
267
|
+
throw new Argon2wError(-32, `malformed PHC ${label}`);
|
|
268
|
+
}
|
|
269
|
+
const value = Number(text);
|
|
270
|
+
if (!Number.isSafeInteger(value) || value > 4294967295) {
|
|
271
|
+
throw new Argon2wError(-32, `malformed PHC ${label}`);
|
|
272
|
+
}
|
|
273
|
+
return value;
|
|
274
|
+
}
|
|
275
|
+
export function parsePHC(encoded) {
|
|
276
|
+
if (typeof encoded !== "string" || encoded.length > 1 << 20) {
|
|
277
|
+
throw new Argon2wError(-32, "malformed PHC string");
|
|
278
|
+
}
|
|
279
|
+
const match = PHC_RE.exec(encoded);
|
|
280
|
+
if (match === null) {
|
|
281
|
+
throw new Argon2wError(-32, "malformed PHC string");
|
|
282
|
+
}
|
|
283
|
+
const type = match[1] ?? "";
|
|
284
|
+
const version = parseDecimalU32(match[2], "version");
|
|
285
|
+
const memoryCost = parseDecimalU32(match[3], "memory cost");
|
|
286
|
+
const timeCost = parseDecimalU32(match[4], "time cost");
|
|
287
|
+
const parallelism = parseDecimalU32(match[5], "parallelism");
|
|
288
|
+
return { type, version, memoryCost, timeCost, parallelism };
|
|
289
|
+
}
|
|
290
|
+
export function needsRehash(encoded, policy) {
|
|
291
|
+
let parsed;
|
|
292
|
+
try {
|
|
293
|
+
parsed = parsePHC(encoded);
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
if (parsed.type !== "argon2id" || parsed.version !== ARGON2_VERSION_13) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
if (policy.version !== undefined && parsed.version !== policy.version) {
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
if (policy.memoryCost !== undefined &&
|
|
305
|
+
parsed.memoryCost !== policy.memoryCost) {
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
if (policy.timeCost !== undefined && parsed.timeCost !== policy.timeCost) {
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
if (policy.parallelism !== undefined &&
|
|
312
|
+
parsed.parallelism !== policy.parallelism) {
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
export function assessRehash(encoded, target) {
|
|
318
|
+
const profile = typeof target === "string"
|
|
319
|
+
? Object.hasOwn(profiles, target)
|
|
320
|
+
? profiles[target]
|
|
321
|
+
: undefined
|
|
322
|
+
: createProfile(target);
|
|
323
|
+
if (profile === undefined) {
|
|
324
|
+
throw new Argon2wError(-30, "unknown hash profile");
|
|
325
|
+
}
|
|
326
|
+
let parsed;
|
|
327
|
+
try {
|
|
328
|
+
parsed = parsePHC(encoded);
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
return "unparseable";
|
|
332
|
+
}
|
|
333
|
+
if (parsed.type !== "argon2id" || parsed.version !== ARGON2_VERSION_13) {
|
|
334
|
+
return "unparseable";
|
|
335
|
+
}
|
|
336
|
+
const memory = parsed.memoryCost - profile.memoryCost;
|
|
337
|
+
const time = parsed.timeCost - profile.timeCost;
|
|
338
|
+
const lanes = parsed.parallelism - profile.parallelism;
|
|
339
|
+
if (memory === 0 && time === 0 && lanes === 0) {
|
|
340
|
+
return "matches";
|
|
341
|
+
}
|
|
342
|
+
if (memory >= 0 && time >= 0 && lanes >= 0) {
|
|
343
|
+
return "above-target";
|
|
344
|
+
}
|
|
345
|
+
if (memory <= 0 && time <= 0 && lanes <= 0) {
|
|
346
|
+
return "below-target";
|
|
347
|
+
}
|
|
348
|
+
return "different-parameters";
|
|
349
|
+
}
|
|
350
|
+
export async function hashRaw(password, options = {}) {
|
|
351
|
+
const params = resolveParams(password, options);
|
|
352
|
+
const wasm = await getWasm();
|
|
353
|
+
const track = { ptrs: [] };
|
|
354
|
+
try {
|
|
355
|
+
const pwdPtr = allocCopy(wasm, params.pwd, track);
|
|
356
|
+
const saltPtr = allocCopy(wasm, params.salt, track);
|
|
357
|
+
const secretPtr = allocCopy(wasm, params.secret, track);
|
|
358
|
+
const adPtr = allocCopy(wasm, params.ad, track);
|
|
359
|
+
const outPtr = wasm.argon2w_alloc(params.outlen);
|
|
360
|
+
if (outPtr === 0) {
|
|
361
|
+
throw new Argon2wError(-22, "wasm allocation failed");
|
|
362
|
+
}
|
|
363
|
+
track.ptrs.push({ ptr: outPtr, size: params.outlen });
|
|
364
|
+
const code = wasm.argon2w_hash_raw(ARGON2_TYPE_ID, ARGON2_VERSION_13, pwdPtr, params.pwd.length, saltPtr, params.salt.length, secretPtr, params.secret.length, adPtr, params.ad.length, params.tCost, params.mCost, params.lanes, outPtr, params.outlen);
|
|
365
|
+
throwIfError(wasm, code);
|
|
366
|
+
const tag = memoryBytes(wasm).slice(outPtr, outPtr + params.outlen);
|
|
367
|
+
return tag;
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
if (isTrapError(error)) {
|
|
371
|
+
resetWasmCache();
|
|
372
|
+
}
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
params.pwd.fill(0);
|
|
377
|
+
params.salt.fill(0);
|
|
378
|
+
params.secret.fill(0);
|
|
379
|
+
params.ad.fill(0);
|
|
380
|
+
freeAll(wasm, track);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n configureWasm,\n getWasm,\n isTrapError,\n memoryBytes,\n readCString,\n resetWasmCache,\n toOwned,\n type Argon2wExports,\n} from \"./wasm.ts\";\n\nexport { configureWasm, resetWasmCache };\n\nexport const ARGON2_VERSION_13 = 19;\nconst ARGON2_TYPE_ID = 2;\n\nexport const MAX_PASSWORD_BYTES = 1 << 20;\nexport const MIN_SALT_BYTES = 8;\nexport const MAX_SALT_BYTES = 1024;\nexport const MAX_SECRET_BYTES = 1024;\nexport const MAX_AD_BYTES = 1 << 20;\nexport const MIN_TAG_BYTES = 4;\nexport const MAX_TAG_BYTES = 512;\nexport const MIN_TIMECOST = 1;\nexport const MAX_TIMECOST = 16;\nexport const MIN_PARALLELISM = 1;\nexport const MAX_PARALLELISM = 16;\nexport const MIN_MEMORY_KIB = 8;\nexport const MAX_MEMORY_KIB = 32768;\nexport const DEFAULT_SALT_BYTES = 16;\n\nexport const EXPERIMENTAL_FREE_LOGIN_COSTS: Readonly<{\n memoryCost: number;\n timeCost: number;\n parallelism: number;\n hashLength: number;\n}> = Object.freeze({\n memoryCost: 2048,\n timeCost: 1,\n parallelism: 1,\n hashLength: 32,\n});\n\nexport const profiles = Object.freeze({\n experimental: EXPERIMENTAL_FREE_LOGIN_COSTS,\n m8t2: Object.freeze({ memoryCost: 8192, timeCost: 2, parallelism: 1, hashLength: 32 }),\n m16t2: Object.freeze({ memoryCost: 16384, timeCost: 2, parallelism: 1, hashLength: 32 }),\n standard: Object.freeze({ memoryCost: 19456, timeCost: 3, parallelism: 1, hashLength: 32 }),\n m32t3: Object.freeze({ memoryCost: 32768, timeCost: 3, parallelism: 1, hashLength: 32 }),\n m32t4: Object.freeze({ memoryCost: 32768, timeCost: 4, parallelism: 1, hashLength: 32 }),\n});\n\nexport type ProfileName = keyof typeof profiles;\n\nexport interface PasswordProfile {\n readonly memoryCost: number;\n readonly timeCost: number;\n readonly parallelism: number;\n readonly hashLength: number;\n}\n\nexport function createProfile(costs: PasswordProfile): Readonly<PasswordProfile> {\n if (costs === null || typeof costs !== \"object\") {\n throw new Argon2wError(-30, \"profile must be an object\");\n }\n const parallelism = checkInt(\"parallelism\", costs.parallelism, MIN_PARALLELISM, MAX_PARALLELISM);\n const profile = {\n memoryCost: checkInt(\"memoryCost\", costs.memoryCost, Math.max(MIN_MEMORY_KIB, 8 * parallelism), MAX_MEMORY_KIB),\n timeCost: checkInt(\"timeCost\", costs.timeCost, MIN_TIMECOST, MAX_TIMECOST),\n parallelism,\n hashLength: checkInt(\"hashLength\", costs.hashLength, MIN_TAG_BYTES, MAX_TAG_BYTES),\n };\n return Object.freeze(profile);\n}\n\nexport type PasswordInput = string | Uint8Array;\n\nexport interface HashOptions {\n profile?: ProfileName;\n timeCost?: number;\n memoryCost?: number;\n parallelism?: number;\n hashLength?: number;\n salt?: Uint8Array;\n secret?: Uint8Array;\n associatedData?: Uint8Array;\n version?: number;\n}\n\nexport class Argon2wError extends Error {\n readonly code: number;\n constructor(code: number, message: string) {\n super(`argon2w: ${message} (code ${code})`);\n this.name = \"Argon2wError\";\n this.code = code;\n }\n}\n\nexport function bytesToHex(bytes: Uint8Array): string {\n let out = \"\";\n for (const b of bytes) {\n out += b.toString(16).padStart(2, \"0\");\n }\n return out;\n}\n\nfunction toBytes(\n input: PasswordInput,\n label: string,\n max: number,\n): Uint8Array<ArrayBuffer> {\n const bytes =\n typeof input === \"string\" ? new TextEncoder().encode(input) : input;\n if (!(bytes instanceof Uint8Array)) {\n throw new Argon2wError(-30, `${label} must be a string or Uint8Array`);\n }\n if (bytes.length > max) {\n throw new Argon2wError(-30, `${label} exceeds ${max} bytes`);\n }\n return toOwned(bytes);\n}\n\nfunction toOwnedOption(\n value: Uint8Array | undefined,\n label: string,\n max: number,\n): Uint8Array<ArrayBuffer> {\n const bytes = value ?? new Uint8Array(0);\n if (!(bytes instanceof Uint8Array)) {\n throw new Argon2wError(-30, `${label} must be a Uint8Array`);\n }\n checkInt(`${label} length`, bytes.length, 0, max);\n return toOwned(bytes);\n}\n\ninterface ResolvedParams {\n pwd: Uint8Array<ArrayBuffer>;\n salt: Uint8Array<ArrayBuffer>;\n secret: Uint8Array<ArrayBuffer>;\n ad: Uint8Array<ArrayBuffer>;\n tCost: number;\n mCost: number;\n lanes: number;\n outlen: number;\n}\n\nfunction checkInt(name: string, value: number, min: number, max: number): number {\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new Argon2wError(-30, `${name} must be an integer in [${min}, ${max}]`);\n }\n return value;\n}\n\nfunction resolveParams(\n password: PasswordInput,\n options: HashOptions = {},\n): ResolvedParams {\n if (options === null || typeof options !== \"object\") {\n throw new Argon2wError(-30, \"options must be an object\");\n }\n let costs: HashOptions = options;\n if (options.profile !== undefined) {\n if (typeof options.profile !== \"string\" || !Object.hasOwn(profiles, options.profile)) {\n throw new Argon2wError(-30, \"unknown hash profile\");\n }\n if ([options.memoryCost, options.timeCost, options.parallelism, options.hashLength].some((value) => value !== undefined)) {\n throw new Argon2wError(-30, \"profile cannot be combined with explicit costs\");\n }\n costs = { ...options, ...profiles[options.profile] };\n }\n const pwd = toBytes(password, \"password\", MAX_PASSWORD_BYTES);\n const rawSalt =\n options.salt === undefined\n ? crypto.getRandomValues(new Uint8Array(DEFAULT_SALT_BYTES))\n : options.salt;\n if (!(rawSalt instanceof Uint8Array)) {\n throw new Argon2wError(-30, \"salt must be a Uint8Array\");\n }\n checkInt(\"salt length\", rawSalt.length, MIN_SALT_BYTES, MAX_SALT_BYTES);\n const salt = toOwned(rawSalt);\n const secret = toOwnedOption(options.secret, \"secret\", MAX_SECRET_BYTES);\n const ad = toOwnedOption(\n options.associatedData,\n \"associatedData\",\n MAX_AD_BYTES,\n );\n const version = options.version ?? ARGON2_VERSION_13;\n if (version !== ARGON2_VERSION_13) {\n throw new Argon2wError(-26, \"only Argon2 version 19 (0x13) is supported\");\n }\n const tCost = checkInt(\n \"timeCost\",\n costs.timeCost ?? 3,\n MIN_TIMECOST,\n MAX_TIMECOST,\n );\n const lanes = checkInt(\n \"parallelism\",\n costs.parallelism ?? 1,\n MIN_PARALLELISM,\n MAX_PARALLELISM,\n );\n const mCost = checkInt(\n \"memoryCost\",\n costs.memoryCost ?? 19456,\n Math.max(MIN_MEMORY_KIB, 8 * lanes),\n MAX_MEMORY_KIB,\n );\n const outlen = checkInt(\n \"hashLength\",\n costs.hashLength ?? 32,\n MIN_TAG_BYTES,\n MAX_TAG_BYTES,\n );\n return { pwd, salt, secret, ad, tCost, mCost, lanes, outlen };\n}\n\ninterface Allocations {\n ptrs: Array<{ ptr: number; size: number }>;\n}\n\nfunction allocCopy(\n wasm: Argon2wExports,\n data: Uint8Array,\n track: Allocations,\n): number {\n if (data.length === 0) {\n return 0;\n }\n const ptr = wasm.argon2w_alloc(data.length);\n if (ptr === 0) {\n throw new Argon2wError(-22, \"wasm allocation failed\");\n }\n track.ptrs.push({ ptr, size: data.length });\n memoryBytes(wasm).set(data, ptr);\n return ptr;\n}\n\nfunction freeAll(wasm: Argon2wExports, track: Allocations): void {\n for (const { ptr, size } of track.ptrs) {\n try {\n wasm.argon2w_free(ptr, size);\n } catch {\n }\n }\n track.ptrs.length = 0;\n}\n\nfunction throwIfError(wasm: Argon2wExports, code: number): void {\n if (code !== 0) {\n const ptr = wasm.argon2w_error_message(code);\n throw new Argon2wError(code, readCString(wasm, ptr));\n }\n}\n\nexport async function hash(\n password: PasswordInput,\n options: HashOptions = {},\n): Promise<string> {\n const params = resolveParams(password, options);\n const wasm = await getWasm();\n const track: Allocations = { ptrs: [] };\n try {\n const pwdPtr = allocCopy(wasm, params.pwd, track);\n const saltPtr = allocCopy(wasm, params.salt, track);\n const secretPtr = allocCopy(wasm, params.secret, track);\n const adPtr = allocCopy(wasm, params.ad, track);\n const outPtr = wasm.argon2w_alloc(params.outlen);\n if (outPtr === 0) {\n throw new Argon2wError(-22, \"wasm allocation failed\");\n }\n track.ptrs.push({ ptr: outPtr, size: params.outlen });\n const encodedLen = wasm.argon2w_encoded_len(\n params.tCost,\n params.mCost,\n params.lanes,\n params.salt.length,\n params.outlen,\n );\n if (encodedLen <= 0 || encodedLen > 1 << 20) {\n throw new Argon2wError(-30, \"invalid encoded length\");\n }\n const encodedPtr = wasm.argon2w_alloc(encodedLen);\n if (encodedPtr === 0) {\n throw new Argon2wError(-22, \"wasm allocation failed\");\n }\n track.ptrs.push({ ptr: encodedPtr, size: encodedLen });\n const code = wasm.argon2w_hash_encoded(\n ARGON2_TYPE_ID,\n ARGON2_VERSION_13,\n pwdPtr,\n params.pwd.length,\n saltPtr,\n params.salt.length,\n secretPtr,\n params.secret.length,\n adPtr,\n params.ad.length,\n params.tCost,\n params.mCost,\n params.lanes,\n outPtr,\n params.outlen,\n encodedPtr,\n encodedLen,\n );\n throwIfError(wasm, code);\n return readCString(wasm, encodedPtr);\n } catch (error) {\n if (isTrapError(error)) {\n resetWasmCache();\n }\n throw error;\n } finally {\n params.pwd.fill(0);\n params.salt.fill(0);\n params.secret.fill(0);\n params.ad.fill(0);\n freeAll(wasm, track);\n }\n}\n\nexport interface VerifyOptions {\n secret?: Uint8Array;\n associatedData?: Uint8Array;\n maxMemoryKib?: number;\n maxTimeCost?: number;\n maxParallelism?: number;\n}\n\nexport function isVerifyInputFailure(code: number): boolean {\n switch (code) {\n case -22:\n case -31:\n case -33:\n case -1:\n case -18:\n case -19:\n case -20:\n case -21:\n case -23:\n case -24:\n case -27:\n return false;\n default:\n return true;\n }\n}\n\nexport async function verify(\n encoded: string,\n password: PasswordInput,\n options: VerifyOptions = {},\n): Promise<boolean> {\n if (typeof encoded !== \"string\" || encoded.length > 1 << 20) {\n return false;\n }\n const maxMemoryKib = options.maxMemoryKib ?? MAX_MEMORY_KIB;\n const maxTimeCost = options.maxTimeCost ?? MAX_TIMECOST;\n const maxParallelism = options.maxParallelism ?? MAX_PARALLELISM;\n checkInt(\"maxMemoryKib\", maxMemoryKib, 0, 4294967295);\n checkInt(\"maxTimeCost\", maxTimeCost, 0, 4294967295);\n checkInt(\"maxParallelism\", maxParallelism, 0, 4294967295);\n try {\n const gate = parsePHC(encoded);\n if (\n gate.memoryCost > maxMemoryKib ||\n gate.timeCost > maxTimeCost ||\n gate.parallelism > maxParallelism\n ) {\n return false;\n }\n } catch {\n }\n const pwd = toBytes(password, \"password\", MAX_PASSWORD_BYTES);\n const secret = toOwnedOption(options.secret, \"secret\", MAX_SECRET_BYTES);\n const ad = toOwnedOption(\n options.associatedData,\n \"associatedData\",\n MAX_AD_BYTES,\n );\n const wasm = await getWasm();\n const track: Allocations = { ptrs: [] };\n const encodedBytes = new TextEncoder().encode(encoded);\n const encodedNul = new Uint8Array(encodedBytes.length + 1);\n encodedNul.set(encodedBytes, 0);\n encodedBytes.fill(0);\n try {\n const encodedPtr = allocCopy(wasm, encodedNul, track);\n const pwdPtr = allocCopy(wasm, pwd, track);\n const secretPtr = allocCopy(wasm, secret, track);\n const adPtr = allocCopy(wasm, ad, track);\n const code = wasm.argon2w_verify(\n encodedPtr,\n pwdPtr,\n pwd.length,\n secretPtr,\n secret.length,\n adPtr,\n ad.length,\n );\n if (!isVerifyInputFailure(code)) {\n throwIfError(wasm, code);\n }\n return code === 0;\n } catch (error) {\n if (isTrapError(error)) {\n resetWasmCache();\n }\n throw error;\n } finally {\n pwd.fill(0);\n secret.fill(0);\n ad.fill(0);\n encodedNul.fill(0);\n freeAll(wasm, track);\n }\n}\n\nexport interface ParsedPHC {\n type: string;\n version: number;\n memoryCost: number;\n timeCost: number;\n parallelism: number;\n}\n\nconst PHC_RE =\n /^\\$(argon2(?:d|i|id))\\$v=(\\d+)\\$m=(\\d+),t=(\\d+),p=(\\d+)\\$([^$]+)\\$([^$]+)$/;\n\nfunction parseDecimalU32(text: string | undefined, label: string): number {\n if (text === undefined || !/^(0|[1-9][0-9]*)$/.test(text)) {\n throw new Argon2wError(-32, `malformed PHC ${label}`);\n }\n if (text.length > 10) {\n throw new Argon2wError(-32, `malformed PHC ${label}`);\n }\n const value = Number(text);\n if (!Number.isSafeInteger(value) || value > 4294967295) {\n throw new Argon2wError(-32, `malformed PHC ${label}`);\n }\n return value;\n}\n\nexport function parsePHC(encoded: string): ParsedPHC {\n if (typeof encoded !== \"string\" || encoded.length > 1 << 20) {\n throw new Argon2wError(-32, \"malformed PHC string\");\n }\n const match = PHC_RE.exec(encoded);\n if (match === null) {\n throw new Argon2wError(-32, \"malformed PHC string\");\n }\n const type = match[1] ?? \"\";\n const version = parseDecimalU32(match[2], \"version\");\n const memoryCost = parseDecimalU32(match[3], \"memory cost\");\n const timeCost = parseDecimalU32(match[4], \"time cost\");\n const parallelism = parseDecimalU32(match[5], \"parallelism\");\n return { type, version, memoryCost, timeCost, parallelism };\n}\n\nexport interface Policy {\n timeCost?: number;\n memoryCost?: number;\n parallelism?: number;\n version?: number;\n}\n\nexport function needsRehash(encoded: string, policy: Policy): boolean {\n let parsed: ParsedPHC;\n try {\n parsed = parsePHC(encoded);\n } catch {\n return true;\n }\n if (parsed.type !== \"argon2id\" || parsed.version !== ARGON2_VERSION_13) {\n return true;\n }\n if (policy.version !== undefined && parsed.version !== policy.version) {\n return true;\n }\n if (\n policy.memoryCost !== undefined &&\n parsed.memoryCost !== policy.memoryCost\n ) {\n return true;\n }\n if (policy.timeCost !== undefined && parsed.timeCost !== policy.timeCost) {\n return true;\n }\n if (\n policy.parallelism !== undefined &&\n parsed.parallelism !== policy.parallelism\n ) {\n return true;\n }\n return false;\n}\n\nexport type RehashAssessment =\n | \"matches\"\n | \"below-target\"\n | \"above-target\"\n | \"different-parameters\"\n | \"unparseable\";\n\nexport function assessRehash(\n encoded: string,\n target: ProfileName | PasswordProfile,\n): RehashAssessment {\n const profile =\n typeof target === \"string\"\n ? Object.hasOwn(profiles, target)\n ? profiles[target as ProfileName]\n : undefined\n : createProfile(target);\n if (profile === undefined) {\n throw new Argon2wError(-30, \"unknown hash profile\");\n }\n let parsed: ParsedPHC;\n try {\n parsed = parsePHC(encoded);\n } catch {\n return \"unparseable\";\n }\n if (parsed.type !== \"argon2id\" || parsed.version !== ARGON2_VERSION_13) {\n return \"unparseable\";\n }\n const memory = parsed.memoryCost - profile.memoryCost;\n const time = parsed.timeCost - profile.timeCost;\n const lanes = parsed.parallelism - profile.parallelism;\n if (memory === 0 && time === 0 && lanes === 0) {\n return \"matches\";\n }\n if (memory >= 0 && time >= 0 && lanes >= 0) {\n return \"above-target\";\n }\n if (memory <= 0 && time <= 0 && lanes <= 0) {\n return \"below-target\";\n }\n return \"different-parameters\";\n}\n\nexport async function hashRaw(\n password: PasswordInput,\n options: HashOptions = {},\n): Promise<Uint8Array> {\n const params = resolveParams(password, options);\n const wasm = await getWasm();\n const track: Allocations = { ptrs: [] };\n try {\n const pwdPtr = allocCopy(wasm, params.pwd, track);\n const saltPtr = allocCopy(wasm, params.salt, track);\n const secretPtr = allocCopy(wasm, params.secret, track);\n const adPtr = allocCopy(wasm, params.ad, track);\n const outPtr = wasm.argon2w_alloc(params.outlen);\n if (outPtr === 0) {\n throw new Argon2wError(-22, \"wasm allocation failed\");\n }\n track.ptrs.push({ ptr: outPtr, size: params.outlen });\n const code = wasm.argon2w_hash_raw(\n ARGON2_TYPE_ID,\n ARGON2_VERSION_13,\n pwdPtr,\n params.pwd.length,\n saltPtr,\n params.salt.length,\n secretPtr,\n params.secret.length,\n adPtr,\n params.ad.length,\n params.tCost,\n params.mCost,\n params.lanes,\n outPtr,\n params.outlen,\n );\n throwIfError(wasm, code);\n const tag = memoryBytes(wasm).slice(outPtr, outPtr + params.outlen);\n return tag;\n } catch (error) {\n if (isTrapError(error)) {\n resetWasmCache();\n }\n throw error;\n } finally {\n params.pwd.fill(0);\n params.salt.fill(0);\n params.secret.fill(0);\n params.ad.fill(0);\n freeAll(wasm, track);\n }\n}\n"]}
|
package/dist/wasm.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface Argon2wExports {
|
|
2
|
+
memory: WebAssembly.Memory;
|
|
3
|
+
_initialize(): void;
|
|
4
|
+
argon2w_alloc(size: number): number;
|
|
5
|
+
argon2w_free(ptr: number, size: number): void;
|
|
6
|
+
argon2w_error_message(code: number): number;
|
|
7
|
+
argon2w_hash_raw(type: number, version: number, pwd: number, pwdlen: number, salt: number, saltlen: number, secret: number, secretlen: number, ad: number, adlen: number, tCost: number, mCost: number, lanes: number, out: number, outlen: number): number;
|
|
8
|
+
argon2w_encoded_len(tCost: number, mCost: number, lanes: number, saltlen: number, outlen: number): number;
|
|
9
|
+
argon2w_hash_encoded(type: number, version: number, pwd: number, pwdlen: number, salt: number, saltlen: number, secret: number, secretlen: number, ad: number, adlen: number, tCost: number, mCost: number, lanes: number, out: number, outlen: number, encoded: number, encodedlen: number): number;
|
|
10
|
+
argon2w_verify(encoded: number, pwd: number, pwdlen: number, secret: number, secretlen: number, ad: number, adlen: number): number;
|
|
11
|
+
}
|
|
12
|
+
export declare function toOwned(data: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
13
|
+
export declare function configureWasm(source: WebAssembly.Module | Uint8Array): void;
|
|
14
|
+
export declare function getWasm(): Promise<Argon2wExports>;
|
|
15
|
+
export declare function resetWasmCache(): void;
|
|
16
|
+
export declare function isTrapError(error: unknown): boolean;
|
|
17
|
+
export declare function memoryBytes(wasm: Argon2wExports): Uint8Array;
|
|
18
|
+
export declare function readCString(wasm: Argon2wExports, ptr: number, maxLength?: number): string;
|
package/dist/wasm.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
let configured = null;
|
|
10
|
+
let instancePromise = null;
|
|
11
|
+
export function toOwned(data) {
|
|
12
|
+
const out = new Uint8Array(data.length);
|
|
13
|
+
out.set(data);
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
export function configureWasm(source) {
|
|
17
|
+
if (source instanceof WebAssembly.Module) {
|
|
18
|
+
configured = { kind: "module", module: source };
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
if (!(source instanceof Uint8Array)) {
|
|
22
|
+
throw new TypeError("argon2w: configureWasm expects a WebAssembly.Module or a " +
|
|
23
|
+
"Uint8Array of Wasm bytes");
|
|
24
|
+
}
|
|
25
|
+
if (source.length === 0) {
|
|
26
|
+
throw new TypeError("argon2w: configureWasm received an empty Uint8Array");
|
|
27
|
+
}
|
|
28
|
+
configured = { kind: "bytes", bytes: toOwned(source) };
|
|
29
|
+
}
|
|
30
|
+
instancePromise = null;
|
|
31
|
+
void getWasm().catch(() => undefined);
|
|
32
|
+
}
|
|
33
|
+
async function resolveBytes() {
|
|
34
|
+
if (configured !== null && configured.kind === "bytes") {
|
|
35
|
+
return toOwned(configured.bytes);
|
|
36
|
+
}
|
|
37
|
+
const proc = globalThis
|
|
38
|
+
.process;
|
|
39
|
+
if (typeof proc?.versions?.node !== "string") {
|
|
40
|
+
throw new Error("argon2w: no Wasm source configured and the runtime cannot read " +
|
|
41
|
+
"argon2w.wasm from disk; call configureWasm(moduleOrBytes) " +
|
|
42
|
+
"explicitly (required on Cloudflare Workers: import the .wasm file and pass it).");
|
|
43
|
+
}
|
|
44
|
+
const fsSpecifier = "node:fs/promises";
|
|
45
|
+
const pathSpecifier = "node:path";
|
|
46
|
+
const urlSpecifier = "node:url";
|
|
47
|
+
const fs = (await import(__rewriteRelativeImportExtension(fsSpecifier)));
|
|
48
|
+
const path = (await import(__rewriteRelativeImportExtension(pathSpecifier)));
|
|
49
|
+
const url = (await import(__rewriteRelativeImportExtension(urlSpecifier)));
|
|
50
|
+
const here = path.dirname(url.fileURLToPath(import.meta.url));
|
|
51
|
+
const candidates = [
|
|
52
|
+
path.join(here, "argon2w.wasm"),
|
|
53
|
+
path.join(here, "..", "src", "argon2w.wasm"),
|
|
54
|
+
];
|
|
55
|
+
for (const file of candidates) {
|
|
56
|
+
try {
|
|
57
|
+
return toOwned(new Uint8Array(await fs.readFile(file)));
|
|
58
|
+
}
|
|
59
|
+
catch { }
|
|
60
|
+
}
|
|
61
|
+
throw new Error("argon2w: unable to locate argon2w.wasm; call configureWasm(moduleOrBytes) " +
|
|
62
|
+
"explicitly (required on Cloudflare Workers: import the .wasm file and pass it).");
|
|
63
|
+
}
|
|
64
|
+
function instantiate(module) {
|
|
65
|
+
const imports = {
|
|
66
|
+
env: {
|
|
67
|
+
emscripten_notify_memory_growth: () => { },
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
const instance = new WebAssembly.Instance(module, imports);
|
|
71
|
+
const exports = instance.exports;
|
|
72
|
+
if (typeof exports._initialize === "function") {
|
|
73
|
+
exports._initialize();
|
|
74
|
+
}
|
|
75
|
+
return exports;
|
|
76
|
+
}
|
|
77
|
+
export async function getWasm() {
|
|
78
|
+
if (instancePromise === null) {
|
|
79
|
+
const pending = (async () => {
|
|
80
|
+
if (configured !== null && configured.kind === "module") {
|
|
81
|
+
return instantiate(configured.module);
|
|
82
|
+
}
|
|
83
|
+
const bytes = await resolveBytes();
|
|
84
|
+
const compiled = await WebAssembly.compile(bytes);
|
|
85
|
+
return instantiate(compiled);
|
|
86
|
+
})();
|
|
87
|
+
void pending.catch(() => {
|
|
88
|
+
if (instancePromise === pending) {
|
|
89
|
+
instancePromise = null;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
instancePromise = pending;
|
|
93
|
+
}
|
|
94
|
+
return instancePromise;
|
|
95
|
+
}
|
|
96
|
+
export function resetWasmCache() {
|
|
97
|
+
instancePromise = null;
|
|
98
|
+
}
|
|
99
|
+
export function isTrapError(error) {
|
|
100
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
101
|
+
return /unreachable|memory access out of bounds|table index is out of bounds|detached/i.test(message);
|
|
102
|
+
}
|
|
103
|
+
export function memoryBytes(wasm) {
|
|
104
|
+
return new Uint8Array(wasm.memory.buffer);
|
|
105
|
+
}
|
|
106
|
+
export function readCString(wasm, ptr, maxLength = 1 << 20) {
|
|
107
|
+
const mem = memoryBytes(wasm);
|
|
108
|
+
if (!Number.isInteger(ptr) || ptr < 0 || ptr >= mem.length) {
|
|
109
|
+
throw new RangeError(`argon2w: CString pointer ${ptr} out of range`);
|
|
110
|
+
}
|
|
111
|
+
if (!Number.isInteger(maxLength) || maxLength < 0) {
|
|
112
|
+
throw new RangeError(`argon2w: invalid CString length ${maxLength}`);
|
|
113
|
+
}
|
|
114
|
+
const limit = Math.min(mem.length, ptr + maxLength);
|
|
115
|
+
let end = ptr;
|
|
116
|
+
while (end < limit && mem[end] !== 0) {
|
|
117
|
+
end += 1;
|
|
118
|
+
}
|
|
119
|
+
if (end === limit) {
|
|
120
|
+
throw new RangeError(`argon2w: unterminated CString at ${ptr}`);
|
|
121
|
+
}
|
|
122
|
+
return new TextDecoder().decode(mem.slice(ptr, end));
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=wasm.js.map
|
package/dist/wasm.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasm.js","sourceRoot":"","sources":["../src/wasm.ts"],"names":[],"mappings":"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","sourcesContent":["export interface Argon2wExports {\n memory: WebAssembly.Memory;\n _initialize(): void;\n argon2w_alloc(size: number): number;\n argon2w_free(ptr: number, size: number): void;\n argon2w_error_message(code: number): number;\n argon2w_hash_raw(\n type: number,\n version: number,\n pwd: number,\n pwdlen: number,\n salt: number,\n saltlen: number,\n secret: number,\n secretlen: number,\n ad: number,\n adlen: number,\n tCost: number,\n mCost: number,\n lanes: number,\n out: number,\n outlen: number,\n ): number;\n argon2w_encoded_len(\n tCost: number,\n mCost: number,\n lanes: number,\n saltlen: number,\n outlen: number,\n ): number;\n argon2w_hash_encoded(\n type: number,\n version: number,\n pwd: number,\n pwdlen: number,\n salt: number,\n saltlen: number,\n secret: number,\n secretlen: number,\n ad: number,\n adlen: number,\n tCost: number,\n mCost: number,\n lanes: number,\n out: number,\n outlen: number,\n encoded: number,\n encodedlen: number,\n ): number;\n argon2w_verify(\n encoded: number,\n pwd: number,\n pwdlen: number,\n secret: number,\n secretlen: number,\n ad: number,\n adlen: number,\n ): number;\n}\n\nlet configured:\n | { kind: \"module\"; module: WebAssembly.Module }\n | { kind: \"bytes\"; bytes: Uint8Array }\n | null = null;\nlet instancePromise: Promise<Argon2wExports> | null = null;\n\nexport function toOwned(data: Uint8Array): Uint8Array<ArrayBuffer> {\n const out = new Uint8Array(data.length);\n out.set(data);\n return out;\n}\n\nexport function configureWasm(source: WebAssembly.Module | Uint8Array): void {\n if (source instanceof WebAssembly.Module) {\n configured = { kind: \"module\", module: source };\n } else {\n if (!(source instanceof Uint8Array)) {\n throw new TypeError(\n \"argon2w: configureWasm expects a WebAssembly.Module or a \" +\n \"Uint8Array of Wasm bytes\",\n );\n }\n if (source.length === 0) {\n throw new TypeError(\"argon2w: configureWasm received an empty Uint8Array\");\n }\n configured = { kind: \"bytes\", bytes: toOwned(source) };\n }\n instancePromise = null;\n void getWasm().catch(() => undefined);\n}\n\nasync function resolveBytes(): Promise<Uint8Array<ArrayBuffer>> {\n if (configured !== null && configured.kind === \"bytes\") {\n return toOwned(configured.bytes);\n }\n const proc = (globalThis as { process?: { versions?: { node?: unknown } } })\n .process;\n if (typeof proc?.versions?.node !== \"string\") {\n throw new Error(\n \"argon2w: no Wasm source configured and the runtime cannot read \" +\n \"argon2w.wasm from disk; call configureWasm(moduleOrBytes) \" +\n \"explicitly (required on Cloudflare Workers: import the .wasm file and pass it).\",\n );\n }\n const fsSpecifier = \"node:fs/promises\";\n const pathSpecifier = \"node:path\";\n const urlSpecifier = \"node:url\";\n const fs = (await import(fsSpecifier)) as {\n readFile(path: string): Promise<Uint8Array>;\n };\n const path = (await import(pathSpecifier)) as {\n dirname(path: string): string;\n join(...parts: string[]): string;\n };\n const url = (await import(urlSpecifier)) as {\n fileURLToPath(url: string | URL): string;\n };\n const here = path.dirname(url.fileURLToPath(import.meta.url));\n const candidates = [\n path.join(here, \"argon2w.wasm\"),\n path.join(here, \"..\", \"src\", \"argon2w.wasm\"),\n ];\n for (const file of candidates) {\n try {\n return toOwned(new Uint8Array(await fs.readFile(file)));\n } catch {}\n }\n throw new Error(\n \"argon2w: unable to locate argon2w.wasm; call configureWasm(moduleOrBytes) \" +\n \"explicitly (required on Cloudflare Workers: import the .wasm file and pass it).\",\n );\n}\n\nfunction instantiate(\n module: WebAssembly.Module,\n): Argon2wExports {\n const imports = {\n env: {\n emscripten_notify_memory_growth: () => {},\n },\n };\n const instance = new WebAssembly.Instance(module, imports);\n const exports = instance.exports as unknown as Argon2wExports;\n if (typeof exports._initialize === \"function\") {\n exports._initialize();\n }\n return exports;\n}\n\nexport async function getWasm(): Promise<Argon2wExports> {\n if (instancePromise === null) {\n const pending = (async () => {\n if (configured !== null && configured.kind === \"module\") {\n return instantiate(configured.module);\n }\n const bytes = await resolveBytes();\n const compiled = await WebAssembly.compile(bytes);\n return instantiate(compiled);\n })();\n void pending.catch(() => {\n if (instancePromise === pending) {\n instancePromise = null;\n }\n });\n instancePromise = pending;\n }\n return instancePromise;\n}\n\nexport function resetWasmCache(): void {\n instancePromise = null;\n}\n\nexport function isTrapError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return /unreachable|memory access out of bounds|table index is out of bounds|detached/i.test(\n message,\n );\n}\n\nexport function memoryBytes(wasm: Argon2wExports): Uint8Array {\n return new Uint8Array(wasm.memory.buffer);\n}\n\nexport function readCString(\n wasm: Argon2wExports,\n ptr: number,\n maxLength: number = 1 << 20,\n): string {\n const mem = memoryBytes(wasm);\n if (!Number.isInteger(ptr) || ptr < 0 || ptr >= mem.length) {\n throw new RangeError(`argon2w: CString pointer ${ptr} out of range`);\n }\n if (!Number.isInteger(maxLength) || maxLength < 0) {\n throw new RangeError(`argon2w: invalid CString length ${maxLength}`);\n }\n const limit = Math.min(mem.length, ptr + maxLength);\n let end = ptr;\n while (end < limit && mem[end] !== 0) {\n end += 1;\n }\n if (end === limit) {\n throw new RangeError(`argon2w: unterminated CString at ${ptr}`);\n }\n return new TextDecoder().decode(mem.slice(ptr, end));\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hallaxius/argon2w",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Argon2id for Cloudflare Workers: official P-H-C implementation compiled to SIMD Wasm, serial lanes, explicit cost parameters.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json",
|
|
14
|
+
"./dist/argon2w.wasm": "./dist/argon2w.wasm"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.build.json && bun scripts/copy-wasm.ts",
|
|
23
|
+
"prepack": "bun run build",
|
|
24
|
+
"test": "bun test",
|
|
25
|
+
"typecheck": "tsc --noEmit"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"argon2",
|
|
29
|
+
"argon2id",
|
|
30
|
+
"password-hashing",
|
|
31
|
+
"cloudflare-workers",
|
|
32
|
+
"workerd",
|
|
33
|
+
"wasm"
|
|
34
|
+
],
|
|
35
|
+
"license": "Apache-2.0",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/Hallaxius/argon2w.git"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/Hallaxius/argon2w#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/Hallaxius/argon2w/issues"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=24"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/bun": "1.4.2",
|
|
52
|
+
"typescript": "7.0.2"
|
|
53
|
+
}
|
|
54
|
+
}
|