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

pull/449/head
vdang 2 years ago
parent 7b9d7a1d88
commit 39ba4a2a17
No known key found for this signature in database
GPG Key ID: 48DFAD25A8F31057

25
Cargo.lock generated

@ -102,6 +102,17 @@ version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "argon2"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95c2fcf79ad1932ac6269a738109997a83c227c09b75842ae564dc8ede6a861c"
dependencies = [
"base64ct",
"blake2",
"password-hash",
]
[[package]]
name = "arrayref"
version = "0.3.6"
@ -2850,6 +2861,17 @@ dependencies = [
"windows-sys 0.42.0",
]
[[package]]
name = "password-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
dependencies = [
"base64ct",
"rand_core 0.6.4",
"subtle",
]
[[package]]
name = "paste"
version = "1.0.11"
@ -4458,11 +4480,14 @@ dependencies = [
name = "tauri-plugin-stronghold"
version = "0.0.0"
dependencies = [
"argon2",
"hex",
"iota-crypto 0.21.0",
"iota_stronghold",
"log",
"rand 0.8.5",
"rand_chacha 0.3.1",
"rand_core 0.6.4",
"rusty-fork",
"serde",
"serde_json",

@ -20,6 +20,15 @@ iota-crypto = "0.21"
hex = "0.4"
zeroize = { version = "1", features = ["zeroize_derive"] }
# kdf dependincies
argon2 = { version = "0.5.0", 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:argon2", "dep:rand_chacha", "dep:rand_core"]

@ -0,0 +1,56 @@
use argon2::Argon2;
use rand_chacha::ChaCha20Rng;
use rand_core::{RngCore, SeedableRng};
use std::path::PathBuf;
use tauri::Config;
/// NOTE: Hash supplied to Stronghold must be 32bits long.
/// This is a current limitation of Stronghold.
const HASH_LENGTH: usize = 32;
const SALT_FILENAME: &str = "stronghold_salt.txt";
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: &PathBuf) -> Vec<u8> {
let mut salt = [0u8; HASH_LENGTH];
create_or_get_salt(&mut salt, salt_path);
let mut encoded = [0u8; HASH_LENGTH];
Argon2::default()
.hash_password_into(password.as_bytes(), &salt, &mut encoded)
.expect("Failed to generate hash for password");
encoded.to_vec()
}
/// Will create a key from [`password`] and a generated salt.
/// Salt will be generated/taken from a default file in the Tauri local
/// directory
pub fn argon2_with_config(password: &str, tauri_config: &Config) -> Vec<u8> {
let salt_dir = tauri::api::path::app_local_data_dir(tauri_config)
.expect("Application local directory not found");
let mut salt_path = PathBuf::new();
salt_path.push(salt_dir);
salt_path.push(SALT_FILENAME);
KeyDerivation::argon2(password, &salt_path)
}
}
// NOTE: this is not ideal as we produce a single salt per application
// rather than having different salt for each Stronghold snapshot/password
fn create_or_get_salt(salt: &mut [u8], salt_path: &PathBuf) {
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;
@ -405,15 +408,35 @@ impl Builder {
}
}
/// Initializes a stronghold plugin with argon2 as a default kdf
pub fn init_and_build_with_argon2<R: Runtime>() -> TauriPlugin<R> {
let plugin_builder = PluginBuilder::new("stronghold").setup(move |app| {
let app2 = app.clone();
app.manage(StrongholdCollection::default());
app.manage(PasswordHashFunction(Box::new(move |pwd: &str| {
kdf::KeyDerivation::argon2_with_config(pwd, &app2.config())
})));
Ok(())
});
Builder::invoke_stronghold_handlers_and_build(plugin_builder)
}
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(password_hash_function));
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