Skip to content
Snippets Groups Projects
Commit 99b3df74 authored by Éloïs's avatar Éloïs
Browse files

[fix] crypto: security: clear seeds, pass, secrets when it's dropped

parent c027afd5
Branches
No related tags found
1 merge request!200[fix] crypto: security: clear seeds, pass, secrets when it's dropped
......@@ -586,6 +586,7 @@ dependencies = [
name = "durs-core"
version = "0.3.0-dev"
dependencies = [
"clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"dubp-currency-params 0.2.0",
"dup-crypto 0.7.0",
......
......@@ -42,25 +42,25 @@ impl From<std::io::Error> for WizardError {
/// Modify network keys command
pub fn modify_network_keys(
salt: &str,
password: &str,
salt: String,
password: String,
mut key_pairs: DuniterKeyPairs,
) -> DuniterKeyPairs {
let generator = ed25519::KeyPairFromSaltedPasswordGenerator::with_default_parameters();
key_pairs.network_keypair =
KeyPairEnum::Ed25519(generator.generate(salt.as_bytes(), password.as_bytes()));
KeyPairEnum::Ed25519(generator.generate(ed25519::SaltedPassword::new(salt, password)));
key_pairs
}
/// Modify member keys command
pub fn modify_member_keys(
salt: &str,
password: &str,
salt: String,
password: String,
mut key_pairs: DuniterKeyPairs,
) -> DuniterKeyPairs {
let generator = ed25519::KeyPairFromSaltedPasswordGenerator::with_default_parameters();
key_pairs.member_keypair = Some(KeyPairEnum::Ed25519(
generator.generate(salt.as_bytes(), password.as_bytes()),
generator.generate(ed25519::SaltedPassword::new(salt, password)),
));
key_pairs
}
......@@ -129,10 +129,9 @@ fn salt_password_prompt() -> Result<KeyPairEnum, WizardError> {
let password = rpassword::prompt_password_stdout("Password: ")?;
if !password.is_empty() {
let generator = ed25519::KeyPairFromSaltedPasswordGenerator::with_default_parameters();
let key_pairs = KeyPairEnum::Ed25519(generator.generate(
salt.into_bytes().as_slice(),
password.into_bytes().as_slice(),
));
let key_pairs = KeyPairEnum::Ed25519(
generator.generate(ed25519::SaltedPassword::new(salt, password)),
);
Ok(key_pairs)
} else {
Err(WizardError::BadInput)
......@@ -191,7 +190,8 @@ mod tests {
}),
member_keypair: None,
};
let result_key_pairs = modify_member_keys(SALT_TEST, PASSWORD_TEST, key_pairs);
let result_key_pairs =
modify_member_keys(SALT_TEST.to_owned(), PASSWORD_TEST.to_owned(), key_pairs);
// We expect network key not to change
assert_eq!(
result_key_pairs.network_keypair.public_key(),
......@@ -239,7 +239,8 @@ mod tests {
}),
member_keypair: None,
};
let result_key_pairs = modify_network_keys(SALT_TEST, PASSWORD_TEST, key_pairs);
let result_key_pairs =
modify_network_keys(SALT_TEST.to_owned(), PASSWORD_TEST.to_owned(), key_pairs);
// We expect network key to update
assert_eq!(
result_key_pairs.network_keypair.public_key(),
......
......@@ -10,6 +10,7 @@ edition = "2018"
path = "src/lib.rs"
[dependencies]
clear_on_drop = "0.2.3"
dirs = "1.0.2"
durs-blockchain = { path = "../../modules/blockchain/blockchain" }
durs-common-tools = { path = "../../tools/common-tools" }
......
......@@ -18,6 +18,7 @@
use crate::commands::DursExecutableCoreCommand;
use crate::errors::DursCoreError;
use crate::DursCore;
use clear_on_drop::clear::Clear;
use durs_conf::keys::*;
use durs_conf::DuRsConf;
......@@ -124,6 +125,14 @@ pub struct SaltPasswordOpt {
pub password: String,
}
impl Drop for SaltPasswordOpt {
#[inline]
fn drop(&mut self) {
<String as Clear>::clear(&mut self.salt);
<String as Clear>::clear(&mut self.password);
}
}
#[derive(StructOpt, Debug, Copy, Clone)]
/// WizardOpt
pub struct WizardOpt {}
......@@ -146,14 +155,20 @@ impl DursExecutableCoreCommand for KeysOpt {
}
KeysSubCommand::Modify(modify_opt) => match modify_opt.subcommand {
ModifySubCommand::NetworkSaltPassword(network_opt) => {
let new_keypairs =
modify_network_keys(&network_opt.salt, &network_opt.password, keypairs);
let new_keypairs = modify_network_keys(
network_opt.salt.clone(),
network_opt.password.clone(),
keypairs,
);
save_keypairs(profile_path, &keypairs_file, new_keypairs)
.map_err(DursCoreError::FailWriteKeypairsFile)
}
ModifySubCommand::MemberSaltPassword(member_opt) => {
let new_keypairs =
modify_member_keys(&member_opt.salt, &member_opt.password, keypairs);
let new_keypairs = modify_member_keys(
member_opt.salt.clone(),
member_opt.password.clone(),
keypairs,
);
save_keypairs(profile_path, &keypairs_file, new_keypairs)
.map_err(DursCoreError::FailWriteKeypairsFile)
}
......
......@@ -17,11 +17,12 @@
use crate::errors::CryptoError;
use crate::seeds::Seed48;
use clear_on_drop::clear::Clear;
use std::io::Read;
const CHACHA20_TAG_SIZE: usize = 16;
#[derive(Clone, Copy, Default)]
#[derive(Clone, Default)]
/// Secret key used for encryption algo
pub struct SecretKey {
key: [u8; 32],
......@@ -29,6 +30,15 @@ pub struct SecretKey {
aad: [u8; 4],
}
impl Drop for SecretKey {
#[inline]
fn drop(&mut self) {
self.key.clear();
self.nonce.clear();
self.aad.clear();
}
}
impl SecretKey {
/// Create new secret key
pub fn new(seed: &Seed48) -> SecretKey {
......
......@@ -221,13 +221,6 @@ pub struct Ed25519KeyPair {
pub seed: Seed32,
}
impl Drop for Ed25519KeyPair {
#[inline]
fn drop(&mut self) {
self.seed.clear();
}
}
impl Display for Ed25519KeyPair {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "({}, hidden)", self.pubkey.to_base58())
......@@ -293,6 +286,27 @@ impl KeyPairFromSeed32Generator {
}
}
/// Salted password
pub struct SaltedPassword {
salt: String,
password: String,
}
impl SaltedPassword {
/// Create new salted password
pub fn new(salt: String, password: String) -> SaltedPassword {
SaltedPassword { salt, password }
}
}
impl Drop for SaltedPassword {
#[inline]
fn drop(&mut self) {
<String as Clear>::clear(&mut self.salt);
<String as Clear>::clear(&mut self.password);
}
}
/// Keypair generator with given parameters for `scrypt` keypair function.
#[derive(Copy, Clone)]
pub struct KeyPairFromSaltedPasswordGenerator {
......@@ -329,7 +343,7 @@ impl KeyPairFromSaltedPasswordGenerator {
pub fn generate_seed(&self, password: &[u8], salt: &[u8]) -> Seed32 {
let mut seed = [0u8; 32];
scrypt::scrypt(salt, password, &self.scrypt_params, &mut seed)
scrypt::scrypt(password, salt, &self.scrypt_params, &mut seed)
.expect("dev error: invalid seed len");
Seed32::new(seed)
......@@ -339,9 +353,12 @@ impl KeyPairFromSaltedPasswordGenerator {
///
/// The [`PublicKey`](struct.PublicKey.html) will be able to verify messaged signed with
/// the [`PrivateKey`](struct.PrivateKey.html).
pub fn generate(&self, password: &[u8], salt: &[u8]) -> Ed25519KeyPair {
pub fn generate(&self, salted_password: SaltedPassword) -> Ed25519KeyPair {
// Generate seed from tuple (password + salt)
let seed = self.generate_seed(password, salt);
let seed = self.generate_seed(
salted_password.password.as_bytes(),
salted_password.salt.as_bytes(),
);
// Generate keypair from seed
KeyPairFromSeed32Generator::generate(seed)
}
......@@ -599,8 +616,10 @@ Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
#[test]
fn keypair_generate() {
let key_pair1 = KeyPairFromSaltedPasswordGenerator::with_default_parameters().generate(
"JhxtHB7UcsDbA9wMSyMKXUzBZUQvqVyB32KwzS9SWoLkjrUhHV".as_bytes(),
"JhxtHB7UcsDbA9wMSyMKXUzBZUQvqVyB32KwzS9SWoLkjrUhHV_".as_bytes(),
SaltedPassword::new(
"JhxtHB7UcsDbA9wMSyMKXUzBZUQvqVyB32KwzS9SWoLkjrUhHV".to_owned(),
"JhxtHB7UcsDbA9wMSyMKXUzBZUQvqVyB32KwzS9SWoLkjrUhHV_".to_owned(),
),
);
assert_eq!(
......@@ -610,7 +629,7 @@ Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
let key_pair2 = KeyPairFromSaltedPasswordGenerator::with_parameters(12u8, 16, 1)
.expect("fail to create KeyPairFromSaltedPasswordGenerator: invalid scrypt params.")
.generate(b"toto", b"toto");
.generate(SaltedPassword::new("toto".to_owned(), "toto".to_owned()));
// Test signature display and debug
assert_eq!(
......@@ -630,8 +649,9 @@ Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
#[test]
fn keypair_generate_sign_and_verify() {
let keypair = KeyPairFromSaltedPasswordGenerator::with_default_parameters()
.generate("password".as_bytes(), "salt".as_bytes());
let keypair = KeyPairFromSaltedPasswordGenerator::with_default_parameters().generate(
SaltedPassword::new("password".to_owned(), "salt".to_owned()),
);
let message = "Version: 10
Type: Identity
......
......@@ -22,14 +22,14 @@
//!
//! ```
//! use dup_crypto::keys::{KeyPair, PublicKey, Signator, Signature};
//! use dup_crypto::keys::ed25519::KeyPairFromSaltedPasswordGenerator;
//! use dup_crypto::keys::ed25519::{KeyPairFromSaltedPasswordGenerator, SaltedPassword};
//!
//! let generator = KeyPairFromSaltedPasswordGenerator::with_default_parameters();
//!
//! let keypair = generator.generate(
//! b"password",
//! b"salt"
//! );
//! let keypair = generator.generate(SaltedPassword::new(
//! "salt".to_owned(),
//! "password".to_owned(),
//! ));
//!
//! let signator = keypair.generate_signator().expect("keypair corrupted");
//!
......
......@@ -17,24 +17,34 @@
use crate::bases::*;
use base58::ToBase58;
use clear_on_drop::clear::Clear;
use durs_common_tools::fatal_error;
use log::error;
use ring::rand;
use std::fmt::{self, Debug, Display, Formatter};
/// Store a 48 bytes seed used to generate keys.
#[derive(Clone, Copy)]
pub struct Seed48([u8; 48]);
#[derive(Default)]
pub struct Seed48(InnerSeed48);
struct InnerSeed48([u8; 48]);
impl Default for InnerSeed48 {
fn default() -> Self {
InnerSeed48([0u8; 48])
}
}
impl AsRef<[u8]> for Seed48 {
fn as_ref(&self) -> &[u8] {
&self.0
&(self.0).0
}
}
impl Default for Seed48 {
fn default() -> Self {
Seed48([0u8; 48])
impl Drop for Seed48 {
#[inline]
fn drop(&mut self) {
<InnerSeed48 as Clear>::clear(&mut self.0);
}
}
......@@ -42,7 +52,7 @@ impl Seed48 {
#[inline]
/// Create new seed
pub fn new(seed_bytes: [u8; 48]) -> Seed48 {
Seed48(seed_bytes)
Seed48(InnerSeed48(seed_bytes))
}
#[inline]
/// Generate random seed
......@@ -56,7 +66,7 @@ impl Seed48 {
}
/// Store a 32 bytes seed used to generate keys.
#[derive(Clone, Copy, Default, Deserialize, PartialEq, Eq, Hash, Serialize)]
#[derive(Clone, Default, Deserialize, PartialEq, Eq, Hash, Serialize)]
pub struct Seed32([u8; 32]);
impl AsRef<[u8]> for Seed32 {
......@@ -71,16 +81,22 @@ impl ToBase58 for Seed32 {
}
}
impl Debug for Seed32 {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "Seed32 {{ {} }}", self)
}
}
impl Display for Seed32 {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.to_base58())
}
}
impl Debug for Seed32 {
// Seed32 { DNann1L... }
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "Seed32 {{ {} }}", self)
impl Drop for Seed32 {
#[inline]
fn drop(&mut self) {
<[u8; 32] as Clear>::clear(&mut self.0);
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment