From f83ef1b2b6c8cec796781eb6eec1112ef81a7920 Mon Sep 17 00:00:00 2001 From: Eyal Kalderon Date: Fri, 4 May 2018 16:52:41 +0800 Subject: [PATCH] Add support for custom RNGs in SSS and WrappedSecrets (#64) --- Cargo.toml | 1 + src/sss/mod.rs | 36 +++++++++++++++++++++++- src/sss/scheme.rs | 17 +++++++---- src/wrapped_secrets/mod.rs | 53 ++++++++++++++++++++++++++++++++++- src/wrapped_secrets/scheme.rs | 6 ++-- 5 files changed, 103 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54491f9..6b5581b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ default-features = false itertools = "^0.7" quickcheck = "^0.4" flate2 = "^0.2" +rand = "^0.4.2" [profile.bench] opt-level = 3 diff --git a/src/sss/mod.rs b/src/sss/mod.rs index 7709d1b..20505ea 100644 --- a/src/sss/mod.rs +++ b/src/sss/mod.rs @@ -13,11 +13,14 @@ pub(crate) use self::scheme::*; mod encode; +use rand::{OsRng, Rng}; use ring::digest::{Algorithm, SHA512}; static HASH_ALGO: &'static Algorithm = &SHA512; /// Performs threshold k-out-of-n Shamir's secret sharing. /// +/// Uses a `rand::OsRng` as a source of entropy. +/// /// # Examples /// /// ``` @@ -37,7 +40,38 @@ static HASH_ALGO: &'static Algorithm = &SHA512; /// ``` pub fn split_secret(k: u8, n: u8, secret: &[u8], sign_shares: bool) -> Result> { SSS::default() - .split_secret(k, n, secret, sign_shares) + .split_secret(&mut OsRng::new()?, k, n, secret, sign_shares) + .map(|shares| shares.into_iter().map(Share::into_string).collect()) +} + +/// Performs threshold k-out-of-n Shamir's secret sharing with a custom RNG. +/// +/// # Examples +/// +/// ``` +/// use rusty_secrets::sss::split_secret; +/// +/// let secret = "These programs were never about terrorism: they’re about economic spying, \ +/// social control, and diplomatic manipulation. They’re about power."; +/// +/// match split_secret(7, 10, &secret.as_bytes(), true) { +/// Ok(shares) => { +/// // Do something with the shares +/// }, +/// Err(_) => { +/// // Deal with error +/// } +/// } +/// ``` +pub fn split_secret_rng( + rng: &mut R, + k: u8, + n: u8, + secret: &[u8], + sign_shares: bool, +) -> Result> { + SSS::default() + .split_secret(rng, k, n, secret, sign_shares) .map(|shares| shares.into_iter().map(Share::into_string).collect()) } diff --git a/src/sss/scheme.rs b/src/sss/scheme.rs index 836bec6..3cbc8e6 100644 --- a/src/sss/scheme.rs +++ b/src/sss/scheme.rs @@ -1,7 +1,7 @@ //! SSS provides Shamir's secret sharing with raw data. use merkle_sigs::sign_data_vec; -use rand::{OsRng, Rng}; +use rand::Rng; use errors::*; use lagrange::interpolate_at; @@ -17,15 +17,16 @@ pub(crate) struct SSS; impl SSS { /// Performs threshold k-out-of-n Shamir's secret sharing. - pub fn split_secret( + pub fn split_secret( &self, + rng: &mut R, threshold: u8, shares_count: u8, secret: &[u8], sign_shares: bool, ) -> Result> { let (threshold, shares_count) = validate_share_count(threshold, shares_count)?; - let shares = Self::secret_share(secret, threshold, shares_count)?; + let shares = Self::secret_share(rng, secret, threshold, shares_count)?; let signatures = if sign_shares { let shares_to_sign = shares @@ -67,19 +68,23 @@ impl SSS { Ok(result.collect()) } - fn secret_share(src: &[u8], threshold: u8, shares_count: u8) -> Result>> { + fn secret_share( + rng: &mut R, + src: &[u8], + threshold: u8, + shares_count: u8, + ) -> Result>> { let mut result = Vec::with_capacity(shares_count as usize); for _ in 0..(shares_count as usize) { result.push(vec![0u8; src.len()]); } let mut col_in = vec![0u8; threshold as usize]; let mut col_out = Vec::with_capacity(shares_count as usize); - let mut osrng = OsRng::new()?; for (c, &s) in src.iter().enumerate() { col_in[0] = s; // NOTE: switch to `try_fill_bytes` when it lands in a stable release: // https://github.com/rust-lang-nursery/rand/commit/230b2258dbd99ff8bd991008c972d923d4b5d10c - osrng.fill_bytes(&mut col_in[1..]); + rng.fill_bytes(&mut col_in[1..]); col_out.clear(); encode_secret_byte(&*col_in, shares_count, &mut col_out)?; for (&y, share) in col_out.iter().zip(result.iter_mut()) { diff --git a/src/wrapped_secrets/mod.rs b/src/wrapped_secrets/mod.rs index 3a797fd..5be7e08 100644 --- a/src/wrapped_secrets/mod.rs +++ b/src/wrapped_secrets/mod.rs @@ -3,11 +3,15 @@ use errors::*; use proto::wrapped::SecretProto; +use rand::{OsRng, Rng}; + mod scheme; pub(crate) use self::scheme::*; /// Performs threshold k-out-of-n Shamir's secret sharing. /// +/// Uses an `OsRng` as a source of entropy. +/// /// # Examples /// /// ``` @@ -41,7 +45,54 @@ pub fn split_secret( sign_shares: bool, ) -> Result> { WrappedSecrets::default() - .split_secret(k, n, secret, mime_type, sign_shares) + .split_secret(&mut OsRng::new()?, k, n, secret, mime_type, sign_shares) + .map(|shares| shares.into_iter().map(Share::into_string).collect()) +} + +/// Performs threshold k-out-of-n Shamir's secret sharing with a custom RNG. +/// +/// # Examples +/// +/// ``` +/// # extern crate rusty_secrets; +/// # extern crate rand; +/// # +/// # fn main() { +/// use rusty_secrets::wrapped_secrets::split_secret_rng; +/// use rand::ChaChaRng; +/// +/// let secret = "These programs were never about terrorism: they’re about economic spying, \ +/// social control, and diplomatic manipulation. They’re about power."; +/// +/// let result = split_secret_rng( +/// &mut ChaChaRng::new_unseeded(), +/// 7, +/// 10, +/// &secret.as_bytes(), +/// Some("text/html".to_string()), +/// true, +/// ); +/// +/// match result { +/// Ok(shares) => { +/// // Do something with the shares +/// }, +/// Err(_) => { +/// // Deal with error +/// } +/// } +/// # } +/// ``` +pub fn split_secret_rng( + rng: &mut R, + k: u8, + n: u8, + secret: &[u8], + mime_type: Option, + sign_shares: bool, +) -> Result> { + WrappedSecrets::default() + .split_secret(rng, k, n, secret, mime_type, sign_shares) .map(|shares| shares.into_iter().map(Share::into_string).collect()) } diff --git a/src/wrapped_secrets/scheme.rs b/src/wrapped_secrets/scheme.rs index f3a5896..a704e39 100644 --- a/src/wrapped_secrets/scheme.rs +++ b/src/wrapped_secrets/scheme.rs @@ -3,6 +3,7 @@ use proto::VersionProto; use proto::wrapped::SecretProto; use protobuf; use protobuf::Message; +use rand::Rng; use sss::SSS; pub(crate) use sss::Share; @@ -12,8 +13,9 @@ pub(crate) struct WrappedSecrets; impl WrappedSecrets { /// Performs threshold k-out-of-n Shamir's secret sharing. - pub fn split_secret( + pub fn split_secret( &self, + rng: &mut R, k: u8, n: u8, secret: &[u8], @@ -30,7 +32,7 @@ impl WrappedSecrets { let data = rusty_secret.write_to_bytes().unwrap(); - SSS::default().split_secret(k, n, data.as_slice(), sign_shares) + SSS::default().split_secret(rng, k, n, data.as_slice(), sign_shares) } /// Recovers the secret from a k-out-of-n Shamir's secret sharing.