full master key generation
This commit is contained in:
parent
151274d754
commit
13bdd6791d
@ -14,6 +14,8 @@ pretty_env_logger = "0.3.0"
|
|||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
dirs = "2.0.0"
|
dirs = "2.0.0"
|
||||||
rust-crypto = "0.2.36"
|
rust-crypto = "0.2.36"
|
||||||
|
dialoguer = "0.4.0"
|
||||||
|
rustc-serialize = "0.3.24"
|
||||||
|
|
||||||
[dependencies.rusqlite]
|
[dependencies.rusqlite]
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
|
39
src/crypt.rs
Normal file
39
src/crypt.rs
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
src/db.rs
12
src/db.rs
@ -1,4 +1,6 @@
|
|||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
|
use rustc_serialize::base64;
|
||||||
|
use rustc_serialize::base64::{FromBase64, ToBase64};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -53,4 +55,14 @@ impl DbHandle {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
38
src/main.rs
38
src/main.rs
@ -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 docopt::Docopt;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
@ -6,6 +10,7 @@ use rand::seq::SliceRandom;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
|
pub mod crypt;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod generate;
|
pub mod generate;
|
||||||
|
|
||||||
@ -38,9 +43,7 @@ struct Args {
|
|||||||
fn get_master_key(db_conn: &mut db::DbHandle) -> [u8; 32] {
|
fn get_master_key(db_conn: &mut db::DbHandle) -> [u8; 32] {
|
||||||
let known_string = db_conn
|
let known_string = db_conn
|
||||||
.get_db_property("known_string")
|
.get_db_property("known_string")
|
||||||
.unwrap_or_else(|error| {
|
.expect("There was a problem reading from the db")
|
||||||
panic!("There was a problem reading from the db: {:?}", error);
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
println!("No master password set yet, create new one:");
|
println!("No master password set yet, create new one:");
|
||||||
let mut random = OsRng::new().unwrap();
|
let mut random = OsRng::new().unwrap();
|
||||||
@ -55,7 +58,34 @@ fn get_master_key(db_conn: &mut db::DbHandle) -> [u8; 32] {
|
|||||||
new_known
|
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
|
master_key
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user