From 272384734824c2e59235bd3cdf034e99198bdb70 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sat, 23 Nov 2019 01:33:24 +0800 Subject: [PATCH] add sha* --- build.rs | 6 ++ src/main.rs | 179 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 141 insertions(+), 44 deletions(-) create mode 100644 build.rs diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..b596729 --- /dev/null +++ b/build.rs @@ -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); +} diff --git a/src/main.rs b/src/main.rs index c964f79..82f2ae4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 { + let mut options = Options::new(); + options.parse_args()?; + Ok(options) } } -pub fn read_file_full(file_name: &str) -> XResult> { +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 + +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> { 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 = 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 { - let mut buf: [u8; DEFAULT_BUF_SIZE] = [0u8; DEFAULT_BUF_SIZE]; +fn calc_file_digest(digest: &mut dyn Digest, file_name: &str) -> XResult { + 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); } }