From 89ed3c26edf646309c6786714bae9988b40e94d0 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sat, 28 Oct 2023 16:41:07 +0800 Subject: [PATCH] feat: update dependencies, optimize --- Cargo.lock | 8 ++++---- src/cmd_decrypt.rs | 40 ++++++++++++++++++---------------------- src/cmd_encrypt.rs | 18 ++++++++---------- src/cmd_info.rs | 3 +-- src/crypto_cryptor.rs | 12 ++++++++---- src/util.rs | 2 +- src/util_digest.rs | 4 ++-- src/util_enc_file.rs | 2 +- src/util_env.rs | 5 +++++ src/util_file.rs | 4 ++-- src/util_progress.rs | 38 ++++++++++++++++++++++++++++---------- src/wrap_key.rs | 28 +++++++++++++++++++++------- 12 files changed, 99 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6a6124..1ad5a22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -611,9 +611,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +checksum = "a481586acf778f1b1455424c343f71124b048ffa5f4fc3f8f6ae9dc432dcb3c7" [[package]] name = "flagset" @@ -1378,9 +1378,9 @@ dependencies = [ [[package]] name = "rust_util" -version = "0.6.45" +version = "0.6.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c3036388284b69995eb2864a943b0de55de76ad5b56fc2d3c60fecd7b9ad82" +checksum = "cffc8cab4e18f1320f13ac0c357b4bef1c120723885a187799440440e563f7a4" dependencies = [ "lazy_static", "libc", diff --git a/src/cmd_decrypt.rs b/src/cmd_decrypt.rs index e733de9..e145511 100644 --- a/src/cmd_decrypt.rs +++ b/src/cmd_decrypt.rs @@ -5,11 +5,7 @@ use std::time::{Instant, SystemTime}; use clap::Args; use openpgp_card::crypto_data::Cryptogram; -use rust_util::{ - debugging, failure, iff, information, opt_result, - println_ex, simple_error, success, util_msg, - warning, XResult, -}; +use rust_util::{debugging, failure, iff, information, opt_result, println_ex, simple_error, success, util_msg, util_size, warning, XResult}; use rust_util::util_time::UnixEpochTime; use x509_parser::prelude::FromDer; use x509_parser::x509::SubjectPublicKeyInfo; @@ -85,10 +81,10 @@ pub fn decrypt(cmd_decrypt: CmdDecrypt) -> XResult<()> { succeed_count += 1; total_len += len; success!( - "Decrypt {} succeed, cost {} ms, file size {} byte(s)", + "Decrypt {} succeed, cost {} ms, file size {}", path.to_str().unwrap_or("N/A"), start_decrypt_single.elapsed().as_millis(), - len + util_size::get_display_size(len as i64) ); } Err(e) => { @@ -99,9 +95,9 @@ pub fn decrypt(cmd_decrypt: CmdDecrypt) -> XResult<()> { } if (succeed_count + failed_count) > 1 { success!( - "Decrypt succeed {} file(s) {} byte(s), failed {} file(s), total cost {} ms", + "Decrypt succeed {} file(s) {}, failed {} file(s), total cost {} ms", succeed_count, - total_len, + util_size::get_display_size(total_len as i64), failed_count, start.elapsed().as_millis(), ); @@ -120,7 +116,9 @@ pub fn decrypt_single(config: &Option, let mut file_in = opt_result!(File::open(path), "Open file: {} failed: {}", &path_display); let (_, meta) = opt_result!( 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()); + util_msg::when_debug(|| { + debugging!("Found meta: {}", serde_json::to_string_pretty(&meta).unwrap()); + }); let encryption_algorithm = meta.encryption_algorithm.as_deref() .unwrap_or(consts::TINY_ENC_AES_GCM); @@ -143,12 +141,12 @@ pub fn decrypt_single(config: &Option, let key_nonce = KeyNonce { k: &key.0, n: &nonce.0 }; // debugging!("Decrypt key: {}", hex::encode(&key.0)); - debugging!("Decrypt nonce: {}", hex::encode(&nonce.0)); + util_msg::when_debug(|| debugging!("Decrypt nonce: {}", hex::encode(&nonce.0))); let enc_meta = parse_encrypted_meta(&meta, cryptor, &key_nonce)?; parse_encrypted_comment(&meta, cryptor, &key_nonce)?; - // Decrypt to output +// Decrypt to output if cmd_decrypt.direct_print { if meta.file_length > 10 * 1024 { warning!("File too large(more than 10K) cannot direct print on console."); @@ -170,7 +168,7 @@ pub fn decrypt_single(config: &Option, return Ok(meta.file_length); } - // Digest file +// Digest file if cmd_decrypt.digest_file { let mut digest_write = DigestWrite::from_algo(digest_algorithm)?; let _ = decrypt_file( @@ -186,7 +184,7 @@ pub fn decrypt_single(config: &Option, return Ok(0); } - // Decrypt to file +// Decrypt to file let compressed_desc = iff!(meta.compress, " [compressed]", ""); let start = Instant::now(); @@ -195,12 +193,12 @@ pub fn decrypt_single(config: &Option, &mut file_in, meta.file_length, &mut file_out, cryptor, &key_nonce, meta.compress, )?; drop(file_out); - util_file::update_out_file_time(enc_meta, path_out); + util_file::update_file_time(enc_meta, path_out); let encrypt_duration = start.elapsed(); debugging!("Inner decrypt file{}: {} elapsed: {} ms", compressed_desc, path_display, encrypt_duration.as_millis()); - if do_skip_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) } @@ -224,7 +222,7 @@ fn decrypt_file(file_in: &mut File, file_len: u64, file_out: &mut impl Write, last_block }; opt_result!(file_out.write_all(&last_block), "Write file failed: {}"); - debugging!("Decrypt finished, total bytes: {}", total_len); + debugging!("Decrypt finished, total: {} byte(s)", total_len); progress.finish(); break; } else { @@ -305,8 +303,7 @@ fn try_decrypt_key_ecdh(config: &Option, ENC_CHACHA20_POLY1305_P384 => (Cryptor::ChaCha20Poly1305, AlgorithmId::EccP384), _ => return simple_error!("Unsupported header enc: {}", &wrap_key.header.enc), }; - let e_pub_key = &wrap_key.header.e_pub_key; - let e_pub_key_bytes = opt_result!(util::decode_base64_url_no_pad(e_pub_key), "Invalid envelop: {}"); + let e_pub_key_bytes = wrap_key.header.get_e_pub_key_bytes()?; let (_, subject_public_key_info) = opt_result!( SubjectPublicKeyInfo::from_der(&e_pub_key_bytes), "Invalid envelop: {}"); @@ -341,15 +338,14 @@ fn try_decrypt_key_ecdh_pgp_x25519(envelop: &TinyEncryptEnvelop, pin: &Option Cryptor::ChaCha20Poly1305, _ => return simple_error!("Unsupported header enc: {}", &wrap_key.header.enc), }; - let e_pub_key = &wrap_key.header.e_pub_key; - let epk_bytes = opt_result!(util::decode_base64_url_no_pad(e_pub_key), "Invalid envelop: {}"); + let e_pub_key_bytes = wrap_key.header.get_e_pub_key_bytes()?; let mut pgp = util_pgp::get_openpgp()?; let mut trans = opt_result!(pgp.transaction(), "Connect PIV card failed: {}"); util_pgp::read_and_verify_openpgp_pin(&mut trans, pin)?; - let shared_secret = trans.decipher(Cryptogram::ECDH(&epk_bytes))?; + let shared_secret = trans.decipher(Cryptogram::ECDH(&e_pub_key_bytes))?; let key = util::simple_kdf(shared_secret.as_slice()); let key_nonce = KeyNonce { k: &key, n: &wrap_key.nonce }; diff --git a/src/cmd_encrypt.rs b/src/cmd_encrypt.rs index 6c2c595..3c80df0 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, iff, information, opt_result, simple_error, success, XResult}; +use rust_util::{debugging, failure, iff, information, opt_result, simple_error, success, util_size, XResult}; use rust_util::util_time::UnixEpochTime; use crate::{crypto_cryptor, crypto_simple, util, util_enc_file, util_env, util_p256, util_p384, util_x25519}; @@ -194,7 +194,7 @@ fn encrypt_file(file_in: &mut File, file_len: u64, file_out: &mut impl Write, cr None => GzStreamEncoder::new_default(), Some(compress_level) => { if *compress_level > 9 { - return simple_error!("Compress level must in range [0, 9]"); + return simple_error!("Compress level must be in range [0, 9]"); } GzStreamEncoder::new(Compression::new(*compress_level)) } @@ -221,10 +221,12 @@ fn encrypt_file(file_in: &mut File, file_len: u64, file_out: &mut impl Write, cr }; opt_result!(file_out.write_all(&last_block_and_tag), "Write file failed: {}"); progress.finish(); - debugging!("Encrypt finished, total bytes: {}", total_len); + debugging!("Encrypt finished, total bytes: {} byte(s)", total_len); if compress { - information!("File is compressed: {} byte(s) -> {} byte(s), ratio: {}%", - total_len, write_len, util::ratio(write_len, total_len)); + information!("File is compressed: {} -> {}, ratio: {}%", + util_size::get_display_size(total_len as i64), + util_size::get_display_size(write_len as i64), + util::ratio(write_len, total_len)); } break; } else { @@ -309,11 +311,7 @@ fn encrypt_envelop_shared_secret(cryptor: Cryptor, cryptor, &key_nonce, key)?; let wrap_key = WrapKey { - header: WrapKeyHeader { - kid: None, - enc: enc_type.to_string(), - e_pub_key: util::encode_base64_url_no_pad(ephemeral_spki), - }, + header: WrapKeyHeader::from(enc_type, ephemeral_spki), nonce: nonce.0.clone(), encrypted_data: encrypted_key, }; diff --git a/src/cmd_info.rs b/src/cmd_info.rs index e5ced51..19b0487 100644 --- a/src/cmd_info.rs +++ b/src/cmd_info.rs @@ -8,7 +8,6 @@ use rust_util::{ debugging, failure, iff, opt_result, simple_error, success, util_msg, util_size, util_time, XResult, }; -use rust_util::util_msg::MessageType; use rust_util::util_time::UnixEpochTime; use simpledateformat::format_human2; @@ -97,7 +96,7 @@ pub fn info_single(path: &PathBuf, cmd_info: &CmdInfo) -> XResult<()> { header(&format!("Envelop #{}", i + 1)), util_envelop::format_envelop(envelop, &config) )); - util_msg::when(MessageType::DEBUG, || { + util_msg::when_debug(|| { if let Ok(wrap_key) = WrapKey::parse(&envelop.encrypted_key) { debugging!("Wrap key: {}", serde_json::to_string(&wrap_key).expect("SHOULD NOT HAPPEN")); } diff --git a/src/crypto_cryptor.rs b/src/crypto_cryptor.rs index 2d6cdfa..af6064c 100644 --- a/src/crypto_cryptor.rs +++ b/src/crypto_cryptor.rs @@ -74,14 +74,16 @@ fn get_encryptor(crypto: Cryptor, key_nonce: &KeyNonce) -> XResult { let mut key: [u8; 32] = opt_result!(key_nonce.k.try_into(), "Bad AES 256 key: {}"); - let aes256_gcm_stream_encryptor = Aes256GcmStreamEncryptor::new(key, key_nonce.n); + let aes256_gcm_stream_encryptor = Aes256GcmStreamEncryptor::new( + key, key_nonce.n); key.zeroize(); Ok(Box::new(Aes256GcmEncryptor { aes256_gcm_stream_encryptor, })) } Cryptor::ChaCha20Poly1305 => Ok(Box::new(ChaCha20Poly1305Encryptor { - chacha20_poly1305_stream_encryptor: ChaCha20Poly1305StreamEncryptor::new(key_nonce.k, key_nonce.n)?, + chacha20_poly1305_stream_encryptor: ChaCha20Poly1305StreamEncryptor::new( + key_nonce.k, key_nonce.n)?, })) } } @@ -90,14 +92,16 @@ fn get_decryptor(crypto: Cryptor, key_nonce: &KeyNonce) -> XResult { let mut key: [u8; 32] = opt_result!(key_nonce.k.try_into(), "Bad AES 256 key: {}"); - let aes256_gcm_stream_decryptor = Aes256GcmStreamDecryptor::new(key, key_nonce.n); + let aes256_gcm_stream_decryptor = Aes256GcmStreamDecryptor::new( + key, key_nonce.n); key.zeroize(); Ok(Box::new(Aes256GcmDecryptor { aes256_gcm_stream_decryptor, })) } Cryptor::ChaCha20Poly1305 => Ok(Box::new(ChaCha20Poly1305Decryptor { - chacha20_poly1305_stream_decryptor: ChaCha20Poly1305StreamDecryptor::new(key_nonce.k, key_nonce.n)?, + chacha20_poly1305_stream_decryptor: ChaCha20Poly1305StreamDecryptor::new( + key_nonce.k, key_nonce.n)?, })) } } diff --git a/src/util.rs b/src/util.rs index 572be38..00669ea 100644 --- a/src/util.rs +++ b/src/util.rs @@ -96,7 +96,7 @@ pub fn make_key256_and_nonce() -> (SecVec, SecVec) { pub fn simple_kdf(input: &[u8]) -> Vec { let mut input = input.to_vec(); for _ in 0..8 { - let mut sha256 = DigestWrite::sha256().expect("SHOULD NOT HAPPEN"); + let mut sha256 = DigestWrite::sha256(); sha256.write_all(&input).expect("SHOULD NOT HAPPEN"); input = sha256.digest(); } diff --git a/src/util_digest.rs b/src/util_digest.rs index bf6fa62..c089a50 100644 --- a/src/util_digest.rs +++ b/src/util_digest.rs @@ -33,8 +33,8 @@ impl DigestWrite { } } - pub fn sha256() -> XResult { - Ok(Self { digest: Box::new(Sha256::new()) }) + pub fn sha256() -> Self { + Self { digest: Box::new(Sha256::new()) } } pub fn digest(self) -> Vec { diff --git a/src/util_enc_file.rs b/src/util_enc_file.rs index 00749f5..40c8906 100644 --- a/src/util_enc_file.rs +++ b/src/util_enc_file.rs @@ -46,7 +46,7 @@ pub fn read_tiny_encrypt_meta(r: &mut impl Read) -> XResult<(u32, TinyEncryptMet return simple_error!("Meta too large: {}", length); } - debugging!("Encrypted meta len: {}", length); + debugging!("Encrypted meta length: {}", length); let mut meta_buff = vec![0; length as usize]; opt_result!(r.read_exact(meta_buff.as_mut_slice()), "Read meta failed: {}"); diff --git a/src/util_env.rs b/src/util_env.rs index 3179b61..93f1b01 100644 --- a/src/util_env.rs +++ b/src/util_env.rs @@ -7,6 +7,7 @@ use crate::consts; pub const TINY_ENCRYPT_ENV_DEFAULT_ALGORITHM: &str = "TINY_ENCRYPT_DEFAULT_ALGORITHM"; pub const TINY_ENCRYPT_ENV_DEFAULT_COMPRESS: &str = "TINY_ENCRYPT_DEFAULT_COMPRESS"; +pub const TINY_ENCRYPT_ENV_NO_PROGRESS: &str = "TINY_ENCRYPT_NO_PROGRESS"; pub fn get_default_encryption_algorithm() -> Option<&'static str> { let env_default_algorithm = env::var(TINY_ENCRYPT_ENV_DEFAULT_ALGORITHM).ok(); @@ -24,4 +25,8 @@ pub fn get_default_encryption_algorithm() -> Option<&'static str> { pub fn get_default_compress() -> Option { iff!(rust_util_env::is_env_off(TINY_ENCRYPT_ENV_DEFAULT_COMPRESS), Some(true), None) +} + +pub fn get_no_progress() -> bool { + rust_util_env::is_env_on(TINY_ENCRYPT_ENV_NO_PROGRESS) } \ No newline at end of file diff --git a/src/util_file.rs b/src/util_file.rs index b8d0a3f..1ed6575 100644 --- a/src/util_file.rs +++ b/src/util_file.rs @@ -6,13 +6,13 @@ use rust_util::util_time::UnixEpochTime; use crate::spec::EncEncryptedMeta; -pub fn update_out_file_time(enc_meta: Option, path_out: &str) { +pub fn update_file_time(enc_meta: Option, path: &str) { if let Some(enc_meta) = &enc_meta { 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, + path, create_time.map(SystemTimeSpec::Absolute), modify_time.map(SystemTimeSpec::Absolute), ); diff --git a/src/util_progress.rs b/src/util_progress.rs index 0d55482..82368ff 100644 --- a/src/util_progress.rs +++ b/src/util_progress.rs @@ -1,28 +1,46 @@ use indicatif::{ProgressBar, ProgressStyle}; +use rust_util::{debugging, util_msg}; + +use crate::util_env; const PB_PROGRESS: &str = "#-"; const PB_TEMPLATE: &str = "{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} {bytes_per_sec} ({eta})"; -pub struct Progress { - progress_bar: ProgressBar, +pub enum Progress { + NoProgress, + Progress(ProgressBar), } impl Progress { pub fn new(total: u64) -> Self { - let progress_bar = ProgressBar::new(total); - progress_bar.set_style(ProgressStyle::default_bar() - .template(PB_TEMPLATE).expect("SHOULD NOT FAIL") - .progress_chars(PB_PROGRESS) - ); - Self { progress_bar } + let no_progress = util_env::get_no_progress(); + let is_atty = util_msg::is_atty(); + + if no_progress || !is_atty { + debugging!("No progress: [{}, {}]", no_progress, is_atty); + Self::NoProgress + } else { + let progress_bar = ProgressBar::new(total); + progress_bar.set_style(ProgressStyle::default_bar() + .template(PB_TEMPLATE).expect("SHOULD NOT FAIL") + .progress_chars(PB_PROGRESS) + ); + Self::Progress(progress_bar) + } } pub fn position(&self, position: u64) { - self.progress_bar.set_position(position) + match self { + Progress::NoProgress => {} + Progress::Progress(progress_bar) => progress_bar.set_position(position), + } } pub fn finish(&self) { - self.progress_bar.finish_and_clear() + match self { + Progress::NoProgress => {} + Progress::Progress(progress_bar) => progress_bar.finish_and_clear(), + } } } \ No newline at end of file diff --git a/src/wrap_key.rs b/src/wrap_key.rs index 49a1df0..05be6ae 100644 --- a/src/wrap_key.rs +++ b/src/wrap_key.rs @@ -1,7 +1,7 @@ use rust_util::{opt_result, simple_error, XResult}; use serde::{Deserialize, Serialize}; -use crate::util::{decode_base64_url_no_pad, encode_base64_url_no_pad}; +use crate::util; #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -20,17 +20,31 @@ pub struct WrapKeyHeader { pub e_pub_key: String, } +impl WrapKeyHeader { + pub fn from(enc_type: &str, ephemeral_spki: &[u8]) -> Self { + WrapKeyHeader { + kid: None, + enc: enc_type.to_string(), + e_pub_key: util::encode_base64_url_no_pad(ephemeral_spki), + } + } + + pub fn get_e_pub_key_bytes(self) -> XResult> { + Ok(opt_result!(util::decode_base64_url_no_pad(&self.e_pub_key), "Invalid envelop e_pub_key: {}")) + } +} + impl WrapKey { pub fn encode(&self) -> XResult { let mut buf = String::with_capacity(512); buf.push_str("WK:"); let header = serde_json::to_string(&self.header)?; - let header_str = encode_base64_url_no_pad(header.as_bytes()); + let header_str = util::encode_base64_url_no_pad(header.as_bytes()); buf.push_str(&header_str); buf.push('.'); - buf.push_str(&encode_base64_url_no_pad(&self.nonce)); + buf.push_str(&util::encode_base64_url_no_pad(&self.nonce)); buf.push('.'); - buf.push_str(&encode_base64_url_no_pad(&self.encrypted_data)); + buf.push_str(&util::encode_base64_url_no_pad(&self.encrypted_data)); Ok(buf) } @@ -43,13 +57,13 @@ impl WrapKey { return simple_error!("Invalid wrap key."); } let header = wks[0].chars().skip(3).collect::(); - let header_bytes = opt_result!(decode_base64_url_no_pad(&header), "Invalid wrap key header: {}"); + let header_bytes = opt_result!(util::decode_base64_url_no_pad(&header), "Invalid wrap key header: {}"); let nonce = wks[1]; let encrypted_data = wks[2]; let header_str = opt_result!(String::from_utf8(header_bytes), "Invalid wrap key header: {}"); let header: WrapKeyHeader = opt_result!(serde_json::from_str(&header_str), "Invalid wrap key header: {}"); - let nonce = opt_result!(decode_base64_url_no_pad(nonce), "Invalid wrap key: {}"); - let encrypted_data = opt_result!(decode_base64_url_no_pad(encrypted_data), "Invalid wrap key: {}"); + let nonce = opt_result!(util::decode_base64_url_no_pad(nonce), "Invalid wrap key: {}"); + let encrypted_data = opt_result!(util::decode_base64_url_no_pad(encrypted_data), "Invalid wrap key: {}"); Ok(WrapKey { header, nonce,