add checksums to shares (CRC-24)

This commit is contained in:
Sebastian Gesemann
2015-01-31 21:06:23 +01:00
parent 08fe9b2bfa
commit 27015b7d43
3 changed files with 74 additions and 28 deletions

6
Cargo.lock generated
View File

@ -2,10 +2,16 @@
name = "secretshare"
version = "0.0.1"
dependencies = [
"crc24 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crc24"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "getopts"
version = "0.2.0"

View File

@ -2,7 +2,11 @@
name = "secretshare"
version = "0.0.1"
authors = ["Sebastian Gesemann <s.gesemann@gmail.com>"]
description = "This is an implementation of Shamir's secret sharing scheme."
license = "GPLv3"
readme = "README.md"
[dependencies]
getopts = "0.2.0"
rustc-serialize = "0.2.10"
crc24 = "0.0.2"

View File

@ -5,6 +5,7 @@
extern crate "rustc-serialize" as serialize;
extern crate getopts;
extern crate crc24;
use std::os;
use std::rand::{ Rng, OsRng };
@ -121,7 +122,14 @@ fn read_no_more_than<R: Reader>(r: &mut R, max: usize) -> IoResult<Vec<u8>> {
Ok(data)
}
fn perform_encode(k: u8, n: u8) -> IoResult<()> {
fn crc24_as_bytes(octets: &[u8]) -> [u8; 3] {
let v = crc24::hash_raw(octets);
[((v >> 16) & 0xFF) as u8,
((v >> 8) & 0xFF) as u8,
( v & 0xFF) as u8]
}
fn perform_encode(k: u8, n: u8, with_checksums: bool) -> IoResult<()> {
let secret = try!(read_no_more_than(&mut stdio::stdin(), 0x10000));
let shares = try!(secret_share(&*secret, k, n));
let config = base64::Config {
@ -129,11 +137,26 @@ fn perform_encode(k: u8, n: u8) -> IoResult<()> {
..base64::STANDARD
};
for (index, share) in shares.iter().enumerate() {
println!("{}-{}-{}", k, index+1, share.to_base64(config));
let salad = share.to_base64(config);
if with_checksums {
let crc_bytes = crc24_as_bytes(&**share);
println!("{}-{}-{}-{}", k, index+1, salad, crc_bytes.to_base64(config));
} else {
println!("{}-{}-{}", k, index+1, salad);
}
}
Ok(())
}
macro_rules! otry {
($o:expr, $e:expr) => (
match $o {
Some(thing_) => thing_,
None => return Err(other_io_err($e))
}
)
}
/// reads shares from stdin and returns Ok(k, shares) on success
/// where shares is a Vec<(u8, Vec<u8>)> representing x-coordinates
/// and share data.
@ -145,36 +168,49 @@ fn read_shares() -> IoResult<(u8, Vec<(u8,Vec<u8>)>)> {
for line in stdin.lines() {
let line = try!(line);
let parts: Vec<_> = line.trim().split('-').collect();
let (k, n, raw) = match
Some(parts).and_then(|p| {
if p.len() != 3 { None } else { Some(p) }
}).and_then(|p| {
let mut iter = p.into_iter();
let p1 = iter.next().unwrap().parse::<u8>();
let p2 = iter.next().unwrap().parse::<u8>();
let p3 = iter.next().unwrap();
match (p1, p2) {
(Some(k), Some(n)) => Some((k,n,p3)),
_ => None
}
}).and_then(|(k,n,text)| {
match text.from_base64() {
Ok(v) => Some((k,n,v)),
_ => None
}
}) {
None => return Err(other_io_err("Share parse error")),
Some(s) => s
};
if let Some((ck,cl)) = opt_k_l {
if ck != k || cl != raw.len() {
if parts.len() < 3 || parts.len() > 4 {
return Err(other_io_err("Share parse error: Expected 3 or 4 \
parts searated by a minus sign"));
}
let (k, n, p3, opt_p4) = {
let mut iter = parts.into_iter();
let msg = "Share parse error: Could not parse K,N parameters";
let k = otry!(iter.next().unwrap().parse::<u8>(), msg);
let n = otry!(iter.next().unwrap().parse::<u8>(), msg);
let p3 = iter.next().unwrap();
let opt_p4 = iter.next();
(k, n, p3, opt_p4)
};
if k < 1 || n < 1 {
return Err(other_io_err("Share parse error: Illegal K,N parameters"));
}
let data = try!(
p3.from_base64().map_err(|_| other_io_err(
"Share parse error: Base64 decoding of data block failed"))
);
if let Some(check) = opt_p4 {
if check.len() != 4 {
return Err(other_io_err("Share parse error: Checksum part is \
expected to be four characters"));
}
let crc_bytes = try!(
check.from_base64().map_err(|_| other_io_err(
"Share parse error: Base64 decoding of checksum failed"))
);
let mychksum = crc24_as_bytes(&*data);
if mychksum != crc_bytes {
return Err(other_io_err("Share parse error: Checksum mismatch"));
}
}
if let Some((ck, cl)) = opt_k_l {
if ck != k || cl != data.len() {
return Err(other_io_err("Incompatible shares"));
}
} else {
opt_k_l = Some((k,raw.len()));
opt_k_l = Some((k, data.len()));
}
if shares.iter().all(|s| s.0 != n) {
shares.push((n, raw));
shares.push((n, data));
counter += 1;
if counter == k {
return Ok((k, shares));
@ -254,7 +290,7 @@ fn main() {
let result =
match action {
Ok(Action::Encode(k,n)) => perform_encode(k,n),
Ok(Action::Encode(k,n)) => perform_encode(k, n, true),
Ok(Action::Decode) => perform_decode(),
Err(e) => {
drop(writeln!(&mut stderr, "Error: {}", e));