Skip to content

Commit

Permalink
Entropy meter
Browse files Browse the repository at this point in the history
- rust modules and PasswordInfo
- Update generation methods and include entropy in UI
- Add entropy meter and update css
  • Loading branch information
Gers2017 committed Sep 11, 2022
1 parent 9798412 commit 3cbb611
Show file tree
Hide file tree
Showing 13 changed files with 351 additions and 196 deletions.
3 changes: 1 addition & 2 deletions package.json
Expand Up @@ -12,8 +12,7 @@
},
"dependencies": {
"@tauri-apps/api": "^1.0.2",
"vue": "^3.2.37",
"vue-toasted": "^1.1.28"
"vue": "^3.2.37"
},
"devDependencies": {
"@tauri-apps/cli": "^1.0.5",
Expand Down
6 changes: 0 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions src-tauri/src/entropy/mod.rs
@@ -0,0 +1,24 @@
use std::collections::HashSet;

// https://en.wikipedia.org/wiki/Password_strength#Entropy_as_a_measure_of_password_strength
// R = pool of unique characters
// log2(R^Length)
pub fn bits_entropy(unique_symbols: usize, pool_length: usize) -> u32 {
let pool_length = pool_length as f64;
(pool_length.powf(unique_symbols as f64)).log2() as u32
}

pub fn get_password_strength(text: &String, pool_length: usize) -> u32 {
let unique_symbols = get_unique_chars_count(text);
bits_entropy(unique_symbols, pool_length)
}

fn get_unique_chars_count(text: &String) -> usize {
let mut set: HashSet<char> = HashSet::new();
let chars: Vec<char> = text.chars().into_iter().collect();
for item in chars {
set.insert(item);
}

set.len()
}
64 changes: 64 additions & 0 deletions src-tauri/src/gen_methods/mod.rs
@@ -0,0 +1,64 @@
use crate::{entropy::get_password_strength, password_info::PasswordInfo, POOL, SPECIAL};
use hex::encode;
use rand::prelude::*;

pub fn gen_schemed(
hash_length: usize,
is_inverted: bool,
words: &mut Vec<String>,
use_special: bool,
) -> PasswordInfo {
let rng = &mut thread_rng();
for _ in 0..10 {
words.shuffle(rng);
}

let word = words.choose(rng).unwrap().to_owned();
let nonsense = gen_nonsense(hash_length, use_special);
let hash = nonsense.text;

let pool_length = POOL.len() + (use_special as usize) * SPECIAL.len();
let text = if is_inverted {
format!("{}{}", hash, word)
} else {
format!("{}{}", word, hash)
};

let entropy = get_password_strength(&text, pool_length);

PasswordInfo::new(text, entropy)
}

pub fn gen_nonsense(length: usize, use_special: bool) -> PasswordInfo {
let rng = &mut thread_rng();
let mut bytes: Vec<u8> = POOL.as_bytes().iter().cloned().collect();

if use_special {
bytes.extend(SPECIAL.as_bytes());
}

for _ in 0..10 {
bytes.shuffle(rng);
}

let bucket: Vec<u8> = (0..length)
.map(|_| bytes.choose(rng).unwrap().to_owned())
.collect();

let pool_length = POOL.len() + (use_special as usize) * SPECIAL.len();
let text = String::from_utf8(bucket).unwrap_or(String::default());
let entropy = get_password_strength(&text, pool_length);

PasswordInfo::new(text, entropy)
}

pub fn gen_random_bytes_hex(size: usize) -> PasswordInfo {
let text = encode(get_random_bytes(size));
let entropy = get_password_strength(&text, 16);
PasswordInfo::new(text, entropy)
}

fn get_random_bytes(size: usize) -> Vec<u8> {
let bytes: Vec<u8> = (0..size).map(|_| random::<u8>()).collect();
bytes
}
6 changes: 6 additions & 0 deletions src-tauri/src/lib.rs
@@ -0,0 +1,6 @@
pub mod entropy;
pub mod gen_methods;
pub mod password_info;

pub const POOL: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // 62
pub const SPECIAL: &str = "!#$%&'()*+,-./:;<=>?{|}~[]^_@|\""; // 31
93 changes: 21 additions & 72 deletions src-tauri/src/main.rs
Expand Up @@ -3,94 +3,42 @@
windows_subsystem = "windows"
)]

use rand::prelude::*;
use passwordo::gen_methods::*;
use passwordo::password_info::PasswordInfo;

const POOL: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const SPECIAL: &str = "*+-=?!<>#$%&?@^~_|";

fn get_words() -> Vec<String> {
let words = vec!["lapras", "pikachu", "mewtwo", "eevee", "magmar", "bidoof"];
words.iter().map(|it| it.to_string()).collect::<Vec<_>>()
}

fn gen_nonsense(length: usize, use_special: bool) -> String {
let rng = &mut thread_rng();
let mut bytes: Vec<u8> = POOL.as_bytes().iter().cloned().collect();
if use_special {
bytes.extend(SPECIAL.as_bytes());
}

bytes.shuffle(rng);

let bucket: Vec<u8> = (0..length)
.map(|_| {
// bytes.choose(rng).unwrap().to_owned()
let i = rng.gen_range(0..bytes.len());
bytes[i]
})
.collect();

String::from_utf8(bucket).unwrap_or(String::default())
}

fn gen_schemed(
hash_length: usize,
is_inverted: bool,
words: &mut Vec<String>,
use_special: bool,
) -> String {
let rng = &mut thread_rng();
words.shuffle(rng);

let word = words.choose(rng).unwrap().to_owned();
let hash = gen_nonsense(hash_length, use_special);

if is_inverted {
return format!("{}{}", hash, word);
}

format!("{}{}", word, hash)
}

fn get_random_bytes(size: usize) -> Vec<u8> {
let bytes: Vec<u8> = (0..size).map(|_| random::<u8>()).collect();
bytes
#[tauri::command]
fn generate_random_bytes_passwords(amount: usize, length: usize) -> Vec<PasswordInfo> {
let res: Vec<PasswordInfo> = (0..amount).map(|_| gen_random_bytes_hex(length)).collect();
res
}

#[tauri::command]
fn generate_nonsense_passwords(
length: usize,
amount: usize,
use_random_bytes: bool,
length: usize,
use_special: bool,
) -> Vec<String> {
let mut res: Vec<String> = Vec::with_capacity(amount);
for _ in 0..amount {
let value = match use_random_bytes {
true => hex::encode(get_random_bytes(length)),
false => gen_nonsense(length, use_special),
};
res.push(value);
}

) -> Vec<PasswordInfo> {
let res: Vec<PasswordInfo> = (0..amount)
.map(|_| gen_nonsense(length, use_special))
.collect();
res
}

#[tauri::command]
fn generate_schemed_passwords(
hash_length: usize,
amount: usize,
hash_length: usize,
is_inverted: bool,
list_of_words: Vec<String>,
use_special: bool,
) -> Vec<String> {
let mut words: Vec<String> = if list_of_words.is_empty() {
get_words()
} else {
list_of_words
};
) -> Vec<PasswordInfo> {
if list_of_words.is_empty() {
return vec![];
}

let mut words = list_of_words;

let res: Vec<String> = (0..amount)
let res: Vec<PasswordInfo> = (0..amount)
.map(|_| gen_schemed(hash_length, is_inverted, &mut words, use_special))
.collect();
res
Expand All @@ -100,7 +48,8 @@ fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
generate_nonsense_passwords,
generate_schemed_passwords
generate_schemed_passwords,
generate_random_bytes_passwords
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
Expand Down
12 changes: 12 additions & 0 deletions src-tauri/src/password_info/mod.rs
@@ -0,0 +1,12 @@
use serde::Serialize;
#[derive(Serialize)]
pub struct PasswordInfo {
pub text: String,
pub entropy: u32,
}

impl PasswordInfo {
pub fn new(text: String, entropy: u32) -> Self {
PasswordInfo { text, entropy }
}
}
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Expand Up @@ -8,7 +8,7 @@
},
"package": {
"productName": "passwordo",
"version": "0.0.0"
"version": "0.0.1"
},
"tauri": {
"allowlist": {
Expand Down

0 comments on commit 3cbb611

Please sign in to comment.