diff --git a/.travis.yml b/.travis.yml index 4e22e71..74d1c30 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,11 @@ -addons: - apt: - packages: - - libcurl4-openssl-dev - - libelf-dev - - libdw-dev + language: rust -before_script: - - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH - -script: - - | - travis-cargo build && - travis-cargo test -after_success: - - travis-cargo coveralls --no-sudo +rust: + - stable + - beta + - nightly +matrix: + allow_failures: + - rust: nightly diff --git a/Cargo.lock b/Cargo.lock index f28d870..0af6ed7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,20 +1,20 @@ [root] name = "rusty_secrets" -version = "0.0.2" +version = "0.0.3" dependencies = [ - "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "getopts" -version = "0.2.14" +name = "libc" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "libc" -version = "0.2.9" +name = "protobuf" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -22,11 +22,16 @@ name = "rand" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-serialize" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" +[metadata] +"checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8" +"checksum protobuf 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec4c2fe04370298218a09ab53a534febf54c160c5554e4de987b6d73c916d5d" +"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5" +"checksum rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818" diff --git a/Cargo.toml b/Cargo.toml index 8c261b4..8c7c284 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,24 +1,14 @@ [package] name = "rusty_secrets" -version = "0.0.2" +version = "0.0.3" authors = ["Frederic Jacobs ", "sellibitze"] description = "Implementation of threshold Shamir secret sharing in the Rust programming language." homepage = "https://github.com/freedomofpress/RustySecrets" -license = "GPL-3.0" +license = "BSD-3-Clause" readme = "README.md" build = "build.rs" [dependencies] -getopts = "^0.2.14" rustc-serialize = "^0.3.18" rand = "^0.3.14" - -[lib] -name = "rusty_secrets" -path = "src/lib/mod.rs" -crate_type = ["rlib"] - -[[bin]] -name = "rusty_secrets_bin" -path = "src/main.rs" -doc = false +[dependencies.protobuf] diff --git a/README.md b/README.md index b4e6330..d39a4bc 100644 --- a/README.md +++ b/README.md @@ -49,27 +49,7 @@ A share is built out of three parts separated with a dash: K-N-D. - N is the identifier of the share and varies between 1 and n where n is the total number of generated shares. - The D part is a Base64 encoding of a specific share's raw data. -### Command-line encoding - -Passing a secret to rustysecrets for encoding: - -``` -$ echo My secret | ./rusty_secrets_bin -e2,5 -2-1-1YAYwmOHqZ69jA -2-2-YJZQDGm22Y77Gw -2-3-+G9ovW9SAnUynQ -2-4-F7rAjX3UOa53KA -2-5-j0P4PHsw4lW+rg -``` - -The parameters following the `-e` option tell rustysecrets to create 5 shares of which 2 will be necessary for decoding. - -Decoding a subset of shares (one share per line) can be done like this: - -``` -$ echo -e "2-2-YJZQDGm22Y77Gw \n 2-4-F7rAjX3UOa53KA" | ./rusty_secrets_bin -d -My secret -``` +// TODO: Rewrite documentation to match current implementation ## Vocabulary diff --git a/protobuf/ShareData.proto b/protobuf/ShareData.proto new file mode 100644 index 0000000..82af023 --- /dev/null +++ b/protobuf/ShareData.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +message ShareData { + bytes shamirData = 1; + bytes signature = 2; + bytes proof = 3; +} + diff --git a/src/ShareDataMod.rs b/src/ShareDataMod.rs new file mode 100644 index 0000000..3b4a23b --- /dev/null +++ b/src/ShareDataMod.rs @@ -0,0 +1,356 @@ +// This file is generated. Do not edit +// @generated + +// https://github.com/Manishearth/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy)] + +#![cfg_attr(rustfmt, rustfmt_skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unsafe_code)] +#![allow(unused_imports)] +#![allow(unused_results)] + +use protobuf::Message as Message_imported_for_functions; +use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; + +#[derive(Clone,Default)] +pub struct ShareData { + // message fields + shamirData: ::protobuf::SingularField<::std::vec::Vec>, + signature: ::protobuf::SingularField<::std::vec::Vec>, + proof: ::protobuf::SingularField<::std::vec::Vec>, + // special fields + unknown_fields: ::protobuf::UnknownFields, + cached_size: ::std::cell::Cell, +} + +// see codegen.rs for the explanation why impl Sync explicitly +unsafe impl ::std::marker::Sync for ShareData {} + +impl ShareData { + pub fn new() -> ShareData { + ::std::default::Default::default() + } + + pub fn default_instance() -> &'static ShareData { + static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ShareData, + }; + unsafe { + instance.get(|| { + ShareData { + shamirData: ::protobuf::SingularField::none(), + signature: ::protobuf::SingularField::none(), + proof: ::protobuf::SingularField::none(), + unknown_fields: ::protobuf::UnknownFields::new(), + cached_size: ::std::cell::Cell::new(0), + } + }) + } + } + + // optional bytes shamirData = 1; + + pub fn clear_shamirData(&mut self) { + self.shamirData.clear(); + } + + pub fn has_shamirData(&self) -> bool { + self.shamirData.is_some() + } + + // Param is passed by value, moved + pub fn set_shamirData(&mut self, v: ::std::vec::Vec) { + self.shamirData = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_shamirData(&mut self) -> &mut ::std::vec::Vec { + if self.shamirData.is_none() { + self.shamirData.set_default(); + }; + self.shamirData.as_mut().unwrap() + } + + // Take field + pub fn take_shamirData(&mut self) -> ::std::vec::Vec { + self.shamirData.take().unwrap_or_else(|| ::std::vec::Vec::new()) + } + + pub fn get_shamirData(&self) -> &[u8] { + match self.shamirData.as_ref() { + Some(v) => &v, + None => &[], + } + } + + // optional bytes signature = 2; + + pub fn clear_signature(&mut self) { + self.signature.clear(); + } + + pub fn has_signature(&self) -> bool { + self.signature.is_some() + } + + // Param is passed by value, moved + pub fn set_signature(&mut self, v: ::std::vec::Vec) { + self.signature = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_signature(&mut self) -> &mut ::std::vec::Vec { + if self.signature.is_none() { + self.signature.set_default(); + }; + self.signature.as_mut().unwrap() + } + + // Take field + pub fn take_signature(&mut self) -> ::std::vec::Vec { + self.signature.take().unwrap_or_else(|| ::std::vec::Vec::new()) + } + + pub fn get_signature(&self) -> &[u8] { + match self.signature.as_ref() { + Some(v) => &v, + None => &[], + } + } + + // optional bytes proof = 3; + + pub fn clear_proof(&mut self) { + self.proof.clear(); + } + + pub fn has_proof(&self) -> bool { + self.proof.is_some() + } + + // Param is passed by value, moved + pub fn set_proof(&mut self, v: ::std::vec::Vec) { + self.proof = ::protobuf::SingularField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_proof(&mut self) -> &mut ::std::vec::Vec { + if self.proof.is_none() { + self.proof.set_default(); + }; + self.proof.as_mut().unwrap() + } + + // Take field + pub fn take_proof(&mut self) -> ::std::vec::Vec { + self.proof.take().unwrap_or_else(|| ::std::vec::Vec::new()) + } + + pub fn get_proof(&self) -> &[u8] { + match self.proof.as_ref() { + Some(v) => &v, + None => &[], + } + } +} + +impl ::protobuf::Message for ShareData { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream) -> ::protobuf::ProtobufResult<()> { + while !try!(is.eof()) { + let (field_number, wire_type) = try!(is.read_tag_unpack()); + match field_number { + 1 => { + try!(::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.shamirData)); + }, + 2 => { + try!(::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.signature)); + }, + 3 => { + try!(::protobuf::rt::read_singular_bytes_into(wire_type, is, &mut self.proof)); + }, + _ => { + try!(::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())); + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + for value in &self.shamirData { + my_size += ::protobuf::rt::bytes_size(1, &value); + }; + for value in &self.signature { + my_size += ::protobuf::rt::bytes_size(2, &value); + }; + for value in &self.proof { + my_size += ::protobuf::rt::bytes_size(3, &value); + }; + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream) -> ::protobuf::ProtobufResult<()> { + if let Some(v) = self.shamirData.as_ref() { + try!(os.write_bytes(1, &v)); + }; + if let Some(v) = self.signature.as_ref() { + try!(os.write_bytes(2, &v)); + }; + if let Some(v) = self.proof.as_ref() { + try!(os.write_bytes(3, &v)); + }; + try!(os.write_unknown_fields(self.get_unknown_fields())); + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn type_id(&self) -> ::std::any::TypeId { + ::std::any::TypeId::of::() + } + + fn as_any(&self) -> &::std::any::Any { + self as &::std::any::Any + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + ::protobuf::MessageStatic::descriptor_static(None::) + } +} + +impl ::protobuf::MessageStatic for ShareData { + fn new() -> ShareData { + ShareData::new() + } + + fn descriptor_static(_: ::std::option::Option) -> &'static ::protobuf::reflect::MessageDescriptor { + static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, + }; + unsafe { + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor( + "shamirData", + ShareData::has_shamirData, + ShareData::get_shamirData, + )); + fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor( + "signature", + ShareData::has_signature, + ShareData::get_signature, + )); + fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor( + "proof", + ShareData::has_proof, + ShareData::get_proof, + )); + ::protobuf::reflect::MessageDescriptor::new::( + "ShareData", + fields, + file_descriptor_proto() + ) + }) + } + } +} + +impl ::protobuf::Clear for ShareData { + fn clear(&mut self) { + self.clear_shamirData(); + self.clear_signature(); + self.clear_proof(); + self.unknown_fields.clear(); + } +} + +impl ::std::cmp::PartialEq for ShareData { + fn eq(&self, other: &ShareData) -> bool { + self.shamirData == other.shamirData && + self.signature == other.signature && + self.proof == other.proof && + self.unknown_fields == other.unknown_fields + } +} + +impl ::std::fmt::Debug for ShareData { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +static file_descriptor_proto_data: &'static [u8] = &[ + 0x0a, 0x0f, 0x53, 0x68, 0x61, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x5f, 0x0a, 0x09, 0x53, 0x68, 0x61, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1e, + 0x0a, 0x0a, 0x73, 0x68, 0x61, 0x6d, 0x69, 0x72, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x68, 0x61, 0x6d, 0x69, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1c, + 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x4a, 0xfc, 0x01, 0x0a, 0x06, 0x12, 0x04, 0x00, 0x00, 0x06, 0x01, 0x0a, 0x08, 0x0a, + 0x01, 0x0c, 0x12, 0x03, 0x00, 0x00, 0x12, 0x0a, 0x0a, 0x0a, 0x02, 0x04, 0x00, 0x12, 0x04, 0x02, + 0x00, 0x06, 0x01, 0x0a, 0x0a, 0x0a, 0x03, 0x04, 0x00, 0x01, 0x12, 0x03, 0x02, 0x08, 0x11, 0x0a, + 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x00, 0x12, 0x03, 0x03, 0x08, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, + 0x04, 0x00, 0x02, 0x00, 0x04, 0x12, 0x04, 0x03, 0x08, 0x02, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, + 0x00, 0x02, 0x00, 0x05, 0x12, 0x03, 0x03, 0x08, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, + 0x00, 0x01, 0x12, 0x03, 0x03, 0x0e, 0x18, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x00, 0x03, + 0x12, 0x03, 0x03, 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, 0x00, 0x02, 0x01, 0x12, 0x03, 0x04, + 0x08, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x04, 0x12, 0x04, 0x04, 0x08, 0x03, + 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x05, 0x12, 0x03, 0x04, 0x08, 0x0d, 0x0a, + 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x01, 0x01, 0x12, 0x03, 0x04, 0x0e, 0x17, 0x0a, 0x0c, 0x0a, + 0x05, 0x04, 0x00, 0x02, 0x01, 0x03, 0x12, 0x03, 0x04, 0x1b, 0x1c, 0x0a, 0x0b, 0x0a, 0x04, 0x04, + 0x00, 0x02, 0x02, 0x12, 0x03, 0x05, 0x08, 0x1d, 0x0a, 0x0d, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, + 0x04, 0x12, 0x04, 0x05, 0x08, 0x04, 0x1d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x05, + 0x12, 0x03, 0x05, 0x08, 0x0d, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x01, 0x12, 0x03, + 0x05, 0x0e, 0x13, 0x0a, 0x0c, 0x0a, 0x05, 0x04, 0x00, 0x02, 0x02, 0x03, 0x12, 0x03, 0x05, 0x1b, + 0x1c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +]; + +static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { + lock: ::protobuf::lazy::ONCE_INIT, + ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, +}; + +fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { + ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() +} + +pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + unsafe { + file_descriptor_proto_lazy.get(|| { + parse_descriptor_proto() + }) + } +} diff --git a/src/lib/custom_error.rs b/src/custom_error.rs similarity index 100% rename from src/lib/custom_error.rs rename to src/custom_error.rs diff --git a/src/lib/gf256.rs b/src/gf256.rs similarity index 100% rename from src/lib/gf256.rs rename to src/gf256.rs diff --git a/src/lib/mod.rs b/src/lib.rs similarity index 86% rename from src/lib/mod.rs rename to src/lib.rs index 783fcb3..21966c4 100644 --- a/src/lib/mod.rs +++ b/src/lib.rs @@ -1,19 +1,24 @@ +extern crate protobuf; extern crate rustc_serialize as serialize; extern crate rand; -use self::rand::{ Rng, OsRng }; -use self::serialize::base64::{ self, FromBase64, ToBase64 }; +use rand::{ Rng, OsRng }; +use serialize::base64::{ self, FromBase64, ToBase64 }; mod gf256; -use self::gf256::Gf256; +use gf256::Gf256; use std::io; use std::iter::repeat; /// Generate generic errors that typeset with `io::Error`. pub mod custom_error; -use self::custom_error::*; +use custom_error::*; +use protobuf::Message; + +mod ShareDataMod; +pub use ShareDataMod::{ShareData}; /// Performs threshold k-out-of-n Shamir secret sharing. /// @@ -30,7 +35,6 @@ use self::custom_error::*; /// Err(_) => {}// Deal with error} /// } /// ``` - pub fn generate_shares(k: u8, n: u8, secret: &[u8]) -> io::Result> { if k > n { return Err(other_io_err("Threshold K can not be larger than N", None)); @@ -44,8 +48,11 @@ pub fn generate_shares(k: u8, n: u8, secret: &[u8]) -> io::Result> { let mut result = Vec::with_capacity(n as usize); - for (index, share) in shares.iter().enumerate() { - let b64_share = share.to_base64(config); + for (index, share) in shares.into_iter().enumerate() { + let mut share_protobuf = ShareData::new(); + share_protobuf.set_shamirData(share); + + let b64_share = share_protobuf.write_to_bytes().unwrap().to_base64(config); let string = format!("{}-{}-{}", k, index+1, b64_share); result.push(string); } @@ -73,10 +80,16 @@ fn process_shares(shares_strings: Vec) -> io::Result<(u8, Vec<(u8, Vec(raw_data.as_slice()) + .map_err(|_| other_io_err("Share parse error: Protobuffer could not be decoded.", None ))); + let data = Vec::from(protobuf_data.get_shamirData()); + if let Some((ck, cl)) = opt_k_l { if ck != k || cl != data.len() { return Err(other_io_err("Incompatible shares", None)); @@ -110,8 +123,8 @@ fn process_shares(shares_strings: Vec) -> io::Result<(u8, Vec<(u8, Vec expressions that takes -// a &'static str as error message as 2nd parameter -// and creates an Error out of it if necessary. -macro_rules! otry { - ($o:expr, $e:expr) => ( - match $o { - Some(thing_) => thing_, - None => return Err(convert::From::from(Error::new($e, None))) - } - ) -} - -fn main() { - let mut stderr = io::stderr(); - let args: Vec = env::args().collect(); - - let mut opts = Options::new(); - opts.optflag("h", "help", "print this help text"); - opts.optflag("d", "decode", "for decoding"); - opts.optopt("e", "encode", "for encoding, K is the required number of \ - shares for decoding, N is the number of shares \ - to generate. 1 <= K <= N <= 255", "K,N"); - let opt_matches = match opts.parse(&args[1..]) { - Ok(m) => m, - Err(f) => { - drop(writeln!(&mut stderr, "Error: {}", f)); - process::exit(1); - } - }; - - if args.len() < 2 || opt_matches.opt_present("h") { - println!( -"The program rustysecrets is an implementation of Shamir's secret sharing scheme.\n\ - It is applied byte-wise within a finite field for arbitrarily long secrets.\n"); - println!("{}", opts.usage("Usage: rustysecrets [options]")); - println!("Input is read from STDIN and output is written to STDOUT."); - return; - } - - let action: Result<_,_> = - match (opt_matches.opt_present("e"), opt_matches.opt_present("d")) { - (false, false) => Err("Nothing to do! Use -e or -d"), - (true, true) => Err("Use either -e or -d and not both"), - (false, true) => Ok(Action::Decode), - (true, false) => { - if let Some(param) = opt_matches.opt_str("e") { - if let Ok((k,n)) = parse_k_n(&*param) { - if 0 < k && k <= n { - Ok(Action::Encode(k,n)) - } else { - Err("Invalid encoding parameters K,N") - } - } else { - Err("Could not parse K,N parameters") - } - } else { - Err("No parameter for -e or -d provided") - } - } - }; - - let result = - match action { - Ok(Action::Encode(k,n)) => perform_encode_from_io(k, n), - Ok(Action::Decode) => perform_decode_from_io(), - Err(e) => Err(other_io_err(e, None)) - }; - - if let Err(e) = result { - drop(writeln!(&mut stderr, "{}", e)); - process::exit(1); - } -} - -fn perform_encode_from_io(k: u8, n: u8) -> io::Result<()> { - let secret = { - let limit: usize = 0x10000; - let stdin = io::stdin(); - let mut locked = stdin.lock(); - let mut tmp: Vec = Vec::new(); - try!(locked.by_ref().take(limit as u64).read_to_end(&mut tmp)); - if tmp.len() == limit { - let mut dummy = [0u8]; - if try!(locked.read(&mut dummy)) > 0 { - return Err(other_io_err("Secret too large", - Some(format!("My limit is at {} bytes.", limit)))); - } - } - tmp.pop(); - tmp - }; - match lib::generate_shares(k, n, &secret) { - Ok(shares) => { - for share in shares {println!("{:?}", share)}; - } - Err(e) => { return Err(e) as io::Result<()>; } - } - - return Ok(()) as io::Result<()>; -} - -fn perform_decode_from_io() -> io::Result<()> { - let stdin = io::stdin(); - let stdin = io::BufReader::new(stdin.lock()); - let mut shares: Vec = Vec::new(); - - for line in stdin.lines() { - match line { - Ok(share) => shares.push(share), - Err(_) => {} - } - } - - return match lib::recover_secret(shares) { - Ok(secret) => { - let mut out = io::stdout(); - try!(out.write_all(&*secret)); - out.flush() - } - Err(e) => {Err(e) as io::Result<()>} - }; -} - -fn parse_k_n(s: &str) -> io::Result<(u8, u8)> { - let mut iter = s.split(','); - let msg = "K and N have to be separated with a comma"; - let s1 = otry!(iter.next(), msg).trim(); - let s2 = otry!(iter.next(), msg).trim(); - let k = try!(s1.parse().map_err(pie2io)); - let n = try!(s2.parse().map_err(pie2io)); - Ok((k, n)) -} diff --git a/tests/generation-errors.rs b/tests/generation_errors.rs similarity index 100% rename from tests/generation-errors.rs rename to tests/generation_errors.rs diff --git a/tests/lib.rs b/tests/randomized_tests.rs similarity index 100% rename from tests/lib.rs rename to tests/randomized_tests.rs diff --git a/tests/recovery-errors.rs b/tests/recovery_errors.rs similarity index 64% rename from tests/recovery-errors.rs rename to tests/recovery_errors.rs index f1c6012..46fd711 100644 --- a/tests/recovery-errors.rs +++ b/tests/recovery_errors.rs @@ -2,15 +2,6 @@ extern crate rusty_secrets; use rusty_secrets::{recover_secret}; -#[test] -#[should_panic(expected = "Not enough shares provided!")] -fn test_recover_sellibitze_missing_share() { - let share1 = "2-1-1YAYwmOHqZ69jA".to_string(); - let shares = vec![share1]; - - recover_secret(shares).unwrap(); -} - #[test] #[should_panic(expected = "Not enough shares provided!")] fn test_recover_sellibitze_no_shares() { @@ -21,8 +12,8 @@ fn test_recover_sellibitze_no_shares() { #[test] #[should_panic(expected = "Share parse error: Expected 3 parts separated by a minus sign")] fn test_recover_2_parts_share() { - let share1 = "2-1-1YAYwmOHqZ69jA".to_string(); - let share2 = "2-F7rAjX3UOa53KA".to_string(); + let share1 = "2-1-CgmKQZHMO+5n5pU".to_string(); + let share2 = "2-2".to_string(); let shares = vec![share1, share2]; @@ -32,8 +23,8 @@ fn test_recover_2_parts_share() { #[test] #[should_panic(expected = "Integer parsing error")] fn test_recover_incorrect_share_num() { - let share1 = "2-1-1YAYwmOHqZ69jA".to_string(); - let share2 = "2-DEFINITLY_NAN-YJZQDGm22Y77Gw".to_string(); + let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); + let share2 = "2-DEFINITLY_NAN-CgkAnUgP3lfwjyM".to_string(); let shares = vec![share1, share2]; @@ -54,7 +45,7 @@ fn test_recover_0_share_num() { #[test] #[should_panic(expected = "Share parse error: Base64 decoding of data block failed")] fn test_recover_invalid_b64() { - let share1 = "2-5-j0P4PHsw4lW+rg".to_string(); + let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); let share2 = "2-1-YJZQDG((((m22Y)))77Gw".to_string(); let shares = vec![share1, share2]; @@ -65,8 +56,8 @@ fn test_recover_invalid_b64() { #[test] #[should_panic(expected = "Incompatible shares")] fn test_recover_invalid_b64_size() { - let share1 = "2-5-j0P4PHsw4lW+rg".to_string(); - let share2 = "2-1-YJZQDGm22Y77GwZ69jA".to_string(); + let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); + let share2 = "3-5-Cgl/3sS13REq2X8".to_string(); let shares = vec![share1, share2]; @@ -76,8 +67,8 @@ fn test_recover_invalid_b64_size() { #[test] #[should_panic(expected = "Duplicate Share Number")] fn test_recover_duplicate_shares_number() { - let share1 = "2-1-1YAYwmOHqZ69jA".to_string(); - let share2 = "2-1-j0P4PHsw4lW+rg".to_string(); + let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); + let share2 = "2-1-CgkAnUgP3lfwjyM".to_string(); let shares = vec![share1, share2]; @@ -87,8 +78,8 @@ fn test_recover_duplicate_shares_number() { #[test] #[should_panic(expected = "Duplicate Share Data")] fn test_recover_duplicate_shares_data() { - let share1 = "2-2-YJZQDGm22Y77Gw".to_string(); - let share2 = "2-3-YJZQDGm22Y77Gw".to_string(); + let share1 = "2-1-CgnlCxRNtnkzENE".to_string(); + let share2 = "2-2-CgnlCxRNtnkzENE".to_string(); let shares = vec![share1, share2]; @@ -98,8 +89,8 @@ fn test_recover_duplicate_shares_data() { #[test] #[should_panic(expected = "Not enough shares provided!")] fn test_recover_too_few_shares() { - let share1 = "5-1-DbuicpLQiCf7bVWiAz8eCpQGpdZmYQ7z2j2+g351tWFLOQPTZkXY8BYfwGGGjkOoz1g9x0ScmLFcWk+2tign".to_string(); - let share2 = "5-2-nShdfkY5+SlfybMyqjHXCZ01bq5N/0Lkf0nQZw5x3bnHIEVfa0RA4YcJ4SjG/UdpgO/gOcyLRkSp2Dwf8bvw".to_string(); + let share1 = "3-1-ChbcCdSZOaMn6DM1jFca2P6/0WRlP7AK".to_string(); + let share2 = "3-2-ChbG46L1zRszs0PPn63XnnupmZTcgYJ3".to_string(); let shares = vec![share1, share2]; diff --git a/tests/test_vectors.rs b/tests/test_vectors.rs index f310bc0..034de0a 100644 --- a/tests/test_vectors.rs +++ b/tests/test_vectors.rs @@ -1,13 +1,35 @@ extern crate rusty_secrets; +extern crate protobuf; +extern crate rustc_serialize as serialize; +use serialize::base64::{ self, FromBase64, ToBase64 }; -use rusty_secrets::{recover_secret}; +use protobuf::Message; +#[cfg(test)] +use rusty_secrets::{recover_secret, ShareData}; + +pub fn wrap_from_sellibitze(share: &str) -> String { + let parts: Vec<_> = share.trim().split('-').collect(); + let share_data = parts[2].from_base64().unwrap(); + + let config = base64::Config { + pad: false, + ..base64::STANDARD + }; + + let mut share_protobuf = ShareData::new(); + share_protobuf.set_shamirData(share_data); + + let b64_share = share_protobuf.write_to_bytes().unwrap().to_base64(config); + + format!("{}-{}-{}", parts[0], parts[1], b64_share) +} #[test] fn test_recover_sellibitze() { - let share1 = "2-1-1YAYwmOHqZ69jA".to_string(); - let share2 = "2-4-F7rAjX3UOa53KA".to_string(); + let share1 = "2-1-1YAYwmOHqZ69jA"; + let share2 = "2-4-F7rAjX3UOa53KA"; - let shares = vec![share1, share2]; + let shares = vec![share1, share2].iter().map(|x| wrap_from_sellibitze(x)).collect::>(); let mut secret = "My secret".to_string().into_bytes(); secret.push(10); @@ -23,7 +45,7 @@ fn test_recover_es_test_vectors() { let share4 = "5-6-yyVPUeaYPPiWK0wIV5OQ/t61V0lSEO+7X++EWeHRlIq3sRBNwUpKNfx/C+Vc9xTzUftrqBKvkWDZQal7nyi2".to_string(); let share5 = "5-7-i8iL6bVf272B3qIjp0QqSny6AIm+DkP7oQjkVVLvx9EMhlvd4HJOxPpmtNF/RjA/zz21d7DY/B//saOPpBQa".to_string(); - let shares = vec![share1, share2, share3, share4, share5]; + let shares = vec![share1, share2, share3, share4, share5].iter().map(|x| wrap_from_sellibitze(x)).collect::>(); let secret = "The immoral cannot be made moral through the use of secret law.".to_string().into_bytes(); assert_eq!(recover_secret(shares).unwrap(), secret); @@ -36,7 +58,7 @@ fn test_recover_sellibitze_more_than_threshold_shars() { let share3 = "2-2-YJZQDGm22Y77Gw".to_string(); let share4 = "2-5-j0P4PHsw4lW+rg".to_string(); - let shares = vec![share1, share2, share3, share4]; + let shares = vec![share1, share2, share3, share4].iter().map(|x| wrap_from_sellibitze(x)).collect::>(); let mut secret = "My secret".to_string().into_bytes(); secret.push(10);