Skip to content

Commit 7ce38a6

Browse files
authored
Merge pull request #11 from halvardssm/fix/crypto-hash-improved-throws
fix(crypto/hash): Improved throw messages
2 parents ddf5d4b + 9391922 commit 7ce38a6

File tree

11 files changed

+5439
-5284
lines changed

11 files changed

+5439
-5284
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ console.log(dump(buffer));
4444

4545
## Packages
4646

47+
- [assert](https://jsr.io/@stdext/assert): The assert package, contains
48+
validators and assertions
4749
- [crypto](https://jsr.io/@stdext/crypto): The crypto package contains utility
4850
for crypto and hashing
4951
- [encoding](https://jsr.io/@stdext/encoding): The encoding package contains

_wasm/crypto_hash_argon2/src/lib.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ extern "C" {
6969

7070
fn get_parsed_options(i: Argon2Options) -> (argon2::Algorithm, argon2::Params) {
7171
let parsed_options: WasmArgon2OptionsIncoming =
72-
serde_wasm_bindgen::from_value(i.into()).unwrap_throw();
72+
serde_wasm_bindgen::from_value(i.into())
73+
.expect_throw("Options could not be parsed");
7374

7475
let algorithm = match parsed_options
7576
.algorithm
@@ -94,34 +95,40 @@ fn get_parsed_options(i: Argon2Options) -> (argon2::Algorithm, argon2::Params) {
9495
.unwrap_or(default_params.p_cost()),
9596
parsed_options.output_length,
9697
)
97-
.expect_throw("failed to create params");
98+
.expect_throw("Failed to parse parameters");
9899

99100
(algorithm, params)
100101
}
101102

102103
/// Hash a password using Argon2
103104
#[wasm_bindgen]
104-
pub fn hash(data: String, options: Argon2Options) -> String {
105+
pub fn hash(data: String, options: Argon2Options) -> Result<String, JsError> {
105106
let (algorithm, parsed_options) = get_parsed_options(options);
106107
let argon2 = Argon2::new(algorithm, Version::V0x13, parsed_options.clone());
107108
let salt = SaltString::generate(&mut OsRng);
108109
let data_bytes = data.as_bytes();
109-
argon2
110+
let hash = argon2
110111
.hash_password(data_bytes, &salt)
111-
.expect("hashing failed")
112-
.to_string()
112+
.expect_throw("Failed to generate hash")
113+
.to_string();
114+
Ok(hash)
113115
}
114116

115117
/// Verify a password using Argon2
116118
#[wasm_bindgen]
117-
pub fn verify(data: String, hash: String, options: Argon2Options) -> bool {
119+
pub fn verify(
120+
data: String,
121+
hash: String,
122+
options: Argon2Options,
123+
) -> Result<bool, JsError> {
118124
let (algorithm, parsed_options) = get_parsed_options(options);
119125

120126
let data_bytes = data.as_bytes();
121-
let parsed_hash = PasswordHash::new(&hash).expect("failed to parse hash");
122-
let argon2 = Argon2::new(algorithm, Version::V0x13, parsed_options.clone())
127+
let parsed_hash = PasswordHash::new(&hash)
128+
.expect_throw("Failed to parse hash, invalid hash provided");
129+
let is_ok = Argon2::new(algorithm, Version::V0x13, parsed_options.clone())
123130
.verify_password(data_bytes, &parsed_hash)
124131
.is_ok();
125132

126-
argon2
133+
Ok(is_ok)
127134
}

_wasm/crypto_hash_bcrypt/src/lib.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,28 @@ pub struct WasmBcryptOptionsIncoming {
3030

3131
fn get_parsed_options(i: BcryptOptions) -> u32 {
3232
let parsed_options: WasmBcryptOptionsIncoming =
33-
serde_wasm_bindgen::from_value(i.into()).unwrap_throw();
33+
serde_wasm_bindgen::from_value(i.into())
34+
.expect_throw("Options could not be parsed");
3435
parsed_options.cost.unwrap_or(DEFAULT_COST)
3536
}
3637

3738
/// Hash a password using Bcrypt
3839
#[wasm_bindgen]
39-
pub fn hash(password: String, options: BcryptOptions) -> String {
40+
pub fn hash(
41+
password: String,
42+
options: BcryptOptions,
43+
) -> Result<String, JsError> {
4044
let cost = get_parsed_options(options);
41-
bcrypt_hash(password, cost).expect_throw("failed to hash password")
45+
Ok(bcrypt_hash(password, cost).expect_throw("Failed to generate hash"))
4246
}
4347

4448
/// Verify a password using Bcrypt
4549
#[wasm_bindgen]
46-
pub fn verify(password: String, hash: String, options: BcryptOptions) -> bool {
47-
bcrypt_verify(password, &hash.as_str())
48-
.expect_throw("failed to verify password")
50+
pub fn verify(
51+
password: String,
52+
hash: String,
53+
options: BcryptOptions,
54+
) -> Result<bool, JsError> {
55+
let is_ok = bcrypt_verify(password, &hash.as_str()).is_ok();
56+
Ok(is_ok)
4957
}

_wasm/crypto_hash_scrypt/src/lib.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,33 +76,40 @@ extern "C" {
7676

7777
fn get_parsed_options(i: ScryptOptions) -> Params {
7878
let parsed_options: WasmScryptOptionsRaw =
79-
serde_wasm_bindgen::from_value(i.into()).unwrap_throw();
79+
serde_wasm_bindgen::from_value(i.into())
80+
.expect_throw("Options could not be parsed");
8081

8182
Params::new(
8283
parsed_options.log_n.unwrap_or(Params::RECOMMENDED_LOG_N),
8384
parsed_options.block_size.unwrap_or(Params::RECOMMENDED_R),
8485
parsed_options.parallelism.unwrap_or(Params::RECOMMENDED_P),
8586
parsed_options.key_lenght.unwrap_or(Params::RECOMMENDED_LEN),
8687
)
87-
.expect("invalid parameters")
88+
.expect_throw("Failed to parse parameters")
8889
}
8990

9091
/// Hash a password using Scrypt
9192
#[wasm_bindgen]
92-
pub fn hash(data: String, options: ScryptOptions) -> String {
93+
pub fn hash(data: String, options: ScryptOptions) -> Result<String, JsError> {
9394
let parsed_options = get_parsed_options(options);
9495
let data_bytes = data.as_bytes();
9596
let salt = SaltString::generate(&mut OsRng);
9697
let hasher = Scrypt
9798
.hash_password_customized(data_bytes, None, None, parsed_options, &salt)
98-
.expect_throw("failed to hash password");
99-
hasher.to_string()
99+
.expect_throw("Failed to generate hash");
100+
Ok(hasher.to_string())
100101
}
101102

102103
/// Verify a password using Scrypt
103104
#[wasm_bindgen]
104-
pub fn verify(data: String, hash: String, _options: ScryptOptions) -> bool {
105+
pub fn verify(
106+
data: String,
107+
hash: String,
108+
_options: ScryptOptions,
109+
) -> Result<bool, JsError> {
105110
let data_bytes = data.as_bytes();
106-
let parsed_hash = PasswordHash::new(&hash).expect("failed to parse hash");
107-
Scrypt.verify_password(data_bytes, &parsed_hash).is_ok()
111+
let parsed_hash = PasswordHash::new(&hash)
112+
.expect_throw("Failed to parse hash, invalid hash provided");
113+
let is_ok = Scrypt.verify_password(data_bytes, &parsed_hash).is_ok();
114+
Ok(is_ok)
108115
}

crypto/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ hashing.
1111

1212
The hash module contains helpers and implementations for password hashing.
1313

14+
> The hash methods are written in Rust and compiled to WASM.
15+
1416
The following algorithms are provided:
1517

1618
- Argon2
@@ -21,6 +23,20 @@ The following algorithms are provided:
2123
import { hash, verify } from "@stdext/crypto/hash";
2224
const h = hash("argon2", "password");
2325
verify("argon2", "password", h);
26+
27+
// With options
28+
29+
const h = hash({ name: "argon2", algorithm: "argon2i" }, "password");
30+
verify({ name: AlgorithmName.Argon2, algorithm: "argon2i" }, "password", h);
31+
```
32+
33+
Hashes can also be imported individually, although this should not be needed if
34+
tree shaking is available in your build process.
35+
36+
```ts
37+
import { hash, verify } from "@stdext/crypto/hash/argon2";
38+
const h = hash("password", options);
39+
verify("password", h, options);
2440
```
2541

2642
### HOTP (HMAC One-Time Password)

0 commit comments

Comments
 (0)