mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
hashsum: implement SHAKE-128 and SHAKE-256
This commit is contained in:
@@ -3,6 +3,7 @@ target/
|
||||
/build/
|
||||
/tmp/
|
||||
/busybox/
|
||||
/.vscode/
|
||||
*~
|
||||
.*.swp
|
||||
.*.swo
|
||||
|
||||
Generated
+79
-166
File diff suppressed because it is too large
Load Diff
@@ -41,10 +41,13 @@ pub fn main() {
|
||||
map.insert(\"sha256sum\", uu_hashsum::uumain);
|
||||
map.insert(\"sha384sum\", uu_hashsum::uumain);
|
||||
map.insert(\"sha512sum\", uu_hashsum::uumain);
|
||||
map.insert(\"sha3sum\", uu_hashsum::uumain);
|
||||
map.insert(\"sha3-224sum\", uu_hashsum::uumain);
|
||||
map.insert(\"sha3-256sum\", uu_hashsum::uumain);
|
||||
map.insert(\"sha3-384sum\", uu_hashsum::uumain);
|
||||
map.insert(\"sha3-512sum\", uu_hashsum::uumain);\n".as_bytes()).unwrap();
|
||||
map.insert(\"sha3-512sum\", uu_hashsum::uumain);
|
||||
map.insert(\"shake128sum\", uu_hashsum::uumain);
|
||||
map.insert(\"shake256sum\", uu_hashsum::uumain);\n".as_bytes()).unwrap();
|
||||
},
|
||||
_ =>
|
||||
mf.write_all(format!("map.insert(\"{krate}\", uu_{krate}::uumain);\n", krate=krate).as_bytes()).unwrap(),
|
||||
|
||||
@@ -13,6 +13,7 @@ libc = "*"
|
||||
regex = "*"
|
||||
regex-syntax = "*"
|
||||
rust-crypto = "*"
|
||||
rustc-serialize = "*"
|
||||
uucore = { path="../uucore" }
|
||||
|
||||
[[bin]]
|
||||
|
||||
+116
-34
@@ -15,6 +15,7 @@ extern crate crypto;
|
||||
extern crate getopts;
|
||||
extern crate regex_syntax;
|
||||
extern crate regex;
|
||||
extern crate rustc_serialize as serialize;
|
||||
|
||||
#[macro_use]
|
||||
extern crate uucore;
|
||||
@@ -25,6 +26,7 @@ use crypto::sha1::Sha1;
|
||||
use crypto::sha2::{Sha224, Sha256, Sha384, Sha512};
|
||||
use crypto::sha3::{Sha3, Sha3Mode};
|
||||
use regex::Regex;
|
||||
use serialize::hex::ToHex;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader, Read, stdin, Write};
|
||||
@@ -38,47 +40,112 @@ fn is_custom_binary(program: &str) -> bool {
|
||||
"md5sum" | "sha1sum"
|
||||
| "sha224sum" | "sha256sum"
|
||||
| "sha384sum" | "sha512sum"
|
||||
| "sha3-224sum" | "sha3-256sum"
|
||||
| "sha3-384sum" | "sha3-512sum"
|
||||
| "shake128sum" | "shake256sum" => true,
|
||||
| "sha3sum" | "sha3-224sum"
|
||||
| "sha3-256sum" | "sha3-384sum"
|
||||
| "sha3-512sum" | "shake128sum"
|
||||
| "shake256sum" => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_algo(program: &str, matches: &getopts::Matches) -> (&'static str, Box<Digest+'static>) {
|
||||
fn detect_algo(program: &str, matches: &getopts::Matches) -> (&'static str, Box<Digest+'static>, usize) {
|
||||
let mut alg: Option<Box<Digest>> = None;
|
||||
let mut name: &'static str = "";
|
||||
let mut output_bits = 0;
|
||||
match program {
|
||||
"md5sum" => ("MD5", Box::new(Md5::new()) as Box<Digest>),
|
||||
"sha1sum" => ("SHA1", Box::new(Sha1::new()) as Box<Digest>),
|
||||
"sha224sum" => ("SHA224", Box::new(Sha224::new()) as Box<Digest>),
|
||||
"sha256sum" => ("SHA256", Box::new(Sha256::new()) as Box<Digest>),
|
||||
"sha384sum" => ("SHA384", Box::new(Sha384::new()) as Box<Digest>),
|
||||
"sha512sum" => ("SHA512", Box::new(Sha512::new()) as Box<Digest>),
|
||||
"sha3-224sum" => ("SHA3-224", Box::new(Sha3::new(Sha3Mode::Sha3_224)) as Box<Digest>),
|
||||
"sha3-256sum" => ("SHA3-256", Box::new(Sha3::new(Sha3Mode::Sha3_256)) as Box<Digest>),
|
||||
"sha3-384sum" => ("SHA3-384", Box::new(Sha3::new(Sha3Mode::Sha3_384)) as Box<Digest>),
|
||||
"sha3-512sum" => ("SHA3-512", Box::new(Sha3::new(Sha3Mode::Sha3_512)) as Box<Digest>),
|
||||
"md5sum" => ("MD5", Box::new(Md5::new()) as Box<Digest>, 128),
|
||||
"sha1sum" => ("SHA1", Box::new(Sha1::new()) as Box<Digest>, 160),
|
||||
"sha224sum" => ("SHA224", Box::new(Sha224::new()) as Box<Digest>, 224),
|
||||
"sha256sum" => ("SHA256", Box::new(Sha256::new()) as Box<Digest>, 256),
|
||||
"sha384sum" => ("SHA384", Box::new(Sha384::new()) as Box<Digest>, 384),
|
||||
"sha512sum" => ("SHA512", Box::new(Sha512::new()) as Box<Digest>, 512),
|
||||
"sha3sum" => {
|
||||
match matches.opt_str("bits") {
|
||||
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
|
||||
Ok(224) => ("SHA3-224", Box::new(Sha3::new(Sha3Mode::Sha3_224)) as Box<Digest>, 224),
|
||||
Ok(256) => ("SHA3-256", Box::new(Sha3::new(Sha3Mode::Sha3_256)) as Box<Digest>, 256),
|
||||
Ok(384) => ("SHA3-384", Box::new(Sha3::new(Sha3Mode::Sha3_384)) as Box<Digest>, 384),
|
||||
Ok(512) => ("SHA3-512", Box::new(Sha3::new(Sha3Mode::Sha3_512)) as Box<Digest>, 512),
|
||||
Ok(_) => crash!(1, "Invalid output size for SHA3 (expected 224, 256, 384, or 512)"),
|
||||
Err(err) => crash!(1, "{}", err)
|
||||
},
|
||||
None => crash!(1, "--bits required for SHA3")
|
||||
}
|
||||
}
|
||||
"sha3-224sum" => ("SHA3-224", Box::new(Sha3::new(Sha3Mode::Sha3_224)) as Box<Digest>, 224),
|
||||
"sha3-256sum" => ("SHA3-256", Box::new(Sha3::new(Sha3Mode::Sha3_256)) as Box<Digest>, 256),
|
||||
"sha3-384sum" => ("SHA3-384", Box::new(Sha3::new(Sha3Mode::Sha3_384)) as Box<Digest>, 384),
|
||||
"sha3-512sum" => ("SHA3-512", Box::new(Sha3::new(Sha3Mode::Sha3_512)) as Box<Digest>, 512),
|
||||
"shake128sum" => {
|
||||
match matches.opt_str("bits") {
|
||||
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
|
||||
Ok(bits) => ("SHAKE128", Box::new(Sha3::new(Sha3Mode::Shake128)) as Box<Digest>, bits),
|
||||
Err(err) => crash!(1, "{}", err)
|
||||
},
|
||||
None => crash!(1, "--bits required for SHAKE-128")
|
||||
}
|
||||
}
|
||||
"shake256sum" => {
|
||||
match matches.opt_str("bits") {
|
||||
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
|
||||
Ok(bits) => ("SHAKE256", Box::new(Sha3::new(Sha3Mode::Shake256)) as Box<Digest>, bits),
|
||||
Err(err) => crash!(1, "{}", err)
|
||||
},
|
||||
None => crash!(1, "--bits required for SHAKE-256")
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
{
|
||||
let mut set_or_crash = |n, val| -> () {
|
||||
let mut set_or_crash = |n, val, bits| -> () {
|
||||
if alg.is_some() { crash!(1, "You cannot combine multiple hash algorithms!") };
|
||||
name = n;
|
||||
alg = Some(val);
|
||||
output_bits = bits
|
||||
};
|
||||
if matches.opt_present("md5") { set_or_crash("MD5", Box::new(Md5::new())) };
|
||||
if matches.opt_present("sha1") { set_or_crash("SHA1", Box::new(Sha1::new())) };
|
||||
if matches.opt_present("sha224") { set_or_crash("SHA224", Box::new(Sha224::new())) };
|
||||
if matches.opt_present("sha256") { set_or_crash("SHA256", Box::new(Sha256::new())) };
|
||||
if matches.opt_present("sha384") { set_or_crash("SHA384", Box::new(Sha384::new())) };
|
||||
if matches.opt_present("sha512") { set_or_crash("SHA512", Box::new(Sha512::new())) };
|
||||
if matches.opt_present("sha3-224") { set_or_crash("SHA3-224", Box::new(Sha3::new(Sha3Mode::Sha3_224))) };
|
||||
if matches.opt_present("sha3-256") { set_or_crash("SHA3-256", Box::new(Sha3::new(Sha3Mode::Sha3_256))) };
|
||||
if matches.opt_present("sha3-384") { set_or_crash("SHA3-384", Box::new(Sha3::new(Sha3Mode::Sha3_384))) };
|
||||
if matches.opt_present("sha3-512") { set_or_crash("SHA3-512", Box::new(Sha3::new(Sha3Mode::Sha3_512))) };
|
||||
if matches.opt_present("md5") { set_or_crash("MD5", Box::new(Md5::new()), 128) }
|
||||
if matches.opt_present("sha1") { set_or_crash("SHA1", Box::new(Sha1::new()), 160) }
|
||||
if matches.opt_present("sha224") { set_or_crash("SHA224", Box::new(Sha224::new()), 224) }
|
||||
if matches.opt_present("sha256") { set_or_crash("SHA256", Box::new(Sha256::new()), 256) }
|
||||
if matches.opt_present("sha384") { set_or_crash("SHA384", Box::new(Sha384::new()), 384) }
|
||||
if matches.opt_present("sha512") { set_or_crash("SHA512", Box::new(Sha512::new()), 512) }
|
||||
if matches.opt_present("sha3") {
|
||||
match matches.opt_str("bits") {
|
||||
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
|
||||
Ok(224) => set_or_crash("SHA3-224", Box::new(Sha3::new(Sha3Mode::Sha3_224)) as Box<Digest>, 224),
|
||||
Ok(256) => set_or_crash("SHA3-256", Box::new(Sha3::new(Sha3Mode::Sha3_256)) as Box<Digest>, 256),
|
||||
Ok(384) => set_or_crash("SHA3-384", Box::new(Sha3::new(Sha3Mode::Sha3_384)) as Box<Digest>, 384),
|
||||
Ok(512) => set_or_crash("SHA3-512", Box::new(Sha3::new(Sha3Mode::Sha3_512)) as Box<Digest>, 512),
|
||||
Ok(_) => crash!(1, "Invalid output size for SHA3 (expected 224, 256, 384, or 512)"),
|
||||
Err(err) => crash!(1, "{}", err)
|
||||
},
|
||||
None => crash!(1, "--bits required for SHA3")
|
||||
}
|
||||
}
|
||||
if matches.opt_present("sha3-224") { set_or_crash("SHA3-224", Box::new(Sha3::new(Sha3Mode::Sha3_224)), 224) }
|
||||
if matches.opt_present("sha3-256") { set_or_crash("SHA3-256", Box::new(Sha3::new(Sha3Mode::Sha3_256)), 256) }
|
||||
if matches.opt_present("sha3-384") { set_or_crash("SHA3-384", Box::new(Sha3::new(Sha3Mode::Sha3_384)), 384) }
|
||||
if matches.opt_present("sha3-512") { set_or_crash("SHA3-512", Box::new(Sha3::new(Sha3Mode::Sha3_512)), 512) }
|
||||
if matches.opt_present("shake128") {
|
||||
match matches.opt_str("bits") {
|
||||
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
|
||||
Ok(bits) => set_or_crash("SHAKE128", Box::new(Sha3::new(Sha3Mode::Shake128)), bits),
|
||||
Err(err) => crash!(1, "{}", err)
|
||||
},
|
||||
None => crash!(1, "--bits required for SHAKE-128")
|
||||
}
|
||||
}
|
||||
if matches.opt_present("shake256") {
|
||||
match matches.opt_str("bits") {
|
||||
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
|
||||
Ok(bits) => set_or_crash("SHAKE256", Box::new(Sha3::new(Sha3Mode::Shake256)), bits),
|
||||
Err(err) => crash!(1, "{}", err)
|
||||
},
|
||||
None => crash!(1, "--bits required for SHAKE-256")
|
||||
}
|
||||
}
|
||||
}
|
||||
if alg.is_none() { crash!(1, "You must specify hash algorithm!") };
|
||||
(name, alg.unwrap())
|
||||
(name, alg.unwrap(), output_bits)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,12 +176,18 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||
opts.optflag("", "sha256", "work with SHA256");
|
||||
opts.optflag("", "sha384", "work with SHA384");
|
||||
opts.optflag("", "sha512", "work with SHA512");
|
||||
opts.optflag("", "sha3", "work with SHA3");
|
||||
opts.optflag("", "sha3-224", "work with SHA3-224");
|
||||
opts.optflag("", "sha3-256", "work with SHA3-256");
|
||||
opts.optflag("", "sha3-384", "work with SHA3-384");
|
||||
opts.optflag("", "sha3-512", "work with SHA3-512");
|
||||
opts.optflag("", "shake128", "work with SHAKE128 using BITS for the output size");
|
||||
opts.optflag("", "shake256", "work with SHAKE256 using BITS for the output size");
|
||||
}
|
||||
|
||||
// Needed for variable-length output sums (e.g. SHAKE)
|
||||
opts.optopt("", "bits", "set the size of the output (only for SHAKE)", "BITS");
|
||||
|
||||
let matches = match opts.parse(&args[1..]) {
|
||||
Ok(m) => m,
|
||||
Err(f) => crash!(1, "{}", f)
|
||||
@@ -125,7 +198,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||
} else if matches.opt_present("version") {
|
||||
version();
|
||||
} else {
|
||||
let (name, algo) = detect_algo(binary_name, &matches);
|
||||
let (name, algo, bits) = detect_algo(binary_name, &matches);
|
||||
|
||||
let binary_flag = matches.opt_present("binary");
|
||||
let text_flag = matches.opt_present("text");
|
||||
@@ -144,7 +217,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||
} else {
|
||||
matches.free
|
||||
};
|
||||
match hashsum(name, algo, files, binary, check, tag, status, quiet, strict, warn) {
|
||||
match hashsum(name, algo, files, binary, check, tag, status, quiet, strict, warn, bits) {
|
||||
Ok(()) => return 0,
|
||||
Err(e) => return e
|
||||
}
|
||||
@@ -162,7 +235,8 @@ fn usage(program: &str, binary_name: &str, opts: &getopts::Options) {
|
||||
format!(" {} [OPTION]... [FILE]...", program)
|
||||
} else {
|
||||
format!(" {} {{--md5|--sha1|--sha224|--sha256|--sha384|--sha512|\
|
||||
--sha3-224|--sha3-256|--sha3-384|sha3-512}} [OPTION]... [FILE]...", program)
|
||||
--sha3|--sha3-224|--sha3-256|--sha3-384|--sha3-512|\
|
||||
--shake128|--shake256}} [OPTION]... [FILE]...", program)
|
||||
};
|
||||
|
||||
let msg = format!("{} {}
|
||||
@@ -175,7 +249,7 @@ Compute and check message digests.", NAME, VERSION, spec);
|
||||
pipe_print!("{}", opts.usage(&msg));
|
||||
}
|
||||
|
||||
fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), i32> {
|
||||
fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool, output_bits: usize) -> Result<(), i32> {
|
||||
let mut bad_format = 0;
|
||||
let mut failed = 0;
|
||||
let binary_marker = if binary {
|
||||
@@ -242,7 +316,7 @@ fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary:
|
||||
};
|
||||
let f = safe_unwrap!(File::open(ck_filename));
|
||||
let mut ckf = BufReader::new(Box::new(f) as Box<Read>);
|
||||
let real_sum = safe_unwrap!(digest_reader(&mut digest, &mut ckf, binary_check))
|
||||
let real_sum = safe_unwrap!(digest_reader(&mut digest, &mut ckf, binary_check, output_bits))
|
||||
.to_ascii_lowercase();
|
||||
if sum == real_sum {
|
||||
if !quiet {
|
||||
@@ -256,7 +330,7 @@ fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary:
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let sum = safe_unwrap!(digest_reader(&mut digest, &mut file, binary));
|
||||
let sum = safe_unwrap!(digest_reader(&mut digest, &mut file, binary, output_bits));
|
||||
if tag {
|
||||
pipe_println!("{} ({}) = {}", algoname, filename, sum);
|
||||
} else {
|
||||
@@ -278,7 +352,7 @@ fn hashsum(algoname: &str, mut digest: Box<Digest>, files: Vec<String>, binary:
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn digest_reader<'a, T: Read>(digest: &mut Box<Digest+'a>, reader: &mut BufReader<T>, binary: bool) -> io::Result<String> {
|
||||
fn digest_reader<'a, T: Read>(digest: &mut Box<Digest+'a>, reader: &mut BufReader<T>, binary: bool, output_bits: usize) -> io::Result<String> {
|
||||
digest.reset();
|
||||
|
||||
// Digest file, do not hold too much in memory at any given moment
|
||||
@@ -321,5 +395,13 @@ fn digest_reader<'a, T: Read>(digest: &mut Box<Digest+'a>, reader: &mut BufReade
|
||||
digest.input(&vec);
|
||||
}
|
||||
|
||||
Ok(digest.result_str())
|
||||
if digest.output_bits() > 0 {
|
||||
Ok(digest.result_str())
|
||||
} else {
|
||||
// Assume it's SHAKE. result_str() doesn't work with shake (as of 8/30/2016)
|
||||
let mut bytes = Vec::new();
|
||||
bytes.resize((output_bits + 7) / 8, 0);
|
||||
digest.result(&mut bytes);
|
||||
Ok(bytes.to_hex())
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
927b362eaf84a75785bbec3370d1c9711349e93f1104eda060784221
|
||||
+1
@@ -0,0 +1 @@
|
||||
bfb3959527d7a3f2f09def2f6915452d55a8f122df9e164d6f31c7fcf6093e14
|
||||
+1
@@ -0,0 +1 @@
|
||||
fbd0c5931195aaa9517869972b372f717bb69f7f9f72bfc0884ed0531c36a16fc2db5dd6d82131968b23ffe0e90757e5
|
||||
+1
@@ -0,0 +1 @@
|
||||
2ed3a863a12e2f8ff140aa86232ff3603a7f24af62f0e2ca74672494ade175a9a3de42a351b5019d931a1deae0499609038d9b47268779d76198e1d410d20974
|
||||
@@ -0,0 +1 @@
|
||||
83d41db453072caa9953f2f316480fbbcb84a5f3505460a18b3a36a814ae8e9e
|
||||
@@ -0,0 +1 @@
|
||||
7c9896ea84a2a1b80b2183a3f2b4e43cd59b7d48471dc213bcedaccb699d6e6f7ad5d304928ab79329f1fc62f6db072d95b51209eb807683f5c9371872a2dd4e
|
||||
+20
-6
@@ -5,28 +5,42 @@ macro_rules! get_hash(
|
||||
);
|
||||
|
||||
macro_rules! test_digest {
|
||||
($($t:ident)*) => ($(
|
||||
($($id:ident $t:ident $size:expr)*) => ($(
|
||||
|
||||
mod $t {
|
||||
mod $id {
|
||||
use::common::util::*;
|
||||
static DIGEST_ARG: &'static str = concat!("--", stringify!($t));
|
||||
static EXPECTED_FILE: &'static str = concat!(stringify!($t), ".expected");
|
||||
static BITS_ARG: &'static str = concat!("--bits=", stringify!($size));
|
||||
static EXPECTED_FILE: &'static str = concat!(stringify!($id), ".expected");
|
||||
|
||||
#[test]
|
||||
fn test_single_file() {
|
||||
let ts = TestScenario::new("hashsum");
|
||||
assert_eq!(ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(ts.ucmd().arg(DIGEST_ARG).arg("input.txt").succeeds().no_stderr().stdout));
|
||||
get_hash!(ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).arg("input.txt").succeeds().no_stderr().stdout));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stdin() {
|
||||
let ts = TestScenario::new("hashsum");
|
||||
assert_eq!(ts.fixtures.read(EXPECTED_FILE),
|
||||
get_hash!(ts.ucmd().arg(DIGEST_ARG).pipe_in_fixture("input.txt").succeeds().no_stderr().stdout));
|
||||
get_hash!(ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).pipe_in_fixture("input.txt").succeeds().no_stderr().stdout));
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
test_digest! { md5 sha1 sha224 sha256 sha384 sha512 }
|
||||
test_digest! {
|
||||
md5 md5 128
|
||||
sha1 sha1 160
|
||||
sha224 sha224 224
|
||||
sha256 sha256 256
|
||||
sha384 sha384 384
|
||||
sha512 sha512 512
|
||||
sha3_224 sha3 224
|
||||
sha3_256 sha3 256
|
||||
sha3_384 sha3 384
|
||||
sha3_512 sha3 512
|
||||
shake128_256 shake128 256
|
||||
shake256_512 shake256 512
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user