full master key generation

master
Tom Alexander 5 years ago
parent 151274d754
commit 13bdd6791d

@ -14,6 +14,8 @@ pretty_env_logger = "0.3.0"
rand = "0.6.5"
dirs = "2.0.0"
rust-crypto = "0.2.36"
dialoguer = "0.4.0"
rustc-serialize = "0.3.24"
[dependencies.rusqlite]
version = "0.18.0"

@ -0,0 +1,39 @@
use super::db;
use crypto::scrypt::{self, ScryptParams};
use rand::rngs::OsRng;
use rand::Rng;
use rustc_serialize::base64;
use rustc_serialize::base64::{FromBase64, ToBase64};
use std::io;
pub fn get_master_key(db_conn: &db::DbHandle, master_password: &str) -> io::Result<[u8; 32]> {
let scrypt_params: ScryptParams = ScryptParams::new(12, 16, 2);
let salt: Vec<u8> = get_salt(db_conn)?;
// 256 bit derived key
let mut derived_key = [0u8; 32];
scrypt::scrypt(
master_password.as_bytes(),
&*salt,
&scrypt_params,
&mut derived_key,
);
Ok(derived_key)
}
fn get_salt(db_conn: &db::DbHandle) -> io::Result<Vec<u8>> {
let existing_salt: Option<String> = db_conn
.get_db_property("salt")
.expect("There was a problem reading from the db");
match existing_salt {
Some(salt) => Ok(salt.from_base64().unwrap()),
None => {
let mut rng = OsRng::new()?;
// 128 bit salt
let salt: Vec<u8> = rng.gen::<[u8; 16]>().to_vec();
db_conn.set_db_property("salt", &salt.to_base64(base64::STANDARD));
Ok(salt)
}
}
}

@ -1,4 +1,6 @@
use rusqlite::Connection;
use rustc_serialize::base64;
use rustc_serialize::base64::{FromBase64, ToBase64};
use std::error::Error;
use std::path::PathBuf;
@ -53,4 +55,14 @@ impl DbHandle {
)
.unwrap();
}
pub fn get_db_property_bytes(&self, name: &str) -> Result<Option<Vec<u8>>, Box<dyn Error>> {
self.get_db_property(name)
.map(|option| option.map(|prop| prop.from_base64().unwrap()))
}
pub fn set_db_property_bytes(&self, name: &str, value: &Vec<u8>) {
let b64value: String = value.to_base64(base64::STANDARD);
self.set_db_property(name, &b64value);
}
}

@ -1,3 +1,7 @@
use crypto::hmac::Hmac;
use crypto::mac::{Mac, MacResult};
use crypto::sha2::Sha256;
use dialoguer::{theme::ColorfulTheme, PasswordInput};
use docopt::Docopt;
use log::debug;
use rand::rngs::OsRng;
@ -6,6 +10,7 @@ use rand::seq::SliceRandom;
use serde::Deserialize;
use std::error::Error;
pub mod crypt;
pub mod db;
pub mod generate;
@ -38,9 +43,7 @@ struct Args {
fn get_master_key(db_conn: &mut db::DbHandle) -> [u8; 32] {
let known_string = db_conn
.get_db_property("known_string")
.unwrap_or_else(|error| {
panic!("There was a problem reading from the db: {:?}", error);
})
.expect("There was a problem reading from the db")
.unwrap_or_else(|| {
println!("No master password set yet, create new one:");
let mut random = OsRng::new().unwrap();
@ -55,7 +58,34 @@ fn get_master_key(db_conn: &mut db::DbHandle) -> [u8; 32] {
new_known
});
let master_key: [u8; 32] = [0; 32];
let master_key: [u8; 32] = {
let master_password = PasswordInput::with_theme(&ColorfulTheme::default())
.with_prompt("Master password")
.with_confirmation(
"Repeat master password",
"Error: the passwords don't match.",
)
.interact()
.unwrap();
crypt::get_master_key(&db_conn, &master_password).unwrap()
};
let mut hmac = Hmac::new(Sha256::new(), &master_key);
hmac.input(known_string.as_bytes());
let existing_hmac = db_conn
.get_db_property_bytes("known_hmac")
.expect("There was a problem reading from the db")
.unwrap_or_else(|| {
let mut raw_result: Vec<u8> = std::iter::repeat(0).take(hmac.output_bytes()).collect();
hmac.raw_result(&mut raw_result);
db_conn.set_db_property_bytes("known_hmac", &raw_result);
raw_result
});
if hmac.result() != MacResult::new(&existing_hmac[..]) {
panic!("Incorrect master password");
}
master_key
}

Loading…
Cancel
Save