Skip to content

Commit

Permalink
[fix] #4190: Fix seed-based keys generation (#4286)
Browse files Browse the repository at this point in the history
Signed-off-by: Daniil Polyakov <[email protected]>
  • Loading branch information
Arjentix authored Feb 17, 2024
1 parent 9644767 commit fbdd591
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 96 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified configs/swarm/executor.wasm
Binary file not shown.
2 changes: 2 additions & 0 deletions crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ std = [
"signature/std",
"ed25519-dalek/std",
"rand/std",
"rand_core/std",
"rand_chacha/std",
"zeroize/std",
"aead/std",
Expand Down Expand Up @@ -70,6 +71,7 @@ curve25519-dalek = { version = "4.1.1", default-features = false }
x25519-dalek = { version = "2.0.0", default-features = false, features = ["static_secrets"] }

rand = { workspace = true, default-features = false, features = ["std_rng", "alloc"]}
rand_core = { version = "0.6.4", default-features = false, features = ["alloc"]}
rand_chacha = { version = "0.3.1", default-features = false }


Expand Down
48 changes: 10 additions & 38 deletions crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ impl KeyPair {
Self::generate_with_configuration(
KeyGenConfiguration::from_random().with_algorithm(Algorithm::Ed25519),
)
.expect("Ed25519 key generation from random bytes should never fail")
}
}

Expand Down Expand Up @@ -225,28 +224,20 @@ impl KeyPair {
}

/// Generates a pair of Public and Private key with the corresponding [`KeyGenConfiguration`].
///
/// # Errors
///
/// Fails if used [`Secp256k1`](Algorithm::Secp256k1) algorithm with seed less than `32` bytes.
pub fn generate_with_configuration(configuration: KeyGenConfiguration) -> Result<Self, Error> {
let key_gen_option = match (configuration.algorithm, configuration.key_gen_option) {
(Algorithm::Secp256k1, KeyGenOption::UseSeed(seed)) if seed.len() < 32 => {
return Err(Error::KeyGen(
"secp256k1 seed for must be at least 32 bytes long".to_owned(),
))
}
(_, key_gen_option) => key_gen_option,
};

Ok(match configuration.algorithm {
pub fn generate_with_configuration(
KeyGenConfiguration {
key_gen_option,
algorithm,
}: KeyGenConfiguration,
) -> Self {
match algorithm {
Algorithm::Ed25519 => signature::ed25519::Ed25519Sha512::keypair(key_gen_option).into(),
Algorithm::Secp256k1 => {
signature::secp256k1::EcdsaSecp256k1Sha256::keypair(key_gen_option).into()
}
Algorithm::BlsNormal => signature::bls::BlsNormal::keypair(key_gen_option).into(),
Algorithm::BlsSmall => signature::bls::BlsSmall::keypair(key_gen_option).into(),
})
}
}
}

Expand Down Expand Up @@ -894,8 +885,7 @@ mod tests {
] {
let key_pair = KeyPair::generate_with_configuration(
KeyGenConfiguration::from_random().with_algorithm(algorithm),
)
.expect("Failed to generate key pair");
);

assert_eq!(
key_pair,
Expand Down Expand Up @@ -956,8 +946,7 @@ mod tests {
] {
let key_pair = KeyPair::generate_with_configuration(
KeyGenConfiguration::from_random().with_algorithm(algorithm),
)
.expect("Failed to generate key pair");
);
let (public_key, _) = key_pair.into();

let encoded_public_key = public_key.encode();
Expand Down Expand Up @@ -1148,21 +1137,4 @@ mod tests {
}
);
}

#[test]
#[cfg(feature = "rand")]
fn secp256k1_key_gen_fails_with_seed_smaller_than_32() {
let seed: Vec<_> = (0..12u8).collect();

let result = KeyPair::generate_with_configuration(
KeyGenConfiguration::from_seed(seed).with_algorithm(Algorithm::Secp256k1),
);

assert_eq!(
result,
Err(Error::KeyGen(
"secp256k1 seed for must be at least 32 bytes long".to_owned()
))
);
}
}
14 changes: 2 additions & 12 deletions crypto/src/signature/ed25519.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
use core::{borrow::Borrow as _, convert::TryFrom};

use arrayref::array_ref;
use ed25519_dalek::Signature;
#[cfg(feature = "rand")]
use rand::rngs::OsRng;
use rand::SeedableRng;
use rand_chacha::ChaChaRng;
use sha2::Digest;
use signature::{Signer as _, Verifier as _};
use zeroize::Zeroize;

use crate::{Error, KeyGenOption, ParseError};

Expand All @@ -22,16 +17,11 @@ use alloc::{string::ToString as _, vec::Vec};
pub struct Ed25519Sha512;

impl Ed25519Sha512 {
pub fn keypair(mut option: KeyGenOption) -> (PublicKey, PrivateKey) {
pub fn keypair(option: KeyGenOption) -> (PublicKey, PrivateKey) {
let signing_key = match option {
#[cfg(feature = "rand")]
KeyGenOption::Random => PrivateKey::generate(&mut OsRng),
KeyGenOption::UseSeed(ref mut s) => {
let hash = sha2::Sha256::digest(s.as_slice());
s.zeroize();
let mut rng = ChaChaRng::from_seed(*array_ref!(hash.as_slice(), 0, 32));
PrivateKey::generate(&mut rng)
}
KeyGenOption::UseSeed(seed) => PrivateKey::generate(&mut super::rng_from_seed(seed)),
KeyGenOption::FromPrivateKey(ref s) => {
let crate::PrivateKeyInner::Ed25519(s) = s.0.borrow() else {
panic!("Wrong private key type, expected `Ed25519`, got {s:?}")
Expand Down
23 changes: 15 additions & 8 deletions crypto/src/signature/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,26 @@ use core::{borrow::Borrow as _, marker::PhantomData};
#[cfg(feature = "std")]
use std::collections::btree_set;

use arrayref::array_ref;
use derive_more::{Deref, DerefMut};
use iroha_primitives::const_vec::ConstVec;
use iroha_schema::{IntoSchema, TypeId};
use parity_scale_codec::{Decode, Encode};
use rand_core::{CryptoRngCore, SeedableRng as _};
#[cfg(not(feature = "ffi_import"))]
use serde::{Deserialize, Serialize};
use sha2::Digest as _;
use zeroize::Zeroize as _;

use crate::{ffi, Error, HashOf, KeyPair, PublicKey};

/// Construct cryptographic RNG from seed.
fn rng_from_seed(mut seed: Vec<u8>) -> impl CryptoRngCore {
let hash = sha2::Sha256::digest(&seed);
seed.zeroize();
rand_chacha::ChaChaRng::from_seed(*array_ref!(hash.as_slice(), 0, 32))
}

ffi::ffi_item! {
/// Represents signature of the data (`Block` or `Transaction` for example).
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, getset::Getters)]
Expand Down Expand Up @@ -534,8 +545,7 @@ mod tests {
fn create_signature_ed25519() {
let key_pair = KeyPair::generate_with_configuration(
KeyGenConfiguration::from_random().with_algorithm(crate::Algorithm::Ed25519),
)
.expect("Failed to generate key pair.");
);
let message = b"Test message to sign.";
let signature = Signature::new(&key_pair, message);
assert!(*signature.public_key() == *key_pair.public_key());
Expand All @@ -547,8 +557,7 @@ mod tests {
fn create_signature_secp256k1() {
let key_pair = KeyPair::generate_with_configuration(
KeyGenConfiguration::from_random().with_algorithm(crate::Algorithm::Secp256k1),
)
.expect("Failed to generate key pair.");
);
let message = b"Test message to sign.";
let signature = Signature::new(&key_pair, message);
assert!(*signature.public_key() == *key_pair.public_key());
Expand All @@ -560,8 +569,7 @@ mod tests {
fn create_signature_bls_normal() {
let key_pair = KeyPair::generate_with_configuration(
KeyGenConfiguration::from_random().with_algorithm(crate::Algorithm::BlsNormal),
)
.expect("Failed to generate key pair.");
);
let message = b"Test message to sign.";
let signature = Signature::new(&key_pair, message);
assert!(*signature.public_key() == *key_pair.public_key());
Expand All @@ -573,8 +581,7 @@ mod tests {
fn create_signature_bls_small() {
let key_pair = KeyPair::generate_with_configuration(
KeyGenConfiguration::from_random().with_algorithm(crate::Algorithm::BlsSmall),
)
.expect("Failed to generate key pair.");
);
let message = b"Test message to sign.";
let signature = Signature::new(&key_pair, message);
assert!(*signature.public_key() == *key_pair.public_key());
Expand Down
23 changes: 4 additions & 19 deletions crypto/src/signature/secp256k1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use alloc::{format, vec::Vec};
use self::ecdsa_secp256k1::EcdsaSecp256k1Impl;
use crate::{Error, KeyGenOption, ParseError};

pub const PRIVATE_KEY_SIZE: usize = 32;

pub struct EcdsaSecp256k1Sha256;

pub type PublicKey = k256::PublicKey;
Expand Down Expand Up @@ -38,35 +36,22 @@ mod ecdsa_secp256k1 {
use alloc::{format, string::ToString as _, vec::Vec};
use core::borrow::Borrow;

use arrayref::array_ref;
use digest::Digest as _;
#[cfg(feature = "rand")]
use rand::rngs::OsRng;
use rand::{RngCore, SeedableRng};
use rand_chacha::ChaChaRng;
use signature::{Signer as _, Verifier as _};
use zeroize::Zeroize;

use super::{PrivateKey, PublicKey, PRIVATE_KEY_SIZE};
use super::{PrivateKey, PublicKey};
use crate::{Error, KeyGenOption, ParseError};

pub struct EcdsaSecp256k1Impl;
type Digest = sha2::Sha256;

impl EcdsaSecp256k1Impl {
pub fn keypair(mut option: KeyGenOption) -> (PublicKey, PrivateKey) {
pub fn keypair(option: KeyGenOption) -> (PublicKey, PrivateKey) {
let signing_key = match option {
#[cfg(feature = "rand")]
KeyGenOption::Random => PrivateKey::random(&mut OsRng),
KeyGenOption::UseSeed(ref mut seed) => {
let mut s = [0u8; PRIVATE_KEY_SIZE];
let mut rng = ChaChaRng::from_seed(*array_ref!(seed.as_slice(), 0, 32));
seed.zeroize();
rng.fill_bytes(&mut s);
let k = Digest::digest(s);
s.zeroize();
PrivateKey::from_slice(k.as_slice())
.expect("Creating private key from seed should always succeed")
KeyGenOption::UseSeed(seed) => {
PrivateKey::random(&mut super::super::rng_from_seed(seed))
}
KeyGenOption::FromPrivateKey(ref s) => {
let crate::PrivateKeyInner::Secp256k1(s) = s.0.borrow() else {
Expand Down
5 changes: 3 additions & 2 deletions tools/kagami/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ impl Args {
_ => unreachable!("Clap group invariant"),
};

KeyPair::generate_with_configuration(configuration.with_algorithm(algorithm))
.wrap_err("Failed to generate key pair")
Ok(KeyPair::generate_with_configuration(
configuration.with_algorithm(algorithm),
))
}
}

Expand Down
24 changes: 7 additions & 17 deletions tools/swarm/src/compose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ use std::{
};

use color_eyre::eyre::{eyre, Context, ContextCompat};
use iroha_crypto::{
error::Error as IrohaCryptoError, Algorithm, KeyGenConfiguration, KeyPair, PrivateKey,
PublicKey,
};
use iroha_crypto::{Algorithm, KeyGenConfiguration, KeyPair, PrivateKey, PublicKey};
use iroha_data_model::{prelude::PeerId, ChainId};
use iroha_primitives::addr::{socket_addr, SocketAddr};
use peer_generator::Peer;
Expand Down Expand Up @@ -389,8 +386,7 @@ impl DockerComposeBuilder<'_> {
let chain_id = ChainId::from("00000000-0000-0000-0000-000000000000");
let peers = peer_generator::generate_peers(self.peers, self.seed)
.wrap_err("Failed to generate peers")?;
let genesis_key_pair = generate_key_pair(self.seed, GENESIS_KEYPAIR_SEED)
.wrap_err("Failed to generate genesis key pair")?;
let genesis_key_pair = generate_key_pair(self.seed, GENESIS_KEYPAIR_SEED);
let service_source = match &self.image_source {
ResolvedImageSource::Build { path } => {
ServiceSource::Build(path.relative_to(target_file_dir)?)
Expand Down Expand Up @@ -468,10 +464,7 @@ impl DockerComposeBuilder<'_> {
}
}

fn generate_key_pair(
base_seed: Option<&[u8]>,
additional_seed: &[u8],
) -> color_eyre::Result<KeyPair, IrohaCryptoError> {
fn generate_key_pair(base_seed: Option<&[u8]>, additional_seed: &[u8]) -> KeyPair {
let cfg = base_seed.map_or_else(KeyGenConfiguration::from_random, |base| {
let seed: Vec<_> = base.iter().chain(additional_seed).copied().collect();
KeyGenConfiguration::from_seed(seed)
Expand All @@ -483,7 +476,7 @@ fn generate_key_pair(
mod peer_generator {
use std::{collections::BTreeMap, num::NonZeroU16};

use color_eyre::{eyre::Context, Report};
use color_eyre::Report;
use iroha_crypto::KeyPair;
use iroha_data_model::prelude::PeerId;
use iroha_primitives::addr::{SocketAddr, SocketAddrHost};
Expand Down Expand Up @@ -521,8 +514,7 @@ mod peer_generator {
.map(|i| {
let service_name = format!("{BASE_SERVICE_NAME}{i}");

let key_pair = super::generate_key_pair(base_seed, service_name.as_bytes())
.wrap_err("Failed to generate key pair")?;
let key_pair = super::generate_key_pair(base_seed, service_name.as_bytes());

let peer = Peer {
name: service_name.clone(),
Expand Down Expand Up @@ -648,8 +640,7 @@ mod tests {
let key_pair =
KeyPair::generate_with_configuration(KeyGenConfiguration::from_seed(vec![
1, 5, 1, 2, 2, 3, 4, 1, 2, 3,
]))
.unwrap();
]));

map.insert(
"iroha0".to_owned(),
Expand Down Expand Up @@ -721,8 +712,7 @@ mod tests {
let chain_id = ChainId::from("00000000-0000-0000-0000-000000000000");

let key_pair =
KeyPair::generate_with_configuration(KeyGenConfiguration::from_seed(vec![0, 1, 2]))
.unwrap();
KeyPair::generate_with_configuration(KeyGenConfiguration::from_seed(vec![0, 1, 2]));

let env: FullPeerEnv = CompactPeerEnv {
chain_id,
Expand Down

0 comments on commit fbdd591

Please sign in to comment.