This commit is contained in:
2019-11-23 01:33:24 +08:00
parent f400eb35ee
commit 2723847348
2 changed files with 141 additions and 44 deletions

6
build.rs Normal file
View File

@@ -0,0 +1,6 @@
use std::process::Command;
fn main() {
let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().unwrap();
let git_hash = String::from_utf8(output.stdout).unwrap();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
}

View File

@@ -1,6 +1,5 @@
use rust_util::{ use rust_util::{
XResult, XResult,
new_box_error,
new_box_ioerror, new_box_ioerror,
util_msg::{ util_msg::{
print_message, print_message,
@@ -9,83 +8,175 @@ use rust_util::{
util_io::*, util_io::*,
}; };
use std::{ use std::{
env, fs::File,
fs::{self, File},
io::{Read, ErrorKind}, io::{Read, ErrorKind},
path::Path,
process::Command,
time::SystemTime,
}; };
use crypto::{ use crypto::{
digest::Digest, digest::Digest,
md5::Md5, md5::Md5,
sha1::Sha1, sha1::Sha1,
sha2::{Sha256, Sha512}, sha2::{
Sha224,
Sha256,
Sha384,
Sha512,
Sha512Trunc224,
Sha512Trunc256,
},
sha3::Sha3,
}; };
use std::ops::Deref; use indicatif::{
ProgressBar,
ProgressStyle
};
use argparse::{ArgumentParser, StoreTrue, Store};
use libsm::sm3::hash::Sm3Hash; use libsm::sm3::hash::Sm3Hash;
const FILE_SIZE_1GB: u64 = 1024 * 1024 * 1024;
const BUFF_SIZE: usize = 512 * 1024;
const PB_PROGRESS: &str = "#-";
const PB_TEMPLATE: &str = "{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})";
fn main() { const VERSION: &str = env!("CARGO_PKG_VERSION");
let h = calc_file_digest(&mut Sha256::new(), "SHA256", "LICENSE"); const GIT_HASH: &str = env!("GIT_HASH");
match h {
Err(_) => {},
Ok(d) => println!("SHA256: {}", d), pub struct Options {
pub version: bool,
pub algorithm: String,
pub file_name: String,
}
impl Options {
pub fn new() -> Options {
Options {
version: false,
algorithm: "SHA256".to_string(),
file_name: String::new(),
}
} }
let sm3 = read_file_full("LICENSE");
match sm3 { pub fn parse_args(&mut self) -> XResult<()> {
Err(_) => {}, {
Ok(s) => { let mut ap = ArgumentParser::new();
let mut sm3h = Sm3Hash::new(&s); ap.set_description("digest - command line digest tool.");
let hh = sm3h.get_hash(); ap.refer(&mut self.algorithm).add_option(&["-a", "--algorithm"], Store, "Algorithm, e.g. SHA256, SM3");
println!("SM3: {}", hex::encode(hh)); ap.refer(&mut self.version).add_option(&["-v", "--version"], StoreTrue, "Print version");
}, ap.refer(&mut self.file_name).add_argument("FILE NAME", Store, "Search text");
ap.parse_args_or_exit();
}
Ok(())
}
pub fn new_and_parse_args() -> XResult<Options> {
let mut options = Options::new();
options.parse_args()?;
Ok(options)
} }
} }
pub fn read_file_full(file_name: &str) -> XResult<Vec<u8>> { fn main() -> XResult<()> {
let options = Options::new_and_parse_args()?;
if options.version {
print_version();
return Ok(());
}
if options.file_name == "" {
println!("NO FILE NAME!");
return Ok(());
}
let the_fn = options.file_name.as_str();
let the_algo = options.algorithm.to_uppercase();
match the_algo.as_str() {
"MD5" => println!("{}: {}", the_algo, calc_file_digest(&mut Md5::new(), the_fn)?),
"SHA1" | "SHA-1" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha1::new(), the_fn)?),
"SHA224" | "SHA-224" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha224::new(), the_fn)?),
"SHA256" | "SHA-256" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha256::new(), the_fn)?),
"SHA384" | "SHA-384" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha384::new(), the_fn)?),
"SHA512" | "SHA-512" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha512::new(), the_fn)?),
"SHA512-224" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha512Trunc224::new(), the_fn)?),
"SHA512-256" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha512Trunc256::new(), the_fn)?),
"SHA3-224" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha3::sha3_224(), the_fn)?),
"SHA3-256" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha3::sha3_256(), the_fn)?),
"SHA3-384" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha3::sha3_384(), the_fn)?),
"SHA3-512" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha3::sha3_512(), the_fn)?),
"SHAKE-128" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha3::shake_128(), the_fn)?),
"SHAKE-256" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha3::shake_256(), the_fn)?),
"KECCAK-224" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha3::keccak224(), the_fn)?),
"KECCAK-256" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha3::keccak256(), the_fn)?),
"KECCAK-384" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha3::keccak384(), the_fn)?),
"KECCAK-512" => println!("{}: {}", the_algo, calc_file_digest(&mut Sha3::keccak512(), the_fn)?),
"SM3" => println!("{}: {}", the_algo, hex::encode(Sm3Hash::new(&read_file_full(the_fn)?).get_hash())),
_ => print_message(MessageType::ERROR, &format!("Unknown algorithm: {}", options.algorithm)),
};
Ok(())
}
fn print_version() {
print!(r#"digest {} - {}
Copyright (C) 2019 Hatter Jiang.
License MIT <https://opensource.org/licenses/MIT>
Written by Hatter Jiang
Supported algorithms:
MD5, SHA1, SHA224, SHA256, SHA512, SHA512-224, SHA512-256,
SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE-128, SHAKE-256,
KECCAK-224, KECCAK-256, KECCAK-384, KECCAK-512, SM3
"#, VERSION, &GIT_HASH[0..7]);
}
fn read_file_full(file_name: &str) -> XResult<Vec<u8>> {
let mut buf: [u8; DEFAULT_BUF_SIZE] = [0u8; DEFAULT_BUF_SIZE]; let mut buf: [u8; DEFAULT_BUF_SIZE] = [0u8; DEFAULT_BUF_SIZE];
let mut f = File::open(file_name)?; let mut f = File::open(file_name)?;
let file_len = match f.metadata() { let file_len = f.metadata()?.len();
Err(_) => -1i64,
Ok(meta_data) => meta_data.len() as i64,
};
let mut ret: Vec<u8> = Vec::new(); let mut ret: Vec<u8> = Vec::new();
let start = SystemTime::now(); let mut read = 0_u64;
let mut written = 0i64;
if file_len > FILE_SIZE_1GB {
return Err(new_box_ioerror("File too large!"));
}
let pb = ProgressBar::new(file_len);
pb.set_style(ProgressStyle::default_bar().template(PB_TEMPLATE).progress_chars(PB_PROGRESS));
loop { loop {
let len = match f.read(&mut buf) { let len = match f.read(&mut buf) {
Ok(0) => { println!(); return Ok(ret); }, Ok(0) => { pb.finish_and_clear(); return Ok(ret); },
Ok(len) => len, Ok(len) => len,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(Box::new(e)), Err(e) => return Err(Box::new(e)),
}; };
ret.append(&mut buf[..len].to_vec()); ret.append(&mut buf[..len].to_vec());
written += len as i64; read += len as u64;
let cost = SystemTime::now().duration_since(start.clone()).unwrap(); pb.set_position(read);
print_status_last_line(&format!("Calc {}", "digest_alg"), file_len, written, cost);
} }
} }
pub fn calc_file_digest(digest: &mut dyn Digest, digest_alg: &str, file_name: &str) -> XResult<String> { fn calc_file_digest(digest: &mut dyn Digest, file_name: &str) -> XResult<String> {
let mut buf: [u8; DEFAULT_BUF_SIZE] = [0u8; DEFAULT_BUF_SIZE]; let mut buf: [u8; BUFF_SIZE] = [0u8; BUFF_SIZE];
let mut f = File::open(file_name)?; let mut f = File::open(file_name)?;
let file_len = match f.metadata() { let file_len = f.metadata()?.len();
Err(_) => -1i64, let mut processed = 0_u64;
Ok(meta_data) => meta_data.len() as i64,
}; let pb = ProgressBar::new(file_len);
let start = SystemTime::now(); pb.set_style(ProgressStyle::default_bar().template(PB_TEMPLATE).progress_chars(PB_PROGRESS));
let mut written = 0i64;
loop { loop {
let len = match f.read(&mut buf) { let len = match f.read(&mut buf) {
Ok(0) => { println!(); return Ok(digest.result_str()); }, Ok(0) => { pb.finish_and_clear(); return Ok(digest.result_str()); },
Ok(len) => len, Ok(len) => len,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(Box::new(e)), Err(e) => return Err(Box::new(e)),
}; };
digest.input(&buf[..len]); digest.input(&buf[..len]);
written += len as i64; processed += len as u64;
let cost = SystemTime::now().duration_since(start.clone()).unwrap(); pb.set_position(processed);
print_status_last_line(&format!("Calc {}", digest_alg), file_len, written, cost);
} }
} }