diff --git a/Cargo.lock b/Cargo.lock index dd1f3de45ae6800100ae7e5786f33ce738e69147..a5834ffc9984ee27ff69fcddc4201fa4a6f7d5e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,6 +173,14 @@ name = "cfg-if" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chacha20-poly1305-aead" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "chrono" version = "0.4.7" @@ -463,6 +471,7 @@ dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "chacha20-poly1305-aead 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "durs-common-tools 0.2.0", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2185,6 +2194,7 @@ dependencies = [ "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum chacha20-poly1305-aead 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77d2058ba29594f69c75e8a9018e0485e3914ca5084e3613cd64529042f5423b" "checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" diff --git a/lib/core/conf/src/keys.rs b/lib/core/conf/src/keys.rs index 1fd36b91371071cd35cf3d05886c889fbc4898ef..6d58de07e01422e847d99712a2e0215198682b0c 100644 --- a/lib/core/conf/src/keys.rs +++ b/lib/core/conf/src/keys.rs @@ -184,7 +184,7 @@ mod tests { fn test_modify_member_keys() { let key_pairs = DuniterKeyPairs { network_keypair: KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair { - seed: Seed::from_base58(BASE58_SEED_INIT) + seed: Seed32::from_base58(BASE58_SEED_INIT) .expect("conf : keypairs file : fail to parse network_seed !"), pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT) .expect("conf : keypairs file : fail to parse network_pub !"), @@ -202,7 +202,7 @@ mod tests { ); assert_eq!( result_key_pairs.network_keypair.seed().clone(), - Seed::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_INIT"), + Seed32::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_INIT"), ); // We expect member key to update as intended @@ -224,7 +224,7 @@ mod tests { .unwrap() .seed() .clone(), - Seed::from_base58(BASE58_SEED_TEST).expect("Wrong data in BASE58_SEED_TEST"), + Seed32::from_base58(BASE58_SEED_TEST).expect("Wrong data in BASE58_SEED_TEST"), ); } @@ -232,7 +232,7 @@ mod tests { fn test_modify_network_keys() { let key_pairs = DuniterKeyPairs { network_keypair: KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair { - seed: Seed::from_base58(BASE58_SEED_INIT) + seed: Seed32::from_base58(BASE58_SEED_INIT) .expect("conf : keypairs file : fail to parse network_seed !"), pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT) .expect("conf : keypairs file : fail to parse network_pub !"), @@ -250,7 +250,7 @@ mod tests { ); assert_eq!( result_key_pairs.network_keypair.seed().clone(), - Seed::from_base58(BASE58_SEED_TEST).expect("Wrong data in BASE58_SEED_TEST") + Seed32::from_base58(BASE58_SEED_TEST).expect("Wrong data in BASE58_SEED_TEST") ); // We expect member key not to change assert_eq!(result_key_pairs.member_keypair, None); @@ -260,13 +260,13 @@ mod tests { fn test_clear_network_keys() { let key_pairs = DuniterKeyPairs { network_keypair: KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair { - seed: Seed::from_base58(BASE58_SEED_INIT) + seed: Seed32::from_base58(BASE58_SEED_INIT) .expect("conf : keypairs file : fail to parse network_seed !"), pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT) .expect("conf : keypairs file : fail to parse network_pub !"), }), member_keypair: Some(KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair { - seed: Seed::from_base58(BASE58_SEED_INIT) + seed: Seed32::from_base58(BASE58_SEED_INIT) .expect("conf : keypairs file : fail to parse network_seed !"), pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT) .expect("conf : keypairs file : fail to parse network_pub !"), @@ -283,7 +283,7 @@ mod tests { ); assert_ne!( result_key_pairs.network_keypair.seed().clone(), - Seed::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_TEST") + Seed32::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_TEST") ); // We expect member key not to change @@ -305,7 +305,7 @@ mod tests { .unwrap() .seed() .clone(), - Seed::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_TEST") + Seed32::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_TEST") ); } @@ -313,13 +313,13 @@ mod tests { fn test_clear_member_keys() { let key_pairs = DuniterKeyPairs { network_keypair: KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair { - seed: Seed::from_base58(BASE58_SEED_INIT) + seed: Seed32::from_base58(BASE58_SEED_INIT) .expect("conf : keypairs file : fail to parse network_seed !"), pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT) .expect("conf : keypairs file : fail to parse network_pub !"), }), member_keypair: Some(KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair { - seed: Seed::from_base58(BASE58_SEED_INIT) + seed: Seed32::from_base58(BASE58_SEED_INIT) .expect("conf : keypairs file : fail to parse network_seed !"), pubkey: ed25519::PublicKey::from_base58(BASE58_PUB_INIT) .expect("conf : keypairs file : fail to parse network_pub !"), @@ -336,7 +336,7 @@ mod tests { ); assert_eq!( result_key_pairs.network_keypair.seed().clone(), - Seed::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_TEST") + Seed32::from_base58(BASE58_SEED_INIT).expect("Wrong data in BASE58_SEED_TEST") ); // We expect member key to change diff --git a/lib/core/conf/src/lib.rs b/lib/core/conf/src/lib.rs index 4a41a3a9c78e61130399c8012f533737d7001925..a1be993233a161bf80268e6d7d0d423e4aff3c63 100644 --- a/lib/core/conf/src/lib.rs +++ b/lib/core/conf/src/lib.rs @@ -557,7 +557,7 @@ pub fn load_conf_at_path( .as_str() .expect("Conf: Fail to parse keypairs file !"); let network_keypair = KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair { - seed: Seed::from_base58(network_seed) + seed: Seed32::from_base58(network_seed) .expect("conf : keypairs file : fail to parse network_seed !"), pubkey: ed25519::PublicKey::from_base58(network_pub) .expect("conf : keypairs file : fail to parse network_pub !"), @@ -576,7 +576,7 @@ pub fn load_conf_at_path( None } else { Some(KeyPairEnum::Ed25519(ed25519::Ed25519KeyPair { - seed: Seed::from_base58(member_seed).expect( + seed: Seed32::from_base58(member_seed).expect( "conf : keypairs file : fail to parse member_seed !", ), pubkey: ed25519::PublicKey::from_base58(member_pub).expect( diff --git a/lib/crypto/Cargo.toml b/lib/crypto/Cargo.toml index b51bda46cf4cdcc9b833fa0360bec1d17b02d28e..71be3ccc165d43cf6445a5f443cd997bcda2fc28 100644 --- a/lib/crypto/Cargo.toml +++ b/lib/crypto/Cargo.toml @@ -16,6 +16,7 @@ path = "src/lib.rs" base58 = "0.1.*" base64 = "0.10.*" byteorder = "1.2.3" +chacha20-poly1305-aead = "0.1.2" clear_on_drop = "0.2.3" failure = "0.1.5" ring = "0.16.5" diff --git a/lib/crypto/src/agreement.rs b/lib/crypto/src/agreement.rs new file mode 100644 index 0000000000000000000000000000000000000000..6c6b824674f379c45a8b443140cef6a64b7ac4c5 --- /dev/null +++ b/lib/crypto/src/agreement.rs @@ -0,0 +1,125 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +//! Manage cryptographic agreement operations. + +use crate::errors::CryptoError; +use ring::{agreement, digest, pbkdf2, rand}; +use std::num::NonZeroU32; + +const SHARED_SECRET_LEN: usize = digest::SHA384_OUTPUT_LEN; +const ITERATIONS: u32 = 3; + +static PBKDF2_ALG: pbkdf2::Algorithm = pbkdf2::PBKDF2_HMAC_SHA384; + +#[derive(Clone)] +/// Ephemeral public key used once to generate shared secret +pub struct EphemeralPublicKey(agreement::PublicKey); + +impl AsRef<[u8]> for EphemeralPublicKey { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +/// Ephemeral key pair used once to generate shared secret +pub struct EphemeralKeyPair { + privkey: agreement::EphemeralPrivateKey, + pubkey: EphemeralPublicKey, +} + +impl EphemeralKeyPair { + /// Generate ephemeral key pair + pub fn generate() -> Result<Self, CryptoError> { + let rng = rand::SystemRandom::new(); + let privkey = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng) + .map_err(|_| CryptoError::FailToGenEphemerKeyPair)?; + let pubkey = EphemeralPublicKey( + privkey + .compute_public_key() + .map_err(|_| CryptoError::FailToGenEphemerPubKey)?, + ); + + Ok(EphemeralKeyPair { privkey, pubkey }) + } + /// Get ephemeral public key + pub fn public_key(&self) -> &EphemeralPublicKey { + &self.pubkey + } + /// Compute shared secret + pub fn compute_shared_secret( + self, + other_ephemeral_public_key: &EphemeralPublicKey, + server: bool, + ) -> Result<[u8; SHARED_SECRET_LEN], CryptoError> { + let salt = if server { + self.pubkey.as_ref() + } else { + other_ephemeral_public_key.as_ref() + }; + + agreement::agree_ephemeral( + self.privkey, + &agreement::UnparsedPublicKey::new( + &agreement::X25519, + other_ephemeral_public_key.as_ref(), + ), + CryptoError::FailToComputeAgreement, + |key_material| Ok(derive(key_material, salt)), + ) + } +} + +fn derive(seed: &[u8], salt: &[u8]) -> [u8; SHARED_SECRET_LEN] { + let mut store_credentials: [u8; SHARED_SECRET_LEN] = [0u8; SHARED_SECRET_LEN]; + pbkdf2::derive( + PBKDF2_ALG, + NonZeroU32::new(ITERATIONS).expect("ITERATIONS must be > 0"), + salt, + seed, + &mut store_credentials, + ); + store_credentials +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_exchange_dh() -> Result<(), CryptoError> { + let ephemeral_kp_server = EphemeralKeyPair::generate()?; + let ephemeral_kp_client = EphemeralKeyPair::generate()?; + + let ephemeral_pk_server = ephemeral_kp_server.public_key().clone(); + let ephemeral_pk_client = ephemeral_kp_client.public_key().clone(); + + let shared_secret_server = + ephemeral_kp_server.compute_shared_secret(&ephemeral_kp_client.public_key(), true)?; + + let shared_secret_client = + ephemeral_kp_client.compute_shared_secret(&ephemeral_pk_server, false)?; + + assert_eq!(shared_secret_server.to_vec(), shared_secret_client.to_vec()); + + println!("ephemeral_pk_server={:?}", ephemeral_pk_server.as_ref()); + println!("ephemeral_pk_client={:?}", ephemeral_pk_client.as_ref()); + println!("shared_secret_server={:?}", shared_secret_server.to_vec()); + println!("shared_secret_client={:?}", shared_secret_client.to_vec()); + //panic!(); + Ok(()) + } +} diff --git a/lib/crypto/src/encryption.rs b/lib/crypto/src/encryption.rs new file mode 100644 index 0000000000000000000000000000000000000000..881d1e5842c8e717d468e74ed1b0092ec1cfb72b --- /dev/null +++ b/lib/crypto/src/encryption.rs @@ -0,0 +1,133 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +//! Manage cryptographic encryption operations. + +use crate::errors::CryptoError; +use crate::seeds::Seed48; +use std::io::Read; + +const CHACHA20_TAG_SIZE: usize = 16; + +#[derive(Clone, Copy, Default)] +/// Secret key used for encryption algo +pub struct SecretKey { + key: [u8; 32], + nonce: [u8; 12], + aad: [u8; 4], +} + +impl SecretKey { + /// Create new secret key + pub fn new(seed: &Seed48) -> SecretKey { + let mut secret_key = SecretKey::default(); + + secret_key.key.copy_from_slice(&seed.as_ref()[0..32]); + secret_key.nonce.copy_from_slice(&seed.as_ref()[32..44]); + secret_key.aad.copy_from_slice(&seed.as_ref()[44..48]); + + secret_key + } +} + +/// Decrypt datas +pub fn decrypt(encrypted_datas: &[u8], secret_key: &SecretKey) -> Result<Vec<u8>, CryptoError> { + let payload_len = encrypted_datas.len() - CHACHA20_TAG_SIZE; + + let mut decrypted_datas = Vec::with_capacity(payload_len); + + chacha20_poly1305_aead::decrypt( + &secret_key.key, + &secret_key.nonce, + &secret_key.aad, + &encrypted_datas[0..payload_len], + &encrypted_datas[payload_len..], + &mut decrypted_datas, + ) + .map_err(CryptoError::FailToDecryptDatas)?; + + Ok(decrypted_datas) +} + +/// Encrypt datas +pub fn encrypt(datas: &[u8], secret_key: &SecretKey) -> Result<Vec<u8>, CryptoError> { + let mut encrypted_datas = Vec::with_capacity(datas.len() + CHACHA20_TAG_SIZE); + + let tag = chacha20_poly1305_aead::encrypt( + &secret_key.key, + &secret_key.nonce, + &secret_key.aad, + datas, + &mut encrypted_datas, + ) + .map_err(CryptoError::FailToEncryptDatas)?; + + encrypted_datas.append(&mut tag.to_vec()); + + Ok(encrypted_datas) +} + +/// Encrypt datas from reader +pub fn encrypt_read<R: Read>( + datas_max_size: usize, + reader: &mut R, + secret_key: &SecretKey, +) -> Result<Vec<u8>, CryptoError> { + let mut encrypted_datas = Vec::with_capacity(datas_max_size + CHACHA20_TAG_SIZE); + + let tag = chacha20_poly1305_aead::encrypt_read( + &secret_key.key, + &secret_key.nonce, + &secret_key.aad, + reader, + &mut encrypted_datas, + ) + .map_err(CryptoError::FailToEncryptDatas)?; + + encrypted_datas.append(&mut tag.to_vec()); + + Ok(encrypted_datas) +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_encryption() -> Result<(), CryptoError> { + let datas = b"My secret datas".to_vec(); + + let secret_key = SecretKey::new(&Seed48::random()); + + let encrypted_datas = encrypt(&datas, &secret_key)?; + let decrypted_datas = decrypt(&encrypted_datas, &secret_key)?; + + println!("encrypted_datas={:?}", encrypted_datas); + println!("decrypted_datas={:?}", decrypted_datas); + + assert_eq!(datas, decrypted_datas); + + let encrypted_datas = encrypt_read(datas.len(), &mut &datas[..], &secret_key)?; + let decrypted_datas = decrypt(&encrypted_datas, &secret_key)?; + + println!("encrypted_datas={:?}", encrypted_datas); + println!("decrypted_datas={:?}", decrypted_datas); + + assert_eq!(datas, decrypted_datas); + + Ok(()) + } +} diff --git a/lib/crypto/src/errors.rs b/lib/crypto/src/errors.rs new file mode 100644 index 0000000000000000000000000000000000000000..9d4b43db1a70f760037ad853534e765832ac2b76 --- /dev/null +++ b/lib/crypto/src/errors.rs @@ -0,0 +1,31 @@ +// Copyright (C) 2017-2019 The AXIOM TEAM Association. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +//! Manage cryptographic errors. + +#[derive(Debug)] +/// Cryptographic error +pub enum CryptoError { + /// Fail to compute agreement + FailToComputeAgreement, + /// Fail to decrypt datas + FailToDecryptDatas(chacha20_poly1305_aead::DecryptError), + /// Fail to encrypt datas + FailToEncryptDatas(std::io::Error), + /// Fail to generate ephemeral key pair + FailToGenEphemerKeyPair, + /// Fail to generate ephemeral public key + FailToGenEphemerPubKey, +} diff --git a/lib/crypto/src/keys/bin_signable.rs b/lib/crypto/src/keys/bin_signable.rs index 23ed48f15b38b472b700f797fbc2a39dcb1868dc..7ae96fb108f110564b45cc299a3610e5cfd2135d 100644 --- a/lib/crypto/src/keys/bin_signable.rs +++ b/lib/crypto/src/keys/bin_signable.rs @@ -116,7 +116,7 @@ mod tests { #[test] fn test_bin_signable() { - let key_pair = ed25519::KeyPairFromSeedGenerator::generate(Seed::new([ + let key_pair = ed25519::KeyPairFromSeed32Generator::generate(Seed32::new([ 0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ])); diff --git a/lib/crypto/src/keys/ed25519.rs b/lib/crypto/src/keys/ed25519.rs index 1803fdac244312af6d7f0f236873723ed2adfe72..ec63172a04b9e28939f29f8445e3c13f523021b3 100644 --- a/lib/crypto/src/keys/ed25519.rs +++ b/lib/crypto/src/keys/ed25519.rs @@ -19,9 +19,9 @@ //! //! [`KeyPairGenerator`]: struct.KeyPairGenerator.html -use super::seed::Seed; use super::PublicKey as PublicKeyMethods; use crate::bases::*; +use crate::seeds::Seed32; use base58::ToBase58; use base64; use clear_on_drop::clear::Clear; @@ -218,7 +218,7 @@ pub struct Ed25519KeyPair { /// Store a Ed25519 public key. pub pubkey: PublicKey, /// Store a seed of 32 bytes. - pub seed: Seed, + pub seed: Seed32, } impl Drop for Ed25519KeyPair { @@ -254,7 +254,7 @@ impl super::KeyPair for Ed25519KeyPair { self.pubkey } - fn seed(&self) -> &Seed { + fn seed(&self) -> &Seed32 { &self.seed } @@ -270,20 +270,20 @@ impl super::KeyPair for Ed25519KeyPair { impl Ed25519KeyPair { /// Generate random keypair pub fn generate_random() -> Self { - KeyPairFromSeedGenerator::generate(Seed::random()) + KeyPairFromSeed32Generator::generate(Seed32::random()) } } /// Keypair generator with seed #[derive(Debug, Copy, Clone)] -pub struct KeyPairFromSeedGenerator {} +pub struct KeyPairFromSeed32Generator {} -impl KeyPairFromSeedGenerator { +impl KeyPairFromSeed32Generator { /// Create a keypair based on a given seed. /// /// The [`PublicKey`](struct.PublicKey.html) will be able to verify messaged signed with /// the [`PrivateKey`](struct.PrivateKey.html). - pub fn generate(seed: Seed) -> Ed25519KeyPair { + pub fn generate(seed: Seed32) -> Ed25519KeyPair { let ring_key_pair = RingKeyPair::from_seed_unchecked(seed.as_ref()) .expect("dev error: fail to generate ed25519 keypair."); Ed25519KeyPair { @@ -326,13 +326,13 @@ impl KeyPairFromSaltedPasswordGenerator { } /// Create a seed based on a given password and salt. - pub fn generate_seed(&self, password: &[u8], salt: &[u8]) -> Seed { + pub fn generate_seed(&self, password: &[u8], salt: &[u8]) -> Seed32 { let mut seed = [0u8; 32]; scrypt::scrypt(salt, password, &self.scrypt_params, &mut seed) .expect("dev error: invalid seed len"); - Seed::new(seed) + Seed32::new(seed) } /// Create a keypair based on a given password and salt. @@ -343,14 +343,15 @@ impl KeyPairFromSaltedPasswordGenerator { // Generate seed from tuple (password + salt) let seed = self.generate_seed(password, salt); // Generate keypair from seed - KeyPairFromSeedGenerator::generate(seed) + KeyPairFromSeed32Generator::generate(seed) } } #[cfg(test)] mod tests { use super::*; - use crate::keys::{KeyPair, Seed, Sig, Signator, Signature}; + use crate::keys::{KeyPair, Sig, Signator, Signature}; + use crate::seeds::Seed32; use base58::FromBase58; use bincode; use std::collections::hash_map::DefaultHasher; @@ -360,7 +361,7 @@ mod tests { let seed58 = "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"; // Test base58 encoding/decoding (loop for every bytes) - let seed = Seed::from_base58(seed58).expect("fail to parser seed !"); + let seed = Seed32::from_base58(seed58).expect("fail to parser seed !"); assert_eq!(seed.to_base58(), seed58); // Test seed display and debug @@ -369,40 +370,40 @@ mod tests { format!("{}", seed) ); assert_eq!( - "Seed { DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV }".to_owned(), + "Seed32 { DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV }".to_owned(), format!("{:?}", seed) ); // Test seed equality let same_seed = seed.clone(); - let other_seed = Seed::default(); + let other_seed = Seed32::default(); assert!(seed.eq(&same_seed)); assert!(!seed.eq(&other_seed)); // Test seed parsing assert_eq!( - Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLVgth",).unwrap_err(), + Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLVgth",).unwrap_err(), BaseConvertionError::InvalidLength { found: 35, expected: 32 } ); assert_eq!( - Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd",).unwrap_err(), + Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd",).unwrap_err(), BaseConvertionError::InvalidLength { found: 31, expected: 32 } ); assert_eq!( - Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd<<").unwrap_err(), + Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd<<").unwrap_err(), BaseConvertionError::InvalidCharacter { character: '<', offset: 42 } ); assert_eq!( - Seed::from_base58( + Seed32::from_base58( "\ DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV\ @@ -561,7 +562,7 @@ mod tests { #[test] fn message_sign_verify() { - let seed = Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(); + let seed = Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(); let expected_signature = super::Signature::from_base64( "9ARKYkEAwp+kQ01rgvWUwJLchVLpZvHg3t/3H32XwWOoG119NiVCtfPSPtR4GDOeOz6Y+29drOLahqhzy+ciBw==", @@ -576,7 +577,7 @@ UniqueID: tic Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 "; - let signator = KeyPairFromSeedGenerator::generate(seed) + let signator = KeyPairFromSeed32Generator::generate(seed) .generate_signator() .expect("fail to generate signator !"); let pubkey = signator.public_key(); @@ -619,7 +620,7 @@ Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 // Test key_pair equality let same_key_pair = key_pair2.clone(); - let other_key_pair = KeyPairFromSeedGenerator::generate(Seed::new([ + let other_key_pair = KeyPairFromSeed32Generator::generate(Seed32::new([ 0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ])); diff --git a/lib/crypto/src/keys/mod.rs b/lib/crypto/src/keys/mod.rs index c4ab3fd63aeca427aec9858db7f57ae2c9465ca6..05016379c7d2d245b99813d1ec68aac7ce745cef 100644 --- a/lib/crypto/src/keys/mod.rs +++ b/lib/crypto/src/keys/mod.rs @@ -50,10 +50,9 @@ pub mod bin_signable; pub mod ed25519; -pub mod seed; pub mod text_signable; -pub use seed::Seed; +pub use crate::seeds::Seed32; use crate::bases::BaseConvertionError; use base58::ToBase58; @@ -325,8 +324,8 @@ pub trait KeyPair: Clone + Display + Debug + PartialEq + Eq { /// Get `PublicKey` fn public_key(&self) -> <Self::Signator as Signator>::PublicKey; - /// Get `Seed` - fn seed(&self) -> &Seed; + /// Get `Seed32` + fn seed(&self) -> &Seed32; /// Verify a signature with public key. fn verify( @@ -398,7 +397,7 @@ impl KeyPair for KeyPairEnum { KeyPairEnum::Schnorr() => fatal_error!("Schnorr algo not yet supported !"), } } - fn seed(&self) -> &Seed { + fn seed(&self) -> &Seed32 { match *self { KeyPairEnum::Ed25519(ref ed25519_keypair) => &ed25519_keypair.seed(), KeyPairEnum::Schnorr() => fatal_error!("Schnorr algo not yet supported !"), @@ -454,14 +453,14 @@ impl Signator for SignatorEnum { mod tests { use super::*; - use crate::hashs::Hash; - use ring::{agreement, rand}; pub fn valid_key_pair_1() -> KeyPairEnum { - KeyPairEnum::Ed25519(ed25519::KeyPairFromSeedGenerator::generate(Seed::new([ - 59u8, 106, 39, 188, 206, 182, 164, 45, 98, 163, 168, 208, 42, 111, 13, 115, 101, 50, - 21, 119, 29, 226, 67, 166, 58, 192, 72, 161, 139, 89, 218, 41, - ]))) + KeyPairEnum::Ed25519(ed25519::KeyPairFromSeed32Generator::generate(Seed32::new( + [ + 59u8, 106, 39, 188, 206, 182, 164, 45, 98, 163, 168, 208, 42, 111, 13, 115, 101, + 50, 21, 119, 29, 226, 67, 166, 58, 192, 72, 161, 139, 89, 218, 41, + ], + ))) } #[test] @@ -526,18 +525,18 @@ mod tests { #[test] fn seed() { - let seed_default = Seed::default(); + let seed_default = Seed32::default(); let seed_bytes = [ 0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; let seed_str_b58 = "11111111111111111111111111111111".to_owned(); - let seed = Seed::new(seed_bytes); + let seed = Seed32::new(seed_bytes); assert_eq!(seed_default, seed); assert_eq!( seed_default, - Seed::from_base58(&seed_str_b58).expect("Fail to parse seed !") + Seed32::from_base58(&seed_str_b58).expect("Fail to parse seed !") ); assert_eq!(seed_str_b58, format!("{}", seed)); @@ -546,7 +545,7 @@ mod tests { } fn false_key_pair_ed25519() -> ed25519::Ed25519KeyPair { - ed25519::KeyPairFromSeedGenerator::generate(Seed::new([ + ed25519::KeyPairFromSeed32Generator::generate(Seed32::new([ 0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ])) @@ -692,48 +691,4 @@ mod tests { let signator = SignatorEnum::Schnorr(); signator.sign(b"message"); } - - #[test] - fn test_exchange_dh() -> Result<(), ring::error::Unspecified> { - let rng = rand::SystemRandom::new(); - - let secret_key_1 = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?; - let public_key_1 = secret_key_1.compute_public_key()?; - - let secret_key_2 = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?; - let public_key_2 = secret_key_2.compute_public_key()?; - - let dh1 = agreement::agree_ephemeral( - secret_key_1, - &agreement::UnparsedPublicKey::new(&agreement::X25519, &public_key_2), - ring::error::Unspecified, - |key_material| { - // In a real application, we'd apply a KDF to the key material and the - // public keys (as recommended in RFC 7748) and then derive session - // keys from the result. - Ok(Hash::compute(key_material)) - }, - )?; - - let dh2 = agreement::agree_ephemeral( - secret_key_2, - &agreement::UnparsedPublicKey::new(&agreement::X25519, &public_key_1), - ring::error::Unspecified, - |key_material| { - // In a real application, we'd apply a KDF to the key material and the - // public keys (as recommended in RFC 7748) and then derive session - // keys from the result. - Ok(Hash::compute(key_material)) - }, - )?; - - assert_eq!(dh1, dh2); - - println!("pk1={:?}", public_key_1); - println!("pk2={:?}", public_key_2); - println!("shared_secret1={:?}", dh1); - println!("shared_secret2={:?}", dh2); - //panic!(); - Ok(()) - } } diff --git a/lib/crypto/src/lib.rs b/lib/crypto/src/lib.rs index 3a02fca5b94eebb3660f1613be02584fae5f09fc..9ce42463b96b9df4ef26d738e13e938fd11adb11 100644 --- a/lib/crypto/src/lib.rs +++ b/lib/crypto/src/lib.rs @@ -36,7 +36,11 @@ extern crate serde_derive; #[macro_use] extern crate log; +pub mod agreement; pub mod bases; +pub mod encryption; +pub mod errors; pub mod hashs; pub mod keys; pub mod rand; +pub mod seeds; diff --git a/lib/crypto/src/rand/mod.rs b/lib/crypto/src/rand.rs similarity index 100% rename from lib/crypto/src/rand/mod.rs rename to lib/crypto/src/rand.rs diff --git a/lib/crypto/src/keys/seed.rs b/lib/crypto/src/seeds.rs similarity index 59% rename from lib/crypto/src/keys/seed.rs rename to lib/crypto/src/seeds.rs index bb56fc05092bf4fe64181c289b185cac8be22bc3..2d26bb200e99f1cb65e0c3b391db9c55d83bff79 100644 --- a/lib/crypto/src/keys/seed.rs +++ b/lib/crypto/src/seeds.rs @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. -//! Provide wrappers around cryptographic seed +//! Provide wrappers around cryptographic seeds use crate::bases::*; use base58::ToBase58; @@ -22,51 +22,84 @@ 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]); + +impl AsRef<[u8]> for Seed48 { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl Default for Seed48 { + fn default() -> Self { + Seed48([0u8; 48]) + } +} + +impl Seed48 { + #[inline] + /// Create new seed + pub fn new(seed_bytes: [u8; 48]) -> Seed48 { + Seed48(seed_bytes) + } + #[inline] + /// Generate random seed + pub fn random() -> Seed48 { + if let Ok(random_bytes) = rand::generate::<[u8; 48]>(&rand::SystemRandom::new()) { + Seed48::new(random_bytes.expose()) + } else { + fatal_error!("System error: fail to generate random seed !") + } + } +} + /// Store a 32 bytes seed used to generate keys. #[derive(Clone, Copy, Default, Deserialize, PartialEq, Eq, Hash, Serialize)] -pub struct Seed([u8; 32]); +pub struct Seed32([u8; 32]); -impl AsRef<[u8]> for Seed { +impl AsRef<[u8]> for Seed32 { fn as_ref(&self) -> &[u8] { &self.0 } } -impl ToBase58 for Seed { +impl ToBase58 for Seed32 { fn to_base58(&self) -> String { self.0.to_base58() } } -impl Display for Seed { +impl Display for Seed32 { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { write!(f, "{}", self.to_base58()) } } -impl Debug for Seed { - // Seed { DNann1L... } +impl Debug for Seed32 { + // Seed32 { DNann1L... } fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { - write!(f, "Seed {{ {} }}", self) + write!(f, "Seed32 {{ {} }}", self) } } -impl Seed { +impl Seed32 { #[inline] /// Create new seed - pub fn new(seed_bytes: [u8; 32]) -> Seed { - Seed(seed_bytes) + pub fn new(seed_bytes: [u8; 32]) -> Seed32 { + Seed32(seed_bytes) } #[inline] /// Create seed from base58 str pub fn from_base58(base58_str: &str) -> Result<Self, BaseConvertionError> { - Ok(Seed::new(b58::str_base58_to_32bytes(base58_str)?)) + Ok(Seed32::new(b58::str_base58_to_32bytes(base58_str)?)) } #[inline] /// Generate random seed - pub fn random() -> Seed { + pub fn random() -> Seed32 { if let Ok(random_bytes) = rand::generate::<[u8; 32]>(&rand::SystemRandom::new()) { - Seed::new(random_bytes.expose()) + Seed32::new(random_bytes.expose()) } else { fatal_error!("System error: fail to generate random seed !") } @@ -80,6 +113,6 @@ mod tests { #[test] fn test_gen_random_seed() { - assert_ne!(Seed::random(), Seed::random()); + assert_ne!(Seed32::random(), Seed32::random()); } } diff --git a/lib/dubp/user-docs/src/documents/certification/v10.rs b/lib/dubp/user-docs/src/documents/certification/v10.rs index 797f20d7c4278b10032c027cdf1e3cf0020e4cf2..2df8cf9835360dbf4d49ac688e5c7d4663a289d4 100644 --- a/lib/dubp/user-docs/src/documents/certification/v10.rs +++ b/lib/dubp/user-docs/src/documents/certification/v10.rs @@ -339,8 +339,8 @@ mod tests { #[test] fn generate_real_certification_document() { - let seed = Seed::from_base58("4tNQ7d9pj2Da5wUVoW9mFn7JjuPoowF977au8DdhEjVR").unwrap(); - let keypair = ed25519::KeyPairFromSeedGenerator::generate(seed); + let seed = Seed32::from_base58("4tNQ7d9pj2Da5wUVoW9mFn7JjuPoowF977au8DdhEjVR").unwrap(); + let keypair = ed25519::KeyPairFromSeed32Generator::generate(seed); let pubkey = PubKey::Ed25519(keypair.public_key()); let signator = SignatorEnum::Ed25519(keypair.generate_signator().expect("fail to gen signator")); diff --git a/lib/dubp/user-docs/src/documents/identity/v10.rs b/lib/dubp/user-docs/src/documents/identity/v10.rs index e0b3b73443dd0eac8c3cea6c3ac40d25bd048270..d652eb4122d85daee1001a3450c1be3f353fe550 100644 --- a/lib/dubp/user-docs/src/documents/identity/v10.rs +++ b/lib/dubp/user-docs/src/documents/identity/v10.rs @@ -272,8 +272,8 @@ mod tests { #[test] fn generate_real_document() { - let keypair = ed25519::KeyPairFromSeedGenerator::generate( - Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(), + let keypair = ed25519::KeyPairFromSeed32Generator::generate( + Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(), ); let pubkey = PubKey::Ed25519(keypair.public_key()); let signator = diff --git a/lib/dubp/user-docs/src/documents/membership/v10.rs b/lib/dubp/user-docs/src/documents/membership/v10.rs index da31a8b39a69212e53b56afd037b9fbff8db6724..54e68431a8065abe29fe3ec3baeeac83186beda0 100644 --- a/lib/dubp/user-docs/src/documents/membership/v10.rs +++ b/lib/dubp/user-docs/src/documents/membership/v10.rs @@ -335,8 +335,8 @@ mod tests { #[test] fn generate_real_document() { - let keypair = ed25519::KeyPairFromSeedGenerator::generate( - Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(), + let keypair = ed25519::KeyPairFromSeed32Generator::generate( + Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(), ); let pubkey = PubKey::Ed25519(keypair.public_key()); let signator = diff --git a/lib/dubp/user-docs/src/documents/revocation/v10.rs b/lib/dubp/user-docs/src/documents/revocation/v10.rs index f222c982dd44e2407811c673d18783d7535cafcc..23e02782894a9e206593924a91ad7ade546a879c 100644 --- a/lib/dubp/user-docs/src/documents/revocation/v10.rs +++ b/lib/dubp/user-docs/src/documents/revocation/v10.rs @@ -303,8 +303,8 @@ mod tests { #[test] fn generate_real_document() { - let keypair = ed25519::KeyPairFromSeedGenerator::generate( - Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(), + let keypair = ed25519::KeyPairFromSeed32Generator::generate( + Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(), ); let pubkey = PubKey::Ed25519(keypair.public_key()); let signator = diff --git a/lib/dubp/user-docs/src/documents/transaction.rs b/lib/dubp/user-docs/src/documents/transaction.rs index 23d579b31de2bdb17819a3a7bf021f6df403f720..d8e787dc63d8d1df9bfed0173d8c7ed97d37dbd4 100644 --- a/lib/dubp/user-docs/src/documents/transaction.rs +++ b/lib/dubp/user-docs/src/documents/transaction.rs @@ -951,8 +951,8 @@ mod tests { #[test] fn generate_real_document() { - let keypair = ed25519::KeyPairFromSeedGenerator::generate( - Seed::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(), + let keypair = ed25519::KeyPairFromSeed32Generator::generate( + Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(), ); let pubkey = PubKey::Ed25519(keypair.public_key()); let signator = diff --git a/lib/dunp/network-documents/src/lib.rs b/lib/dunp/network-documents/src/lib.rs index 2cd0d00f91bf70c4130d8e82dcf0ec9f572c842d..5dca0bd4efce3c2d2546196122a1fc2091425c5b 100644 --- a/lib/dunp/network-documents/src/lib.rs +++ b/lib/dunp/network-documents/src/lib.rs @@ -160,11 +160,11 @@ mod tests { use super::*; pub fn keypair1() -> ed25519::Ed25519KeyPair { - let seed = Seed::new([ + let seed = Seed32::new([ 61u8, 245, 136, 162, 155, 50, 205, 43, 116, 15, 45, 84, 138, 54, 114, 214, 71, 213, 11, 251, 135, 182, 202, 131, 48, 91, 166, 226, 40, 255, 251, 172, ]); - ed25519::KeyPairFromSeedGenerator::generate(seed) + ed25519::KeyPairFromSeed32Generator::generate(seed) } #[test] diff --git a/lib/modules/ws2p/ws2p-messages/lib.rs b/lib/modules/ws2p/ws2p-messages/lib.rs index 76669500d92b38b0e261120dbcbb0b8500999bac..adbb46a2a785486b6e21e75f79ba5e2f9ff20f62 100644 --- a/lib/modules/ws2p/ws2p-messages/lib.rs +++ b/lib/modules/ws2p/ws2p-messages/lib.rs @@ -175,11 +175,11 @@ mod tests { use std::str::FromStr; pub fn keypair1() -> ed25519::Ed25519KeyPair { - let seed = Seed::new([ + let seed = Seed32::new([ 228, 125, 124, 120, 57, 212, 246, 250, 139, 246, 62, 26, 56, 241, 175, 123, 151, 209, 5, 106, 2, 148, 43, 101, 118, 160, 233, 7, 112, 222, 0, 169, ]); - ed25519::KeyPairFromSeedGenerator::generate(seed) + ed25519::KeyPairFromSeed32Generator::generate(seed) } pub fn create_endpoint_v11() -> EndpointV2 { diff --git a/lib/modules/ws2p/ws2p/tests/connection_negociation.rs b/lib/modules/ws2p/ws2p/tests/connection_negociation.rs index 0d7f5d7439aff45eb72b7775123ba8f4d80341de..6bd46cd9652bedcd72bb68d7f0f7604b31b7cdad 100644 --- a/lib/modules/ws2p/ws2p/tests/connection_negociation.rs +++ b/lib/modules/ws2p/ws2p/tests/connection_negociation.rs @@ -40,19 +40,19 @@ pub fn currency() -> CurrencyName { } pub fn keypair1() -> ed25519::Ed25519KeyPair { - let seed = Seed::new([ + let seed = Seed32::new([ 61u8, 245, 136, 162, 155, 50, 205, 43, 116, 15, 45, 84, 138, 54, 114, 214, 71, 213, 11, 251, 135, 182, 202, 131, 48, 91, 166, 226, 40, 255, 251, 172, ]); - ed25519::KeyPairFromSeedGenerator::generate(seed) + ed25519::KeyPairFromSeed32Generator::generate(seed) } pub fn keypair2() -> ed25519::Ed25519KeyPair { - let seed = Seed::new([ + let seed = Seed32::new([ 228, 125, 124, 120, 57, 212, 246, 250, 139, 246, 62, 26, 56, 241, 175, 123, 151, 209, 5, 106, 2, 148, 43, 101, 118, 160, 233, 7, 112, 222, 0, 169, ]); - ed25519::KeyPairFromSeedGenerator::generate(seed) + ed25519::KeyPairFromSeed32Generator::generate(seed) } fn server_node() -> MySelfWs2pNode {