diff --git a/Cargo.lock b/Cargo.lock index 3076319..3845595 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,6 +161,7 @@ dependencies = [ "rand", "thiserror", "z32", + "zeroize", ] [[package]] @@ -300,3 +301,9 @@ name = "z32" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4e62ec361f7259399a83b7983270dd0249067d94600c50475e65dca64e24083" + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/kytz/Cargo.toml b/kytz/Cargo.toml index f734c8f..14cfebc 100644 --- a/kytz/Cargo.toml +++ b/kytz/Cargo.toml @@ -12,3 +12,4 @@ bytes = "1.5.0" rand = "0.8.5" thiserror = "1.0.50" z32 = "1.0.2" +zeroize = "1.7.0" diff --git a/kytz/src/crypto/keys.rs b/kytz/src/crypto/keys.rs deleted file mode 100644 index 0bb4d76..0000000 --- a/kytz/src/crypto/keys.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Keypairs. - -use crate::crypto::Key; - -/// Generate a random secret seed. -pub fn generate_seed() -> Key { - rand::random() -} diff --git a/kytz/src/crypto/mod.rs b/kytz/src/crypto/mod.rs index dd6fa58..6ca5ffc 100644 --- a/kytz/src/crypto/mod.rs +++ b/kytz/src/crypto/mod.rs @@ -1,5 +1,4 @@ pub mod encryption; -pub mod keys; pub mod passphrase; pub mod seed; @@ -7,3 +6,13 @@ pub mod seed; pub type Key = [u8; bessie::KEY_LEN]; /// A 24 bytes Nonce or salt. pub type Nonce = [u8; bessie::NONCE_LEN]; + +/// Generate a random secret seed. +pub fn generate_seed() -> Key { + rand::random() +} + +/// Generate a random secret seed. +pub fn generate_salt() -> Nonce { + rand::random() +} diff --git a/kytz/src/crypto/seed.rs b/kytz/src/crypto/seed.rs index 9ef9907..e8205f6 100644 --- a/kytz/src/crypto/seed.rs +++ b/kytz/src/crypto/seed.rs @@ -3,6 +3,7 @@ //! Seed file contains a seed encrypted with a strong passphrase. use bytes::{Bytes, BytesMut}; +use zeroize::Zeroize; use crate::{ crypto::{ @@ -19,7 +20,7 @@ const VERSION: u8 = 0; /// Encrypt the seed with a strong passphrase, and return an [encrypted seed /// file](../../../design/seed.md). pub fn encrypt_seed(seed: &Key, passphrase: &str) -> Bytes { - let encryption_key = derive_encrypiton_key(passphrase); + let mut encryption_key = derive_encryption_key(passphrase); let mut seed_file = BytesMut::with_capacity(SEED_SCHEME.len() + 33); seed_file.extend_from_slice(SEED_SCHEME); @@ -32,9 +33,12 @@ pub fn encrypt_seed(seed: &Key, passphrase: &str) -> Bytes { seed_file.extend_from_slice(z32::encode(&suffix).as_bytes()); + encryption_key.zeroize(); + seed_file.freeze() } +/// Decrypt the [seed file](../../../design/seed.md). pub fn decrypt_seed(seed_file: Bytes, passphrase: &str) -> Result> { if !seed_file.starts_with(SEED_SCHEME) { return Err(Error::Generic("Not a Kytz seed".to_string())); @@ -52,14 +56,19 @@ pub fn decrypt_seed(seed_file: Bytes, passphrase: &str) -> Result> { } fn decrypted_seed_v0(suffix: &[u8], passphrase: &str) -> Result> { - let encryption_key = derive_encrypiton_key(passphrase); + let mut encryption_key = derive_encryption_key(passphrase); let encrypted_seed = &suffix[1..]; - decrypt(&encryption_key, encrypted_seed) + let decrypted_seed = decrypt(&encryption_key, encrypted_seed); + + // Empty the encryption key in memory. + encryption_key.zeroize(); + + decrypted_seed } /// Derive a secret key from a strong passphrase for encrypting/decrypting the seed. -fn derive_encrypiton_key(passphrase: &str) -> Key { +fn derive_encryption_key(passphrase: &str) -> Key { // Argon2 with default params (Argon2id v19) let hasher = argon2::Argon2::default(); @@ -84,8 +93,8 @@ mod test { use std::time::Instant; use super::*; - use crate::crypto::keys::*; use crate::crypto::passphrase::*; + use crate::crypto::*; #[test] fn test_encrypt_decrypt_seed() { @@ -94,7 +103,7 @@ mod test { let encrypted_seed_file = encrypt_seed(&seed, &passphrase); - dbg!(&encrypted_seed_file); + // dbg!(&encrypted_seed_file); let start = Instant::now(); let decrypted_seed = decrypt_seed(encrypted_seed_file, &passphrase)