From 186330fe2c5abb4db622320bce120cf5374af855 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Tue, 17 Oct 2023 22:27:25 +0800 Subject: [PATCH] feat: v0.4.3, add --digest-file for decrypt --- Cargo.lock | 128 +++++++++++++++++++++++++++++++++++++++------ Cargo.toml | 3 +- src/cmd_decrypt.rs | 32 ++++++++++-- src/main.rs | 1 + src/util_digest.rs | 71 +++++++++++++++++++++++++ 5 files changed, 214 insertions(+), 21 deletions(-) create mode 100644 src/util_digest.rs diff --git a/Cargo.lock b/Cargo.lock index 8a92d75..4fe4b57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,7 +117,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time", + "time 0.3.30", ] [[package]] @@ -384,7 +384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -561,7 +561,7 @@ dependencies = [ "hkdf", "pem-rfc7468", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -589,7 +589,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -632,6 +632,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "generic-array" version = "0.14.7" @@ -651,7 +663,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -677,7 +689,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -888,7 +900,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.5", "serde", "smallvec", "zeroize", @@ -1186,6 +1198,29 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + [[package]] name = "rand" version = "0.8.5" @@ -1194,7 +1229,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1204,9 +1239,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.4" @@ -1216,6 +1266,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1272,7 +1331,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sha2", "signature", "spki", @@ -1290,6 +1349,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +dependencies = [ + "gcc", + "libc", + "rand 0.3.23", + "rustc-serialize", + "time 0.1.45", +] + [[package]] name = "rust_util" version = "0.6.43" @@ -1308,6 +1380,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1453,7 +1531,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1599,6 +1677,17 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + [[package]] name = "time" version = "0.3.30" @@ -1630,7 +1719,7 @@ dependencies = [ [[package]] name = "tiny-encrypt" -version = "0.4.2" +version = "0.4.3" dependencies = [ "aes-gcm-stream", "base64", @@ -1644,9 +1733,10 @@ dependencies = [ "openpgp-card-pcsc", "p256", "p384", - "rand", + "rand 0.8.5", "rpassword", "rsa", + "rust-crypto", "rust_util", "serde", "serde_json", @@ -1731,6 +1821,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1961,7 +2057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ "curve25519-dalek", - "rand_core", + "rand_core 0.6.4", "serde", "zeroize", ] @@ -1993,7 +2089,7 @@ dependencies = [ "oid-registry", "rusticata-macros", "thiserror", - "time", + "time 0.3.30", ] [[package]] @@ -2017,7 +2113,7 @@ dependencies = [ "p384", "pbkdf2", "pcsc", - "rand_core", + "rand_core 0.6.4", "rsa", "secrecy", "sha1", diff --git a/Cargo.toml b/Cargo.toml index 16a59ac..dabeff9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tiny-encrypt" -version = "0.4.2" +version = "0.4.3" edition = "2021" license = "MIT" description = "A simple and tiny file encrypt tool" @@ -24,6 +24,7 @@ rand = "0.8" # reqwest = { version = "0.11", features = ["blocking", "rustls", "rustls-tls"] } rpassword = "7.2" rsa = { version = "0.9", features = ["pem"] } +rust-crypto = "0.2.36" rust_util = "0.6" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/cmd_decrypt.rs b/src/cmd_decrypt.rs index f4dc65e..9eeba8e 100644 --- a/src/cmd_decrypt.rs +++ b/src/cmd_decrypt.rs @@ -26,6 +26,7 @@ use crate::consts::{ use crate::crypto_aes::{aes_gcm_decrypt, try_aes_gcm_decrypt_with_salt}; use crate::spec::{EncEncryptedMeta, TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta}; use crate::util::SecVec; +use crate::util_digest::DigestWrite; use crate::util_progress::Progress; use crate::wrap_key::WrapKey; @@ -48,6 +49,12 @@ pub struct CmdDecrypt { /// Direct print to the console, file must less than 10K #[arg(long)] pub direct_print: bool, + /// Digest file + #[arg(long)] + pub digest_file: bool, + /// Digest algorithm (sha1, sha256[default], sha384, sha512 ...) + #[arg(long)] + pub digest_algorithm: Option, } pub fn decrypt(cmd_decrypt: CmdDecrypt) -> XResult<()> { @@ -102,9 +109,15 @@ pub fn decrypt_single(config: &Option, util_enc_file::read_tiny_encrypt_meta_and_normalize(&mut file_in), "Read file: {}, failed: {}", &path_display); debugging!("Found meta: {}", serde_json::to_string_pretty(&meta).unwrap()); - let do_write_file_out = cmd_decrypt.skip_decrypt_file || cmd_decrypt.direct_print; + let do_skip_file_out = cmd_decrypt.skip_decrypt_file || cmd_decrypt.direct_print || cmd_decrypt.digest_file; let path_out = &path_display[0..path_display.len() - TINY_ENC_FILE_EXT.len()]; - if !do_write_file_out { util::require_file_not_exists(path_out)?; } + if !do_skip_file_out { util::require_file_not_exists(path_out)?; } + + let digest_algorithm = match &cmd_decrypt.digest_algorithm { + None => "sha256", + Some(algo) => algo.as_str(), + }; + if cmd_decrypt.digest_file { DigestWrite::from_algo(digest_algorithm)?; } // QUICK CHECK let selected_envelop = select_envelop(&meta, config)?; @@ -140,10 +153,21 @@ pub fn decrypt_single(config: &Option, return Ok(meta.file_length); } + // Digest file + if cmd_decrypt.digest_file { + let mut digest_write = DigestWrite::from_algo(digest_algorithm)?; + let _ = decrypt_file( + &mut file_in, meta.file_length, &mut digest_write, &key.0, &nonce.0, meta.compress, + )?; + let digest = digest_write.digest(); + success!("File digest {}: {}", digest_algorithm.to_uppercase(), hex::encode(digest)); + return Ok(meta.file_length); + } + // Decrypt to file let compressed_desc = iff!(meta.compress, " [compressed]", ""); let start = Instant::now(); - + let mut file_out = File::create(path_out)?; let _ = decrypt_file( &mut file_in, meta.file_length, &mut file_out, &key.0, &nonce.0, meta.compress, @@ -154,7 +178,7 @@ pub fn decrypt_single(config: &Option, let encrypt_duration = start.elapsed(); debugging!("Inner decrypt file{}: {} elapsed: {} ms", compressed_desc, path_display, encrypt_duration.as_millis()); - if do_write_file_out & &cmd_decrypt.remove_file { util::remove_file_with_msg(path); } + if do_skip_file_out & &cmd_decrypt.remove_file { util::remove_file_with_msg(path); } Ok(meta.file_length) } diff --git a/src/main.rs b/src/main.rs index dd5c9cc..80ef2c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use crate::cmd_version::CmdVersion; mod consts; mod util; +mod util_digest; mod util_progress; mod util_piv; mod util_pgp; diff --git a/src/util_digest.rs b/src/util_digest.rs new file mode 100644 index 0000000..abb31f9 --- /dev/null +++ b/src/util_digest.rs @@ -0,0 +1,71 @@ +use std::io::Write; +use std::iter::repeat; + +use crypto::digest::Digest; +use crypto::md5::Md5; +use crypto::ripemd160::Ripemd160; +use crypto::sha1::Sha1; +use crypto::sha2::{Sha224, Sha256, Sha384, Sha512, Sha512Trunc224, Sha512Trunc256}; +use crypto::sha3::Sha3; +use crypto::whirlpool::Whirlpool; +use rust_util::{simple_error, XResult}; + +pub struct DigestWrite { + digest: Box, +} + +impl Write for DigestWrite { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.digest.input(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +impl DigestWrite { + pub fn from_algo(algo: &str) -> XResult { + match get_digest_by_algorithm(algo) { + None => simple_error!("Unsupported algo: {}", algo), + Some(digest) => Ok(Self { digest }) + } + } + + pub fn digest(self) -> Vec { + let mut digest = self.digest; + let mut buf: Vec = repeat(0).take((digest.output_bits() + 7) / 8).collect(); + digest.result(&mut buf); + buf + } +} + +fn get_digest_by_algorithm(algo: &str) -> Option> { + let algo = algo.to_uppercase(); + match algo.as_str() { + "RIPEMD160" => Some(Box::new(Ripemd160::new())), + "WHIRLPOOL" => Some(Box::new(Whirlpool::new())), + // "BLAKE2S" => Some(Box::new(Blake2s::new(iff!(options.blake_len == 0_usize, 32, options.blake_len)))), + // "BLAKE2B" => Some(Box::new(Blake2b::new(iff!(options.blake_len == 0_usize, 64, options.blake_len)))), + "MD5" => Some(Box::new(Md5::new())), + "SHA1" | "SHA-1" => Some(Box::new(Sha1::new())), + "SHA224" | "SHA-224" => Some(Box::new(Sha224::new())), + "SHA256" | "SHA-256" => Some(Box::new(Sha256::new())), + "SHA384" | "SHA-384" => Some(Box::new(Sha384::new())), + "SHA512" | "SHA-512" => Some(Box::new(Sha512::new())), + "SHA512-224" => Some(Box::new(Sha512Trunc224::new())), + "SHA512-256" => Some(Box::new(Sha512Trunc256::new())), + "SHA3-224" => Some(Box::new(Sha3::sha3_224())), + "SHA3-256" => Some(Box::new(Sha3::sha3_256())), + "SHA3-384" => Some(Box::new(Sha3::sha3_384())), + "SHA3-512" => Some(Box::new(Sha3::sha3_512())), + "SHAKE-128" => Some(Box::new(Sha3::shake_128())), + "SHAKE-256" => Some(Box::new(Sha3::shake_256())), + "KECCAK-224" => Some(Box::new(Sha3::keccak224())), + "KECCAK-256" => Some(Box::new(Sha3::keccak256())), + "KECCAK-384" => Some(Box::new(Sha3::keccak384())), + "KECCAK-512" => Some(Box::new(Sha3::keccak512())), + _ => None, + } +} \ No newline at end of file