Skip to content

Commit 52c4553

Browse files
authored
fix!(argon2): respect the salt provided in hash options (#899)
1 parent fea946f commit 52c4553

File tree

13 files changed

+98
-73
lines changed

13 files changed

+98
-73
lines changed

depracted/deno-lint/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
"typanion": "^3.14.0"
7474
},
7575
"devDependencies": {
76-
"@napi-rs/cli": "^3.0.0-alpha.54",
76+
"@napi-rs/cli": "^3.0.0-alpha.63",
7777
"@types/webpack": "^5.28.5"
7878
},
7979
"funding": {

packages/argon2/README.md

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,6 @@ It has a simple design aimed at the highest memory filling rate and effective us
2727
Hybrid that mixes Argon2i and Argon2d passes.
2828
Uses the Argon2i approach for the first half pass over memory and Argon2d approach for subsequent passes. This effectively places it in the “middle” between the other two: it doesn’t provide as good TMTO/GPU cracking resistance as Argon2d, nor as good of side-channel resistance as Argon2i, but overall provides the most well-rounded approach to both classes of attacks.
2929

30-
## Support matrix
31-
32-
| | node12 | node14 | node16 | node18 |
33-
| ------------------- | ------ | ------ | ------ | ------ |
34-
| Windows x64 |||||
35-
| Windows x32 |||||
36-
| Windows arm64 |||||
37-
| macOS x64 |||||
38-
| macOS arm64(m chip) |||||
39-
| Linux x64 gnu |||||
40-
| Linux x64 musl |||||
41-
| Linux arm gnu |||||
42-
| Linux arm64 gnu |||||
43-
| Linux arm64 musl |||||
44-
| Android arm64 |||||
45-
| Android armv7 |||||
46-
| FreeBSD x64 |||||
47-
4830
# Benchmarks
4931

5032
See [benchmark/](benchmark/argon2.js).

packages/argon2/__test__/argon2.spec.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { randomBytes } from 'crypto'
1+
import { randomBytes } from 'node:crypto'
22

33
import test from 'ava'
44

@@ -43,6 +43,30 @@ test('should be able to hash string', async (t) => {
4343
)
4444
})
4545

46+
test('should be able to hash string with a defined salt', async (t) => {
47+
await t.notThrowsAsync(() =>
48+
hash('whatever', {
49+
salt: randomBytes(32),
50+
}),
51+
)
52+
await t.notThrowsAsync(() =>
53+
hash('whatever', {
54+
secret: randomBytes(32),
55+
salt: randomBytes(32),
56+
}),
57+
)
58+
59+
const salt = randomBytes(32)
60+
t.is(
61+
await hash('whatever', {
62+
salt,
63+
}),
64+
await hash('whatever', {
65+
salt,
66+
}),
67+
)
68+
})
69+
4670
test('should be able to hashRaw string with a defined salt', async (t) => {
4771
await t.notThrowsAsync(() => hash('whatever'))
4872
await t.notThrowsAsync(() =>
Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,38 @@
1-
const { cpus } = require('os')
1+
import { cpus } from 'node:os'
22

3-
const nodeArgon2 = require('argon2')
4-
const { Suite } = require('benchmark')
5-
const chalk = require('chalk')
3+
import nodeArgon2 from 'argon2'
4+
import { Bench } from 'tinybench'
65

7-
const { hash, verify, Algorithm } = require('../index')
6+
import { hash, verify, Algorithm } from '../index.js'
87

98
const PASSWORD = '$v=19$m=4096,t=3,p=1$fyLYvmzgpBjDTP6QSypj3g$pb1Q3Urv1amxuFft0rGwKfEuZPhURRDV7TJqcBnwlGo'
109
const CORES = cpus().length
1110

12-
const suite = new Suite('Hash with all cores')
13-
14-
suite
15-
.add(
16-
'@node-rs/argon',
17-
async (deferred) => {
18-
await hash(PASSWORD, {
19-
algorithm: Algorithm.Argon2id,
20-
parallelism: CORES,
21-
})
22-
deferred.resolve()
23-
},
24-
{ defer: true },
25-
)
26-
.add(
27-
'node-argon',
28-
async (deferred) => {
29-
await nodeArgon2.hash(PASSWORD, { type: nodeArgon2.argon2id, parallelism: CORES })
30-
deferred.resolve()
31-
},
32-
{
33-
defer: true,
34-
},
35-
)
36-
.on('cycle', function (event) {
37-
console.info(String(event.target))
11+
const HASHED = await hash(PASSWORD, {
12+
algorithm: Algorithm.Argon2id,
13+
parallelism: CORES,
14+
})
15+
16+
const bench = new Bench('Hash with all cores')
17+
18+
bench
19+
.add('@node-rs/argon hash', async () => {
20+
await hash(PASSWORD, {
21+
algorithm: Algorithm.Argon2id,
22+
parallelism: CORES,
23+
})
24+
})
25+
.add('node-argon hash', async () => {
26+
await nodeArgon2.hash(PASSWORD, { type: nodeArgon2.argon2id, parallelism: CORES })
3827
})
39-
.on('complete', function () {
40-
console.info(`${this.name} bench suite: Fastest is ${chalk.green(this.filter('fastest').map('name'))}`)
28+
.add('@node-rs/argon verify', async () => {
29+
console.assert(await verify(HASHED, PASSWORD))
4130
})
42-
.run()
31+
.add('node-argon verify', async () => {
32+
console.assert(await nodeArgon2.verify(HASHED, PASSWORD))
33+
})
34+
35+
await bench.warmup()
36+
await bench.run()
37+
38+
console.table(bench.table())
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}

packages/argon2/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@
6262
"version": "napi version && git add npm"
6363
},
6464
"devDependencies": {
65-
"@napi-rs/cli": "^3.0.0-alpha.54",
65+
"@napi-rs/cli": "^3.0.0-alpha.63",
6666
"argon2": "^0.41.0",
67-
"cross-env": "^7.0.3"
67+
"cross-env": "^7.0.3",
68+
"tinybench": "^2.9.0"
6869
}
6970
}

packages/argon2/src/lib.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,18 @@ impl Task for HashTask {
125125
type JsValue = String;
126126

127127
fn compute(&mut self) -> Result<Self::Output> {
128-
let salt = SaltString::generate(&mut OsRng);
128+
let salt = if let Some(salt) = &self.options.salt {
129+
SaltString::encode_b64(salt)
130+
.map_err(|err| Error::new(Status::InvalidArg, format!("{err}")))?
131+
} else {
132+
SaltString::generate(&mut OsRng)
133+
};
134+
let hasher = self
135+
.options
136+
.to_argon()
137+
.map_err(|err| Error::new(Status::InvalidArg, format!("{err}")))?;
129138

130-
let hasher = self.options.to_argon();
131139
hasher
132-
.map_err(|err| Error::new(Status::InvalidArg, format!("{err}")))?
133140
.hash_password(self.password.as_slice(), &salt)
134141
.map_err(|err| Error::new(Status::GenericFailure, format!("{err}")))
135142
.map(|h| h.to_string())
@@ -263,8 +270,12 @@ impl Task for VerifyTask {
263270
type JsValue = bool;
264271

265272
fn compute(&mut self) -> Result<Self::Output> {
266-
let parsed_hash = argon2::PasswordHash::new(self.hashed.as_str())
267-
.map_err(|err| Error::new(Status::InvalidArg, format!("{err}")))?;
273+
let parsed_hash = argon2::PasswordHash::new(self.hashed.as_str()).map_err(|err| {
274+
Error::new(
275+
Status::InvalidArg,
276+
format!("Invalid hashed password: {err}"),
277+
)
278+
})?;
268279
let argon2 = self.options.to_argon();
269280
Ok(
270281
argon2

packages/bcrypt/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"url": "https://github.com/napi-rs/node-rs/issues"
7171
},
7272
"devDependencies": {
73-
"@napi-rs/cli": "^3.0.0-alpha.54",
73+
"@napi-rs/cli": "^3.0.0-alpha.63",
7474
"@types/bcrypt": "^5.0.2",
7575
"bcrypt": "^5.1.1",
7676
"bcryptjs": "^2.4.3",

packages/crc32/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"url": "https://github.com/napi-rs/node-rs/issues"
6565
},
6666
"devDependencies": {
67-
"@napi-rs/cli": "^3.0.0-alpha.54",
67+
"@napi-rs/cli": "^3.0.0-alpha.63",
6868
"@types/crc": "^3.8.3",
6969
"buffer": "^6.0.3",
7070
"crc": "^4.3.2",

packages/jieba/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"url": "https://github.com/napi-rs/node-rs/issues"
6565
},
6666
"devDependencies": {
67-
"@napi-rs/cli": "^3.0.0-alpha.54",
67+
"@napi-rs/cli": "^3.0.0-alpha.63",
6868
"nodejieba": "^3.0.0"
6969
},
7070
"funding": {

0 commit comments

Comments
 (0)