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

View File

@@ -1,6 +1,5 @@
use rust_util::{
XResult,
new_box_error,
new_box_ioerror,
util_msg::{
print_message,
@@ -9,83 +8,175 @@ use rust_util::{
util_io::*,
};
use std::{
env,
fs::{self, File},
fs::File,
io::{Read, ErrorKind},
path::Path,
process::Command,
time::SystemTime,
};
use crypto::{
digest::Digest,
md5::Md5,
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;
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() {
let h = calc_file_digest(&mut Sha256::new(), "SHA256", "LICENSE");
match h {
Err(_) => {},
Ok(d) => println!("SHA256: {}", d),
const VERSION: &str = env!("CARGO_PKG_VERSION");
const GIT_HASH: &str = env!("GIT_HASH");
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 {
Err(_) => {},
Ok(s) => {
let mut sm3h = Sm3Hash::new(&s);
let hh = sm3h.get_hash();
println!("SM3: {}", hex::encode(hh));
},
pub fn parse_args(&mut self) -> XResult<()> {
{
let mut ap = ArgumentParser::new();
ap.set_description("digest - command line digest tool.");
ap.refer(&mut self.algorithm).add_option(&["-a", "--algorithm"], Store, "Algorithm, e.g. SHA256, SM3");
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 f = File::open(file_name)?;
let file_len = match f.metadata() {
Err(_) => -1i64,
Ok(meta_data) => meta_data.len() as i64,
};
let file_len = f.metadata()?.len();
let mut ret: Vec<u8> = Vec::new();
let start = SystemTime::now();
let mut written = 0i64;
let mut read = 0_u64;
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 {
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,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(Box::new(e)),
};
ret.append(&mut buf[..len].to_vec());
written += len as i64;
let cost = SystemTime::now().duration_since(start.clone()).unwrap();
print_status_last_line(&format!("Calc {}", "digest_alg"), file_len, written, cost);
read += len as u64;
pb.set_position(read);
}
}
pub fn calc_file_digest(digest: &mut dyn Digest, digest_alg: &str, file_name: &str) -> XResult<String> {
let mut buf: [u8; DEFAULT_BUF_SIZE] = [0u8; DEFAULT_BUF_SIZE];
fn calc_file_digest(digest: &mut dyn Digest, file_name: &str) -> XResult<String> {
let mut buf: [u8; BUFF_SIZE] = [0u8; BUFF_SIZE];
let mut f = File::open(file_name)?;
let file_len = match f.metadata() {
Err(_) => -1i64,
Ok(meta_data) => meta_data.len() as i64,
};
let start = SystemTime::now();
let mut written = 0i64;
let file_len = f.metadata()?.len();
let mut processed = 0_u64;
let pb = ProgressBar::new(file_len);
pb.set_style(ProgressStyle::default_bar().template(PB_TEMPLATE).progress_chars(PB_PROGRESS));
loop {
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,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(Box::new(e)),
};
digest.input(&buf[..len]);
written += len as i64;
let cost = SystemTime::now().duration_since(start.clone()).unwrap();
print_status_last_line(&format!("Calc {}", digest_alg), file_len, written, cost);
processed += len as u64;
pb.set_position(processed);
}
}