Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
## [2.1.1](https://github.com/filipo11021/nodejs-password-hashing/compare/v2.1.0...v2.1.1) (2026-01-26)


### Bug Fixes

* **#26:** downgrade @types/node to v24 and lock in dependabot ([#37](https://github.com/filipo11021/nodejs-password-hashing/issues/37)) ([dcfd6d7](https://github.com/filipo11021/nodejs-password-hashing/commit/dcfd6d77ab1c0e72cacbee17599154108101a3cc)), closes [#26](https://github.com/filipo11021/nodejs-password-hashing/issues/26) [#26](https://github.com/filipo11021/nodejs-password-hashing/issues/26)
- **#26:** downgrade @types/node to v24 and lock in dependabot ([#37](https://github.com/filipo11021/nodejs-password-hashing/issues/37)) ([dcfd6d7](https://github.com/filipo11021/nodejs-password-hashing/commit/dcfd6d77ab1c0e72cacbee17599154108101a3cc)), closes [#26](https://github.com/filipo11021/nodejs-password-hashing/issues/26) [#26](https://github.com/filipo11021/nodejs-password-hashing/issues/26)

# [2.1.0](https://github.com/filipo11021/nodejs-password-hashing/compare/v2.0.0...v2.1.0) (2026-01-23)

Expand Down
149 changes: 149 additions & 0 deletions src/argon2/argon2-validation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { createArgon2Hashing } from "./argon2.ts";
import assert from "node:assert/strict";
import { describe, it } from "node:test";

void describe("Argon2 Parameter Validation - RFC 9106 Compliance", () => {
void describe("parallelism parameter", () => {
void it("should accept parallelism = 1 (minimum per RFC 9106)", () => {
assert.doesNotThrow(() => {
createArgon2Hashing({
parallelism: 1,
memory: 8,
});
}, "parallelism = 1 should be valid per RFC 9106");
});

void it("should reject parallelism = 0 (below minimum)", () => {
assert.throws(
() => {
createArgon2Hashing({
parallelism: 0,
memory: 8,
});
},
{
name: "ZodError",
},
"parallelism must be at least 1",
);
});
});

void describe("tagLength parameter", () => {
void it("should accept tagLength = 4 (minimum per RFC 9106)", () => {
assert.doesNotThrow(() => {
createArgon2Hashing({
tagLength: 4,
});
}, "tagLength = 4 should be valid per RFC 9106");
});

void it("should reject tagLength = 3 (below minimum)", () => {
assert.throws(
() => {
createArgon2Hashing({
tagLength: 3,
});
},
{
name: "ZodError",
},
"tagLength must be at least 4",
);
});
});

void describe("memory parameter relative to parallelism", () => {
void it("should accept memory = 8 * parallelism (minimum per RFC 9106)", () => {
assert.doesNotThrow(() => {
createArgon2Hashing({
parallelism: 2,
memory: 16, // Exactly 8 * 2
});
}, "memory = 8 * parallelism should be valid per RFC 9106");
});

void it("should reject memory < 8 * parallelism (below minimum)", () => {
assert.throws(
() => {
createArgon2Hashing({
parallelism: 2,
memory: 15, // Less than 8 * 2
});
},
{
name: "ZodError",
},
"memory must be at least 8 * parallelism",
);
});
});

void describe("passes parameter", () => {
void it("should accept passes = 1 (minimum per RFC 9106)", () => {
assert.doesNotThrow(() => {
createArgon2Hashing({
passes: 1,
});
}, "passes = 1 should be valid per RFC 9106");
});

void it("should reject passes = 0 (below minimum)", () => {
assert.throws(
() => {
createArgon2Hashing({
passes: 0,
});
},
{
name: "ZodError",
},
"passes must be at least 1",
);
});
});

void describe("edge cases - absolute minimums", () => {
void it("should accept absolute minimum configuration (parallelism=1, memory=8)", () => {
assert.doesNotThrow(() => {
createArgon2Hashing({
parallelism: 1,
memory: 8, // Exactly 8 * 1
passes: 1,
tagLength: 4,
});
}, "absolute minimum configuration should be valid per RFC 9106");
});

void it("should reject memory = 7 when parallelism = 1", () => {
assert.throws(
() => {
createArgon2Hashing({
parallelism: 1,
memory: 7,
});
},
{
name: "ZodError",
},
"memory = 7 should be rejected when parallelism = 1",
);
});
});

void describe("edge cases - invalid values", () => {
void it("should reject negative values", () => {
assert.throws(
() => {
createArgon2Hashing({
passes: -1,
});
},
{
name: "ZodError",
},
"passes must be positive",
);
});
});
});
5 changes: 3 additions & 2 deletions src/argon2/argon2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { MAX_UINT24, MAX_UINT32 } from "../utils/numbers.ts";
const optionsSchema = z
.object({
memory: z.number().max(MAX_UINT32),
passes: z.number().min(2).max(MAX_UINT32),
passes: z.number().min(1).max(MAX_UINT32),
parallelism: z.number().min(1).max(MAX_UINT24),
tagLength: z.number().min(4).max(MAX_UINT32),
saltLength: z.number().min(16).max(1024),
Expand All @@ -23,7 +23,8 @@ const optionsSchema = z
return params.memory >= 8 * params.parallelism;
},
{
message: "memory parameter must be at least 8 * parallelism",
message:
"memory parameter must be greater than or equal to 8 * parallelism",
},
)
.readonly();
Expand Down