From b268d88e3c6cb41d5bdf99f80842c23130c2d19c Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 15 Oct 2023 11:29:31 +0800 Subject: [PATCH] feat: v0.3.3, optimize code --- Cargo.lock | 2 +- Cargo.toml | 6 ++--- src/cmd_decrypt.rs | 26 ++++++++---------- src/cmd_encrypt.rs | 67 +++++++++++++++++++++++----------------------- src/util.rs | 11 ++++++-- 5 files changed, 58 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 742361e..a0d1eaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2144,7 +2144,7 @@ dependencies = [ [[package]] name = "tiny-encrypt" -version = "0.3.2" +version = "0.3.3" dependencies = [ "aes-gcm-stream", "base64", diff --git a/Cargo.toml b/Cargo.toml index a349409..a4d080d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tiny-encrypt" -version = "0.3.2" +version = "0.3.3" edition = "2021" license = "MIT" description = "A simple and tiny file encrypt tool" @@ -11,9 +11,9 @@ description = "A simple and tiny file encrypt tool" aes-gcm-stream = "0.2" base64 = "0.21" chrono = "0.4" -clap = { version = "4.1", features = ["derive"] } +clap = { version = "4.4", features = ["derive"] } flate2 = "1.0" -fs-set-times = "0.20.0" +fs-set-times = "0.20" hex = "0.4" openpgp-card = "0.3" openpgp-card-pcsc = "0.3" diff --git a/src/cmd_decrypt.rs b/src/cmd_decrypt.rs index 24d758c..83560e5 100644 --- a/src/cmd_decrypt.rs +++ b/src/cmd_decrypt.rs @@ -1,5 +1,5 @@ -use std::{fs, io}; use std::fs::File; +use std::io; use std::io::{Read, Write}; use std::path::PathBuf; use std::time::{Instant, SystemTime}; @@ -113,9 +113,10 @@ pub fn decrypt_single(config: &Option, if cmd_decrypt.skip_decrypt_file { information!("Decrypt file is skipped."); } else { + let compressed_desc = iff!(meta.compress, " [compressed]", ""); let start = Instant::now(); util_msg::print_lastline( - &format!("Decrypting file: {}{} ...", path_display, iff!(meta.compress, " [compressed]", "")) + &format!("Decrypting file: {}{} ...", path_display, compressed_desc) ); let mut file_out = File::create(path_out)?; @@ -125,18 +126,13 @@ pub fn decrypt_single(config: &Option, update_out_file_time(enc_meta, path_out); let encrypt_duration = start.elapsed(); - debugging!("Inner decrypt file: {} elapsed: {} ms", path_display, encrypt_duration.as_millis()); + debugging!("Inner decrypt file{}: {} elapsed: {} ms", compressed_desc, path_display, encrypt_duration.as_millis()); } util::zeroize(key); util::zeroize(nonce); drop(file_in); - if cmd_decrypt.remove_file { - match fs::remove_file(path) { - Err(e) => warning!("Remove file: {} failed: {}", path_display, e), - Ok(_) => information!("Remove file: {} succeed", path_display), - } - } + if cmd_decrypt.remove_file { util::remove_file_with_msg(path); } Ok(meta.file_length) } @@ -179,13 +175,13 @@ fn decrypt_file(file_in: &mut File, file_out: &mut File, key: &[u8], nonce: &[u8 fn update_out_file_time(enc_meta: Option, path_out: &str) { if let Some(enc_meta) = &enc_meta { - let create_time = enc_meta.c_time.map(|t| SystemTime::from_millis(t)); - let modify_time = enc_meta.m_time.map(|t| SystemTime::from_millis(t)); + let create_time = enc_meta.c_time.map(SystemTime::from_millis); + let modify_time = enc_meta.m_time.map(SystemTime::from_millis); if create_time.is_some() || modify_time.is_some() { let set_times_result = fs_set_times::set_times( path_out, - create_time.map(|t| SystemTimeSpec::Absolute(t)), - modify_time.map(|t| SystemTimeSpec::Absolute(t)), + create_time.map(SystemTimeSpec::Absolute), + modify_time.map(SystemTimeSpec::Absolute), ); match set_times_result { Ok(_) => information!("Set file time succeed."), @@ -199,7 +195,7 @@ fn parse_encrypted_comment(meta: &TinyEncryptMeta, key: &[u8], nonce: &[u8]) -> if let Some(encrypted_comment) = &meta.encrypted_comment { match util::decode_base64(encrypted_comment) { Err(e) => warning!("Decode encrypted comment failed: {}", e), - Ok(ec_bytes) => match try_aes_gcm_decrypt_with_salt(&key, &nonce, SALT_COMMENT, &ec_bytes) { + Ok(ec_bytes) => match try_aes_gcm_decrypt_with_salt(key, nonce, SALT_COMMENT, &ec_bytes) { Err(e) => warning!("Decrypt encrypted comment failed: {}", e), Ok(decrypted_comment_bytes) => match String::from_utf8(decrypted_comment_bytes.clone()) { Err(_) => success!("Encrypted message hex: {}", hex::encode(&decrypted_comment_bytes)), @@ -218,7 +214,7 @@ fn parse_encrypted_meta(meta: &TinyEncryptMeta, key: &[u8], nonce: &[u8]) -> XRe let enc_encrypted_meta_bytes = opt_result!( util::decode_base64(enc_encrypted_meta), "Decode enc-encrypted-meta failed: {}"); let enc_meta = opt_result!( - EncEncryptedMeta::unseal(&key, &nonce, &enc_encrypted_meta_bytes), "Unseal enc-encrypted-meta failed: {}"); + EncEncryptedMeta::unseal(key, nonce, &enc_encrypted_meta_bytes), "Unseal enc-encrypted-meta failed: {}"); if let Some(filename) = &enc_meta.filename { information!("Source filename: {}", filename); } diff --git a/src/cmd_encrypt.rs b/src/cmd_encrypt.rs index 1ba0727..fa37776 100644 --- a/src/cmd_encrypt.rs +++ b/src/cmd_encrypt.rs @@ -7,7 +7,7 @@ use std::time::Instant; use clap::Args; use flate2::Compression; use rsa::Pkcs1v15Encrypt; -use rust_util::{debugging, failure, information, opt_result, simple_error, success, util_msg, warning, XResult}; +use rust_util::{debugging, failure, iff, information, opt_result, simple_error, success, util_msg, XResult}; use rust_util::util_time::UnixEpochTime; use zeroize::Zeroize; @@ -125,8 +125,8 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en let file_metadata = opt_result!(fs::metadata(path), "Read file: {} meta failed: {}", path.display()); let enc_encrypted_meta = EncEncryptedMeta { filename: Some(util::get_file_name(path)), - c_time: file_metadata.created().ok().map(|t| t.to_millis()).flatten(), - m_time: file_metadata.modified().ok().map(|t| t.to_millis()).flatten(), + c_time: file_metadata.created().ok().and_then(|t| t.to_millis()), + m_time: file_metadata.modified().ok().and_then(|t| t.to_millis()), }; let enc_encrypted_meta_bytes = opt_result!(enc_encrypted_meta.seal(&key, &nonce), "Seal enc-encrypted-meta failed: {}"); @@ -141,54 +141,55 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en debugging!("Encrypted meta: {:?}", encrypt_meta); if cmd_encrypt.compatible_with_1_0 { - if !cmd_encrypt.disable_compress_meta { - return simple_error!("Compatible with 1.0 mode must turns --disable-compress-meta on."); - } - - if let Some(envelops) = encrypt_meta.envelops { - let mut filter_envelops = vec![]; - for envelop in envelops { - if (envelop.r#type == TinyEncryptEnvelopType::Pgp) && encrypt_meta.pgp_envelop.is_none() { - encrypt_meta.pgp_fingerprint = Some(format!("KID:{}", envelop.kid)); - encrypt_meta.pgp_envelop = Some(envelop.encrypted_key.clone()); - } else if (envelop.r#type == TinyEncryptEnvelopType::Ecdh) && encrypt_meta.ecdh_envelop.is_none() { - encrypt_meta.ecdh_point = Some(format!("KID:{}", envelop.kid)); - encrypt_meta.ecdh_envelop = Some(envelop.encrypted_key.clone()); - } else { - filter_envelops.push(envelop); - } - } - encrypt_meta.envelops = if filter_envelops.is_empty() { None } else { Some(filter_envelops) }; - if encrypt_meta.envelops.is_none() { - encrypt_meta.version = TINY_ENCRYPT_VERSION_10.to_string(); - } - } + encrypt_meta = process_compatible_with_1_0(cmd_encrypt, encrypt_meta)?; } let mut file_out = File::create(&path_out)?; let compress_meta = !cmd_encrypt.disable_compress_meta; let _ = file::write_tiny_encrypt_meta(&mut file_out, &encrypt_meta, compress_meta)?; + let compress_desc = iff!(cmd_encrypt.compress, " [with compress]", ""); let start = Instant::now(); - util_msg::print_lastline(&format!("Encrypting file: {} ...", path_display)); + util_msg::print_lastline( + &format!("Encrypting file: {}{} ...", path_display, compress_desc) + ); encrypt_file(&mut file_in, &mut file_out, &key, &nonce, cmd_encrypt.compress, &cmd_encrypt.compress_level)?; util_msg::clear_lastline(); let encrypt_duration = start.elapsed(); - debugging!("Encrypt file: {} elapsed: {} ms", path_display, encrypt_duration.as_millis()); + debugging!("Inner encrypt file{}: {} elapsed: {} ms", compress_desc, path_display, encrypt_duration.as_millis()); util::zeroize(key); util::zeroize(nonce); drop(file_in); drop(file_out); - if cmd_encrypt.remove_file { - match fs::remove_file(path) { - Err(e) => warning!("Remove file: {} failed: {}", path_display, e), - Ok(_) => information!("Remove file: {} succeed", path_display), - } - } + if cmd_encrypt.remove_file { util::remove_file_with_msg(path); } Ok(file_metadata.len()) } +fn process_compatible_with_1_0(cmd_encrypt: &CmdEncrypt, mut encrypt_meta: TinyEncryptMeta) -> XResult { + if !cmd_encrypt.disable_compress_meta { + return simple_error!("Compatible with 1.0 mode must turns --disable-compress-meta on."); + } + if let Some(envelops) = encrypt_meta.envelops { + let mut filter_envelops = vec![]; + for envelop in envelops { + if (envelop.r#type == TinyEncryptEnvelopType::Pgp) && encrypt_meta.pgp_envelop.is_none() { + encrypt_meta.pgp_fingerprint = Some(format!("KID:{}", envelop.kid)); + encrypt_meta.pgp_envelop = Some(envelop.encrypted_key.clone()); + } else if (envelop.r#type == TinyEncryptEnvelopType::Ecdh) && encrypt_meta.ecdh_envelop.is_none() { + encrypt_meta.ecdh_point = Some(format!("KID:{}", envelop.kid)); + encrypt_meta.ecdh_envelop = Some(envelop.encrypted_key.clone()); + } else { + filter_envelops.push(envelop); + } + } + encrypt_meta.envelops = if filter_envelops.is_empty() { None } else { Some(filter_envelops) }; + if encrypt_meta.envelops.is_none() { + encrypt_meta.version = TINY_ENCRYPT_VERSION_10.to_string(); + } + } + Ok(encrypt_meta) +} fn encrypt_file(file_in: &mut File, file_out: &mut File, key: &[u8], nonce: &[u8], compress: bool, compress_level: &Option) -> XResult { let mut total_len = 0; diff --git a/src/util.rs b/src/util.rs index 2956914..9087462 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,15 +1,22 @@ use std::{fs, io}; use std::io::Write; -use std::path::Path; +use std::path::{Path, PathBuf}; use base64::Engine; use base64::engine::general_purpose; use rand::random; -use rust_util::{simple_error, warning, XResult}; +use rust_util::{information, simple_error, warning, XResult}; use zeroize::Zeroize; use crate::consts::TINY_ENC_FILE_EXT; +pub fn remove_file_with_msg(path: &PathBuf) { + match fs::remove_file(path) { + Err(e) => warning!("Remove file: {} failed: {}", path.display(), e), + Ok(_) => information!("Remove file: {} succeed", path.display()), + } +} + pub fn get_file_name(path: &Path) -> String { let path_display = format!("{}", path.display()); if path_display.contains('/') {