Derive key pairs from passwords

This commit is contained in:
Dennis Schwerdel 2017-05-08 15:11:07 +02:00
parent cac4f81876
commit 4ac42d14ef
9 changed files with 52 additions and 7 deletions

View File

@ -4,6 +4,7 @@ This project follows [semantic versioning](http://semver.org).
### UNRELEASED ### UNRELEASED
* [added] Derive key pairs from passwords
* [modified] Added root repository to exclude list * [modified] Added root repository to exclude list
* [modified] Initializing data in index before use * [modified] Initializing data in index before use

1
Cargo.lock generated
View File

@ -14,6 +14,7 @@ dependencies = [
"index 0.1.0", "index 0.1.0",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"libsodium-sys 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"murmurhash3 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "murmurhash3 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"pbr 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "pbr 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -20,6 +20,7 @@ log = "0.3"
byteorder = "1.0" byteorder = "1.0"
ansi_term = "0.9" ansi_term = "0.9"
sodiumoxide = "0.0.14" sodiumoxide = "0.0.14"
libsodium-sys = "0.0.14"
filetime = "0.1" filetime = "0.1"
regex = "0.2" regex = "0.2"
fuse = "0.3" fuse = "0.3"

View File

@ -32,6 +32,11 @@ key will be set as default encryption key.
Set the key pair as default Set the key pair as default
* `-p`, `--password <PASSWORD>`:
Derive the key pair from the given password instead of randomly creating it.
* `-h`, `--help`: * `-h`, `--help`:
Prints help information Prints help information

View File

@ -14,6 +14,10 @@ writes it to the given file `FILE`.
## OPTIONS ## OPTIONS
* `-p`, `--password <PASSWORD>`:
Derive the key pair from the given password instead of randomly creating it.
* `-h`, `--help`: * `-h`, `--help`:
Prints help information Prints help information

View File

@ -116,11 +116,13 @@ pub enum Arguments {
hash: Option<HashMethod> hash: Option<HashMethod>
}, },
GenKey { GenKey {
file: Option<String> file: Option<String>,
password: Option<String>
}, },
AddKey { AddKey {
repo_path: String, repo_path: String,
file: Option<String>, file: Option<String>,
password: Option<String>,
set_default: bool set_default: bool
}, },
AlgoTest { AlgoTest {
@ -399,11 +401,14 @@ pub fn parse() -> Result<(LogLevel, Arguments), ErrorCode> {
.arg(Arg::from_usage("<REPO> 'Path of the repository'") .arg(Arg::from_usage("<REPO> 'Path of the repository'")
.validator(|val| validate_repo_path(val, true, Some(false), Some(false))))) .validator(|val| validate_repo_path(val, true, Some(false), Some(false)))))
.subcommand(SubCommand::with_name("genkey").about("Generate a new key pair") .subcommand(SubCommand::with_name("genkey").about("Generate a new key pair")
.arg(Arg::from_usage("-p --password [PASSWORD] 'Derive the key pair from the given password'"))
.arg(Arg::from_usage("[FILE] 'Destination file for the keypair'"))) .arg(Arg::from_usage("[FILE] 'Destination file for the keypair'")))
.subcommand(SubCommand::with_name("addkey").about("Add a key pair to the repository") .subcommand(SubCommand::with_name("addkey").about("Add a key pair to the repository")
.arg(Arg::from_usage("-g --generate 'Generate a new key pair'") .arg(Arg::from_usage("-g --generate 'Generate a new key pair'")
.conflicts_with("FILE")) .conflicts_with_all(&["FILE", "PASSWORD"]))
.arg(Arg::from_usage("[set_default] --default -d 'Set the key pair as default'")) .arg(Arg::from_usage("[set_default] --default -d 'Set the key pair as default'"))
.arg(Arg::from_usage("-p --password [PASSWORD] 'Derive the key pair from the given password'")
.conflicts_with("FILE"))
.arg(Arg::from_usage("<REPO> 'Path of the repository'") .arg(Arg::from_usage("<REPO> 'Path of the repository'")
.validator(|val| validate_repo_path(val, true, Some(false), Some(false)))) .validator(|val| validate_repo_path(val, true, Some(false), Some(false))))
.arg(Arg::from_usage("[FILE] 'File containing the keypair'") .arg(Arg::from_usage("[FILE] 'File containing the keypair'")
@ -592,7 +597,8 @@ pub fn parse() -> Result<(LogLevel, Arguments), ErrorCode> {
}, },
("genkey", Some(args)) => { ("genkey", Some(args)) => {
Arguments::GenKey { Arguments::GenKey {
file: args.value_of("FILE").map(|v| v.to_string()) file: args.value_of("FILE").map(|v| v.to_string()),
password: args.value_of("password").map(|v| v.to_string())
} }
}, },
("addkey", Some(args)) => { ("addkey", Some(args)) => {
@ -600,6 +606,7 @@ pub fn parse() -> Result<(LogLevel, Arguments), ErrorCode> {
Arguments::AddKey { Arguments::AddKey {
repo_path: repository.to_string(), repo_path: repository.to_string(),
set_default: args.is_present("set_default"), set_default: args.is_present("set_default"),
password: args.value_of("password").map(|v| v.to_string()),
file: args.value_of("FILE").map(|v| v.to_string()) file: args.value_of("FILE").map(|v| v.to_string())
} }
}, },

View File

@ -625,8 +625,11 @@ pub fn run() -> Result<(), ErrorCode> {
print_config(&repo.config); print_config(&repo.config);
} }
}, },
Arguments::GenKey{file} => { Arguments::GenKey{file, password} => {
let (public, secret) = Crypto::gen_keypair(); let (public, secret) = match password {
None => Crypto::gen_keypair(),
Some(ref password) => Crypto::keypair_from_password(password)
};
info!("Created the following key pair"); info!("Created the following key pair");
println!("public: {}", to_hex(&public[..])); println!("public: {}", to_hex(&public[..]));
println!("secret: {}", to_hex(&secret[..])); println!("secret: {}", to_hex(&secret[..]));
@ -634,13 +637,16 @@ pub fn run() -> Result<(), ErrorCode> {
checked!(Crypto::save_keypair_to_file(&public, &secret, file), "save key pair", ErrorCode::SaveKey); checked!(Crypto::save_keypair_to_file(&public, &secret, file), "save key pair", ErrorCode::SaveKey);
} }
}, },
Arguments::AddKey{repo_path, set_default, file} => { Arguments::AddKey{repo_path, set_default, password, file} => {
let mut repo = try!(open_repository(&repo_path)); let mut repo = try!(open_repository(&repo_path));
let (public, secret) = if let Some(file) = file { let (public, secret) = if let Some(file) = file {
checked!(Crypto::load_keypair_from_file(file), "load key pair", ErrorCode::LoadKey) checked!(Crypto::load_keypair_from_file(file), "load key pair", ErrorCode::LoadKey)
} else { } else {
info!("Created the following key pair"); info!("Created the following key pair");
let (public, secret) = Crypto::gen_keypair(); let (public, secret) = match password {
None => Crypto::gen_keypair(),
Some(ref password) => Crypto::keypair_from_password(password)
};
println!("public: {}", to_hex(&public[..])); println!("public: {}", to_hex(&public[..]));
println!("secret: {}", to_hex(&secret[..])); println!("secret: {}", to_hex(&secret[..]));
(public, secret) (public, secret)

View File

@ -14,6 +14,7 @@ extern crate chrono;
#[macro_use] extern crate log; #[macro_use] extern crate log;
extern crate byteorder; extern crate byteorder;
extern crate sodiumoxide; extern crate sodiumoxide;
extern crate libsodium_sys;
extern crate ansi_term; extern crate ansi_term;
extern crate filetime; extern crate filetime;
extern crate regex; extern crate regex;

View File

@ -7,9 +7,11 @@ use std::sync::{Once, ONCE_INIT};
use serde_yaml; use serde_yaml;
use serde_bytes::ByteBuf; use serde_bytes::ByteBuf;
use libsodium_sys;
use sodiumoxide; use sodiumoxide;
use sodiumoxide::crypto::sealedbox; use sodiumoxide::crypto::sealedbox;
use sodiumoxide::crypto::box_; use sodiumoxide::crypto::box_;
use sodiumoxide::crypto::pwhash;
pub use sodiumoxide::crypto::box_::{SecretKey, PublicKey}; pub use sodiumoxide::crypto::box_::{SecretKey, PublicKey};
use ::util::*; use ::util::*;
@ -211,4 +213,21 @@ impl Crypto {
sodium_init(); sodium_init();
box_::gen_keypair() box_::gen_keypair()
} }
pub fn keypair_from_password(password: &str) -> (PublicKey, SecretKey) {
let salt = pwhash::Salt::from_slice(b"the_great_zvault_password_salt_1").unwrap();
let mut key = [0u8; pwhash::HASHEDPASSWORDBYTES];
let key = pwhash::derive_key(&mut key, password.as_bytes(), &salt, pwhash::OPSLIMIT_INTERACTIVE, pwhash::MEMLIMIT_INTERACTIVE).unwrap();
let mut seed = [0u8; 32];
let offset = key.len()-seed.len();
for (i, b) in seed.iter_mut().enumerate() {
*b = key[i+offset];
}
let mut pk = [0u8; 32];
let mut sk = [0u8; 32];
if unsafe { libsodium_sys::crypto_box_seed_keypair(&mut pk, &mut sk, &seed) } != 0 {
panic!("Libsodium failed");
}
(PublicKey::from_slice(&pk).unwrap(), SecretKey::from_slice(&sk).unwrap())
}
} }