Skip to content

Commit

Permalink
Merge pull request #11 from halvardssm/fix/crypto-hash-improved-throws
Browse files Browse the repository at this point in the history
fix(crypto/hash): Improved throw messages
  • Loading branch information
halvardssm authored Dec 29, 2024
2 parents ddf5d4b + 9391922 commit 7ce38a6
Show file tree
Hide file tree
Showing 11 changed files with 5,439 additions and 5,284 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ console.log(dump(buffer));

## Packages

- [assert](https://jsr.io/@stdext/assert): The assert package, contains
validators and assertions
- [crypto](https://jsr.io/@stdext/crypto): The crypto package contains utility
for crypto and hashing
- [encoding](https://jsr.io/@stdext/encoding): The encoding package contains
Expand Down
27 changes: 17 additions & 10 deletions _wasm/crypto_hash_argon2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ extern "C" {

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

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

(algorithm, params)
}

/// Hash a password using Argon2
#[wasm_bindgen]
pub fn hash(data: String, options: Argon2Options) -> String {
pub fn hash(data: String, options: Argon2Options) -> Result<String, JsError> {
let (algorithm, parsed_options) = get_parsed_options(options);
let argon2 = Argon2::new(algorithm, Version::V0x13, parsed_options.clone());
let salt = SaltString::generate(&mut OsRng);
let data_bytes = data.as_bytes();
argon2
let hash = argon2
.hash_password(data_bytes, &salt)
.expect("hashing failed")
.to_string()
.expect_throw("Failed to generate hash")
.to_string();
Ok(hash)
}

/// Verify a password using Argon2
#[wasm_bindgen]
pub fn verify(data: String, hash: String, options: Argon2Options) -> bool {
pub fn verify(
data: String,
hash: String,
options: Argon2Options,
) -> Result<bool, JsError> {
let (algorithm, parsed_options) = get_parsed_options(options);

let data_bytes = data.as_bytes();
let parsed_hash = PasswordHash::new(&hash).expect("failed to parse hash");
let argon2 = Argon2::new(algorithm, Version::V0x13, parsed_options.clone())
let parsed_hash = PasswordHash::new(&hash)
.expect_throw("Failed to parse hash, invalid hash provided");
let is_ok = Argon2::new(algorithm, Version::V0x13, parsed_options.clone())
.verify_password(data_bytes, &parsed_hash)
.is_ok();

argon2
Ok(is_ok)
}
20 changes: 14 additions & 6 deletions _wasm/crypto_hash_bcrypt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,28 @@ pub struct WasmBcryptOptionsIncoming {

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

/// Hash a password using Bcrypt
#[wasm_bindgen]
pub fn hash(password: String, options: BcryptOptions) -> String {
pub fn hash(
password: String,
options: BcryptOptions,
) -> Result<String, JsError> {
let cost = get_parsed_options(options);
bcrypt_hash(password, cost).expect_throw("failed to hash password")
Ok(bcrypt_hash(password, cost).expect_throw("Failed to generate hash"))
}

/// Verify a password using Bcrypt
#[wasm_bindgen]
pub fn verify(password: String, hash: String, options: BcryptOptions) -> bool {
bcrypt_verify(password, &hash.as_str())
.expect_throw("failed to verify password")
pub fn verify(
password: String,
hash: String,
options: BcryptOptions,
) -> Result<bool, JsError> {
let is_ok = bcrypt_verify(password, &hash.as_str()).is_ok();
Ok(is_ok)
}
23 changes: 15 additions & 8 deletions _wasm/crypto_hash_scrypt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,33 +76,40 @@ extern "C" {

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

Params::new(
parsed_options.log_n.unwrap_or(Params::RECOMMENDED_LOG_N),
parsed_options.block_size.unwrap_or(Params::RECOMMENDED_R),
parsed_options.parallelism.unwrap_or(Params::RECOMMENDED_P),
parsed_options.key_lenght.unwrap_or(Params::RECOMMENDED_LEN),
)
.expect("invalid parameters")
.expect_throw("Failed to parse parameters")
}

/// Hash a password using Scrypt
#[wasm_bindgen]
pub fn hash(data: String, options: ScryptOptions) -> String {
pub fn hash(data: String, options: ScryptOptions) -> Result<String, JsError> {
let parsed_options = get_parsed_options(options);
let data_bytes = data.as_bytes();
let salt = SaltString::generate(&mut OsRng);
let hasher = Scrypt
.hash_password_customized(data_bytes, None, None, parsed_options, &salt)
.expect_throw("failed to hash password");
hasher.to_string()
.expect_throw("Failed to generate hash");
Ok(hasher.to_string())
}

/// Verify a password using Scrypt
#[wasm_bindgen]
pub fn verify(data: String, hash: String, _options: ScryptOptions) -> bool {
pub fn verify(
data: String,
hash: String,
_options: ScryptOptions,
) -> Result<bool, JsError> {
let data_bytes = data.as_bytes();
let parsed_hash = PasswordHash::new(&hash).expect("failed to parse hash");
Scrypt.verify_password(data_bytes, &parsed_hash).is_ok()
let parsed_hash = PasswordHash::new(&hash)
.expect_throw("Failed to parse hash, invalid hash provided");
let is_ok = Scrypt.verify_password(data_bytes, &parsed_hash).is_ok();
Ok(is_ok)
}
16 changes: 16 additions & 0 deletions crypto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ hashing.

The hash module contains helpers and implementations for password hashing.

> The hash methods are written in Rust and compiled to WASM.
The following algorithms are provided:

- Argon2
Expand All @@ -21,6 +23,20 @@ The following algorithms are provided:
import { hash, verify } from "@stdext/crypto/hash";
const h = hash("argon2", "password");
verify("argon2", "password", h);

// With options

const h = hash({ name: "argon2", algorithm: "argon2i" }, "password");
verify({ name: AlgorithmName.Argon2, algorithm: "argon2i" }, "password", h);
```

Hashes can also be imported individually, although this should not be needed if
tree shaking is available in your build process.

```ts
import { hash, verify } from "@stdext/crypto/hash/argon2";
const h = hash("password", options);
verify("password", h, options);
```

### HOTP (HMAC One-Time Password)
Expand Down
Loading

0 comments on commit 7ce38a6

Please sign in to comment.