diff --git a/Cargo.toml b/Cargo.toml index 9e73892..0be7408 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,7 @@ serde_json = "1.0" rand = "0.8" pwbox = "0.5" directories = "4.0" -native-dialog = "0.6" \ No newline at end of file +native-dialog = "0.6" +hex = "0.4" +sha2 = "0.10" +argon2 = "0.5" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index eaf1ae3..01e559b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,10 +16,12 @@ use log::info; use native_dialog::MessageDialog; use simple_logger::SimpleLogger; use crate::notes::{Note, NoteMetadata}; +use crate::password::{check_password, generate_new_password}; use crate::saving::Saving; mod notes; mod saving; +mod password; #[derive(PartialEq)] enum CurrentMode { @@ -101,7 +103,9 @@ impl eframe::App for App { if !self.tested_password && self.password.is_some() { if let Some(note) = self.notes.get(0) { - if note.decrypt(self.password.as_ref().unwrap()).is_err() { + if let Ok(password) = check_password(self.password.as_ref().unwrap(), note) { + self.password = Some(password); + } else { let _ = MessageDialog::new() .set_title("invalid password") .set_text("failed to verify the password against an existing note. please try again") @@ -111,9 +115,11 @@ impl eframe::App for App { self.tested_password = false; return; } - - self.tested_password = true; + } else { + self.password = Some(generate_new_password(self.password.as_ref().unwrap())) } + + self.tested_password = true; } if self.update_notes_next { diff --git a/src/password/mod.rs b/src/password/mod.rs new file mode 100644 index 0000000..6aa3f70 --- /dev/null +++ b/src/password/mod.rs @@ -0,0 +1,35 @@ +use anyhow::bail; +use argon2::Argon2; +use sha2::{Sha256, Digest}; +use crate::notes::Note; + +pub fn generate_new_password(password: &str) -> String { + let mut output = [0_u8; 32]; + let mut output_key = [0u8; 256]; + + hash_password(password.as_bytes(), &mut output); + Argon2::default().hash_password_into(&password.as_bytes(), &output, &mut output_key).unwrap(); + + hex::encode(output_key) +} + +pub fn check_password(password: &str, note: &Note) -> anyhow::Result { + if note.decrypt(password).is_err() { + let new_password = generate_new_password(password); + if note.decrypt(&new_password).is_err() { + bail!("invalid password"); + } else { + Ok(new_password) + } + } else { + Ok(password.into()) + } +} + +fn hash_password(password: &[u8], output: &mut [u8]) { + let mut hasher = Sha256::new(); + hasher.update(password); + let result = hasher.finalize(); + + output.clone_from_slice(&result[..]) +} \ No newline at end of file