Show entropy to the user when inserting a password
Seems like according to the formula used (`E = L * log2(R)`, where `E` is the ntropy, `L` is the password length and `R` is the quantity of unique characters), a good value is a entropy higher than 60. This is shown by using two distinct colors when rendering the entropy (dark orange when is lower than 60, and light green when is higher than 60). Even though entropy is quite important, it would be more useful to take into account dictionaries when calculating the entropy, because raw bruteforce attacks are somewhat mitigated with the usage of a KDF. Related #1
This commit is contained in:
parent
f4b5a0541d
commit
b051b923fd
2 changed files with 33 additions and 4 deletions
17
src/main.rs
17
src/main.rs
|
@ -11,12 +11,12 @@ use std::fs;
|
|||
use std::time::SystemTime;
|
||||
use directories::ProjectDirs;
|
||||
use eframe::{CreationContext, Frame};
|
||||
use egui::{Context, RichText, TextEdit, Widget};
|
||||
use egui::{Color32, Context, RichText, TextEdit, Widget, WidgetText};
|
||||
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::password::{check_password, entropy, generate_new_password};
|
||||
use crate::saving::Saving;
|
||||
|
||||
mod notes;
|
||||
|
@ -223,7 +223,20 @@ impl eframe::App for App {
|
|||
ui.label(RichText::new("after starting the app, the password will be tested against the latest note").italics());
|
||||
|
||||
ui.add_space(10.0);
|
||||
ui.horizontal(|ui| {
|
||||
TextEdit::singleline(&mut self.password_buffer).password(true).ui(ui);
|
||||
if let Some(entropy) = entropy(&self.password_buffer) {
|
||||
let text = if entropy < 60_f64 {
|
||||
WidgetText::from(format!("entropy: {:.2}", entropy))
|
||||
.color(Color32::from_rgb(220, 88, 42))
|
||||
} else {
|
||||
WidgetText::from(format!("entropy: {:.2}", entropy))
|
||||
.color(Color32::from_rgb(144, 238, 144))
|
||||
};
|
||||
|
||||
ui.label(text);
|
||||
}
|
||||
});
|
||||
ui.add_space(7.5);
|
||||
|
||||
if ui.button("start app").clicked() {
|
||||
|
|
|
@ -8,11 +8,27 @@ pub fn generate_new_password(password: &str) -> String {
|
|||
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();
|
||||
Argon2::default().hash_password_into(password.as_bytes(), &output, &mut output_key).unwrap();
|
||||
|
||||
hex::encode(output_key)
|
||||
}
|
||||
|
||||
pub fn entropy(password: &str) -> Option<f64> {
|
||||
if password.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let length = password.len() as f64;
|
||||
let unique_characters = {
|
||||
let mut unique_chars: Vec<char> = password.chars().collect();
|
||||
unique_chars.dedup();
|
||||
|
||||
unique_chars.len()
|
||||
} as f64;
|
||||
|
||||
Some(length * unique_characters.log2())
|
||||
}
|
||||
|
||||
pub fn check_password(password: &str, note: &Note) -> anyhow::Result<String> {
|
||||
if note.decrypt(password).is_err() {
|
||||
let new_password = generate_new_password(password);
|
||||
|
|
Loading…
Reference in a new issue