Skip to content

Commit ca0c191

Browse files
feat(argon2): support salt input on Argon2 (#660)
* Support salt input on Argon2 Signed-off-by: Corentin Mors <[email protected]> * Support salt input on Argon2 - try 2 Signed-off-by: Corentin Mors <[email protected]> * Avoid generate salt if it's provided --------- Signed-off-by: Corentin Mors <[email protected]> Co-authored-by: LongYinan <[email protected]>
1 parent 3d9df7e commit ca0c191

File tree

3 files changed

+30
-9
lines changed

3 files changed

+30
-9
lines changed

packages/argon2/__test__/argon2.spec.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { randomBytes } from 'crypto'
22

33
import test from 'ava'
44

5-
import { Algorithm, hash, verify, Version } from '../index.js'
5+
import { Algorithm, hash, hashRaw, verify, Version } from '../index.js'
66

77
const passwordString = 'some_string123'
88
const passwordBuffer = Buffer.from(passwordString)
@@ -43,6 +43,16 @@ test('should be able to hash string', async (t) => {
4343
)
4444
})
4545

46+
test('should be able to hashRaw string with a defined salt', async (t) => {
47+
await t.notThrowsAsync(() => hash('whatever'))
48+
await t.notThrowsAsync(() =>
49+
hashRaw('whatever', {
50+
secret: randomBytes(32),
51+
salt: randomBytes(32),
52+
}),
53+
)
54+
})
55+
4656
test('should be able to verify hashed string', async (t) => {
4757
const PASSWORD = 'Argon2_is_the_best_algorithm_ever'
4858
t.true(await verify(await hash(PASSWORD), PASSWORD))
@@ -88,7 +98,7 @@ test('should return memoryCost error', async (t) => {
8898
}),
8999
)
90100

91-
t.is(error.message, 'memory cost is too small')
101+
t.is(error?.message, 'memory cost is too small')
92102
})
93103

94104
test('should return timeCost error', async (t) => {
@@ -98,7 +108,7 @@ test('should return timeCost error', async (t) => {
98108
}),
99109
)
100110

101-
t.is(error.message, 'time cost is too small')
111+
t.is(error?.message, 'time cost is too small')
102112
})
103113

104114
test('should return parallelism error', async (t) => {
@@ -109,5 +119,5 @@ test('should return parallelism error', async (t) => {
109119
}),
110120
)
111121

112-
t.is(error.message, 'not enough threads')
122+
t.is(error?.message, 'not enough threads')
113123
})

packages/argon2/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export interface Options {
6464
algorithm?: Algorithm
6565
version?: Version
6666
secret?: Buffer
67+
salt?: Buffer
6768
}
6869
export function hash(
6970
password: string | Buffer,

packages/argon2/src/lib.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub struct Options {
8989
pub algorithm: Option<Algorithm>,
9090
pub version: Option<Version>,
9191
pub secret: Option<Buffer>,
92+
pub salt: Option<Buffer>,
9293
}
9394

9495
impl Options {
@@ -122,6 +123,7 @@ impl Task for HashTask {
122123

123124
fn compute(&mut self) -> Result<Self::Output> {
124125
let salt = SaltString::generate(&mut OsRng);
126+
125127
let hasher = self.options.to_argon();
126128
hasher
127129
.map_err(|err| Error::new(Status::InvalidArg, format!("{err}")))?
@@ -181,7 +183,6 @@ impl Task for RawHashTask {
181183
type JsValue = Buffer;
182184

183185
fn compute(&mut self) -> Result<Self::Output> {
184-
let salt = SaltString::generate(&mut OsRng);
185186
let hasher = self
186187
.options
187188
.to_argon()
@@ -192,10 +193,19 @@ impl Task for RawHashTask {
192193
.unwrap_or(Params::DEFAULT_OUTPUT_LEN);
193194
let mut output = vec![0; output_len];
194195

195-
hasher
196-
.hash_password_into(self.password.as_slice(), salt.as_bytes(), &mut output)
197-
.map_err(|err| Error::new(Status::GenericFailure, format!("{err}")))
198-
.map(|_| output)
196+
match &self.options.salt {
197+
Some(buf) => hasher.hash_password_into(self.password.as_slice(), buf.as_ref(), &mut output),
198+
None => {
199+
let generated_salt = SaltString::generate(&mut OsRng);
200+
hasher.hash_password_into(
201+
self.password.as_slice(),
202+
generated_salt.as_bytes(),
203+
&mut output,
204+
)
205+
}
206+
}
207+
.map_err(|err| Error::new(Status::GenericFailure, format!("{err}")))
208+
.map(|_| output)
199209
}
200210

201211
fn resolve(&mut self, _env: Env, output: Self::Output) -> Result<Self::JsValue> {

0 commit comments

Comments
 (0)