feat(stronghold): add an init function that uses argon2 (#449)

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
pull/542/head
Alexandre Dang 2 years ago committed by GitHub
parent 700549ab02
commit dacde1629d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
"stronghold": patch
---
Added `Builder::with_argon2`.

1778
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -20,6 +20,15 @@ iota-crypto = "0.23"
hex = "0.4"
zeroize = { version = "1", features = ["zeroize_derive"] }
# kdf dependencies
rust-argon2 = { version = "1", optional = true }
rand_chacha = { version = "0.3.1", optional = true }
rand_core = { version = "0.6.4", features = ["getrandom"], optional = true }
[dev-dependencies]
rand = "0.8"
rusty-fork = "0.3"
rusty-fork = "0.3"
[features]
default = ["kdf"]
kdf = ["dep:rust-argon2", "dep:rand_chacha", "dep:rand_core"]

@ -0,0 +1,35 @@
use rand_chacha::ChaCha20Rng;
use rand_core::{RngCore, SeedableRng};
use std::path::Path;
/// NOTE: Hash supplied to Stronghold must be 32bits long.
/// This is a current limitation of Stronghold.
const HASH_LENGTH: usize = 32;
pub struct KeyDerivation {}
impl KeyDerivation {
/// Will create a key from [`password`] and a generated salt.
/// Salt will be generated to file [`salt_path`] or taken from it
/// if file already exists
pub fn argon2(password: &str, salt_path: &Path) -> Vec<u8> {
let mut salt = [0u8; HASH_LENGTH];
create_or_get_salt(&mut salt, salt_path);
argon2::hash_raw(password.as_bytes(), &salt, &Default::default())
.expect("Failed to generate hash for password")
}
}
fn create_or_get_salt(salt: &mut [u8], salt_path: &Path) {
if salt_path.is_file() {
// Get existing salt
let tmp = std::fs::read(salt_path).unwrap();
salt.clone_from_slice(&tmp);
} else {
// Generate new salt
let mut gen = ChaCha20Rng::from_entropy();
gen.fill_bytes(salt);
std::fs::write(salt_path, salt).expect("Failed to write salt for Stronghold")
}
}

@ -22,6 +22,9 @@ use tauri::{
};
use zeroize::Zeroize;
#[cfg(feature = "kdf")]
pub mod kdf;
pub mod stronghold;
type PasswordHashFn = dyn Fn(&str) -> Vec<u8> + Send + Sync;
@ -394,26 +397,70 @@ fn get_client(
}
}
enum PasswordHashFunctionKind {
#[cfg(feature = "kdf")]
Argon2(PathBuf),
Custom(Box<PasswordHashFn>),
}
pub struct Builder {
password_hash_function: Box<PasswordHashFn>,
password_hash_function: PasswordHashFunctionKind,
}
impl Builder {
pub fn new<F: Fn(&str) -> Vec<u8> + Send + Sync + 'static>(password_hash_function: F) -> Self {
Self {
password_hash_function: Box::new(password_hash_function),
password_hash_function: PasswordHashFunctionKind::Custom(Box::new(
password_hash_function,
)),
}
}
/// Initializes [`Self`] with argon2 as password hash function.
///
/// # Examples
///
/// ```rust
/// tauri::Builder::default()
/// .setup(|app| {
/// let salt_path = app
/// .path_resolver()
/// .app_local_data_dir()
/// .expect("could not resolve app local data path")
/// .join("salt.txt");
/// app.handle().plugin(tauri_plugin_stronghold::Builder::with_argon2(&salt_path).build())?;
/// Ok(())
/// });
/// ```
#[cfg(feature = "kdf")]
pub fn with_argon2(salt_path: &std::path::Path) -> Self {
Self {
password_hash_function: PasswordHashFunctionKind::Argon2(salt_path.to_owned()),
}
}
pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
let password_hash_function = self.password_hash_function;
PluginBuilder::new("stronghold")
.setup(move |app| {
app.manage(StrongholdCollection::default());
app.manage(PasswordHashFunction(password_hash_function));
Ok(())
})
let plugin_builder = PluginBuilder::new("stronghold").setup(move |app| {
app.manage(StrongholdCollection::default());
app.manage(PasswordHashFunction(match password_hash_function {
#[cfg(feature = "kdf")]
PasswordHashFunctionKind::Argon2(path) => {
Box::new(move |p| kdf::KeyDerivation::argon2(p, &path))
}
PasswordHashFunctionKind::Custom(f) => f,
}));
Ok(())
});
Builder::invoke_stronghold_handlers_and_build(plugin_builder)
}
fn invoke_stronghold_handlers_and_build<R: Runtime>(
builder: PluginBuilder<R>,
) -> TauriPlugin<R> {
builder
.invoke_handler(tauri::generate_handler![
initialize,
destroy,

Loading…
Cancel
Save