feat: v0.4.3, add --digest-file for decrypt

This commit is contained in:
2023-10-17 22:27:25 +08:00
parent ddd3ac3b2d
commit 186330fe2c
5 changed files with 214 additions and 21 deletions

View File

@@ -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<String>,
}
pub fn decrypt(cmd_decrypt: CmdDecrypt) -> XResult<()> {
@@ -102,9 +109,15 @@ pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
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<TinyEncryptConfig>,
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<TinyEncryptConfig>,
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)
}

View File

@@ -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;

71
src/util_digest.rs Normal file
View File

@@ -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<dyn Digest>,
}
impl Write for DigestWrite {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.digest.input(buf);
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl DigestWrite {
pub fn from_algo(algo: &str) -> XResult<Self> {
match get_digest_by_algorithm(algo) {
None => simple_error!("Unsupported algo: {}", algo),
Some(digest) => Ok(Self { digest })
}
}
pub fn digest(self) -> Vec<u8> {
let mut digest = self.digest;
let mut buf: Vec<u8> = repeat(0).take((digest.output_bits() + 7) / 8).collect();
digest.result(&mut buf);
buf
}
}
fn get_digest_by_algorithm(algo: &str) -> Option<Box<dyn Digest>> {
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,
}
}