diff --git a/Cargo.lock b/Cargo.lock index 7ebdcdb..c44e720 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2063,7 +2063,7 @@ dependencies = [ [[package]] name = "tiny-encrypt" -version = "0.2.1" +version = "0.2.2" dependencies = [ "aes-gcm-stream", "base64", diff --git a/Cargo.toml b/Cargo.toml index 312c984..2bd63f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tiny-encrypt" -version = "0.2.1" +version = "0.2.2" edition = "2021" license = "MIT" description = "A simple and tiny file encrypt tool" diff --git a/src/cmd_decrypt.rs b/src/cmd_decrypt.rs index 05124a0..4847663 100644 --- a/src/cmd_decrypt.rs +++ b/src/cmd_decrypt.rs @@ -11,15 +11,16 @@ use openpgp_card::crypto_data::Cryptogram; use rust_util::{debugging, failure, iff, information, opt_result, simple_error, success, util_msg, util_term, warning, XResult}; use x509_parser::prelude::FromDer; use x509_parser::x509::SubjectPublicKeyInfo; -use yubikey::piv::{AlgorithmId, decrypt_data, RetiredSlotId, SlotId}; use yubikey::YubiKey; +use yubikey::piv::{AlgorithmId, decrypt_data, RetiredSlotId, SlotId}; use zeroize::Zeroize; use crate::{card, file, util}; use crate::compress::GzStreamDecoder; +use crate::config::TinyEncryptConfig; use crate::crypto_aes::aes_gcm_decrypt; use crate::spec::{TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta}; -use crate::util::{ENC_AES256_GCM_P256, ENC_AES256_GCM_X25519, TINY_ENC_FILE_EXT}; +use crate::util::{ENC_AES256_GCM_P256, ENC_AES256_GCM_X25519, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT}; use crate::wrap_key::WrapKey; #[derive(Debug, Args)] @@ -39,13 +40,15 @@ pub struct CmdDecrypt { pub fn decrypt(cmd_decrypt: CmdDecrypt) -> XResult<()> { debugging!("Cmd decrypt: {:?}", cmd_decrypt); + let config = TinyEncryptConfig::load(TINY_ENC_CONFIG_FILE).ok(); + let start = Instant::now(); let mut succeed_count = 0; let mut failed_count = 0; let mut total_len = 0_u64; for path in &cmd_decrypt.paths { let start_decrypt_single = Instant::now(); - match decrypt_single(path, &cmd_decrypt.pin, &cmd_decrypt.slot, &cmd_decrypt) { + match decrypt_single(&config, path, &cmd_decrypt.pin, &cmd_decrypt.slot, &cmd_decrypt) { Ok(len) => { succeed_count += 1; total_len += len; @@ -74,7 +77,11 @@ pub fn decrypt(cmd_decrypt: CmdDecrypt) -> XResult<()> { Ok(()) } -pub fn decrypt_single(path: &PathBuf, pin: &Option, slot: &Option, cmd_decrypt: &CmdDecrypt) -> XResult { +pub fn decrypt_single(config: &Option, + path: &PathBuf, + pin: &Option, + slot: &Option, + cmd_decrypt: &CmdDecrypt) -> XResult { let path_display = format!("{}", path.display()); util::require_tiny_enc_file_and_exists(path)?; @@ -87,7 +94,7 @@ pub fn decrypt_single(path: &PathBuf, pin: &Option, slot: &Option, slot: &Option) -> XResult> { +fn try_decrypt_key(config: &Option, + envelop: &TinyEncryptEnvelop, + pin: &Option, + slot: &Option) -> XResult> { match envelop.r#type { TinyEncryptEnvelopType::Pgp => try_decrypt_key_pgp(envelop, pin), TinyEncryptEnvelopType::PgpX25519 => try_decrypt_key_ecdh_pgp_x25519(envelop, pin), - TinyEncryptEnvelopType::Ecdh => try_decrypt_key_ecdh(envelop, pin, slot), + TinyEncryptEnvelopType::Ecdh => try_decrypt_key_ecdh(config, envelop, pin, slot), unknown_type => { return simple_error!("Unknown or not supported type: {}", unknown_type.get_name()); } } } -fn try_decrypt_key_ecdh(envelop: &TinyEncryptEnvelop, pin: &Option, slot: &Option) -> XResult> { +fn try_decrypt_key_ecdh(config: &Option, + envelop: &TinyEncryptEnvelop, + pin: &Option, + slot: &Option) -> XResult> { let wrap_key = WrapKey::parse(&envelop.encrypted_key)?; if wrap_key.header.enc.as_str() != ENC_AES256_GCM_P256 { return simple_error!("Unsupported header requires: {}, actual: {}", ENC_AES256_GCM_P256, &wrap_key.header.enc); @@ -174,7 +187,7 @@ fn try_decrypt_key_ecdh(envelop: &TinyEncryptEnvelop, pin: &Option, slot let e_pub_key_bytes = opt_result!(util::decode_base64_url_no_pad(e_pub_key), "Invalid envelop: {}"); let (_, subject_public_key_info) = opt_result!(SubjectPublicKeyInfo::from_der(&e_pub_key_bytes), "Invalid envelop: {}"); - let slot = read_slot(slot)?; + let slot = read_slot(config, &envelop.kid, slot)?; let pin = read_pin(pin); let epk_bytes = subject_public_key_info.subject_public_key.as_ref(); @@ -252,10 +265,20 @@ fn get_openpgp() -> XResult { Ok(OpenPgp::new(card)) } -fn read_slot(slot: &Option) -> XResult { +fn read_slot(config: &Option, kid: &str, slot: &Option) -> XResult { match slot { Some(slot) => Ok(slot.to_string()), None => { + if let Some(config) = config { + if let Some(e) = config.find_by_kid(kid) { + if let Some(args) = &e.args { + if let Some(first_arg) = args.iter().next() { + information!("Found kid: {}'s slot: {}", kid, first_arg); + return Ok(first_arg.to_string()); + } + } + } + } print!("Input slot(eg 82, 83 ...): "); io::stdout().flush().ok(); let mut buff = String::new(); @@ -294,6 +317,7 @@ fn select_envelop(meta: &TinyEncryptMeta) -> XResult<&TinyEncryptEnvelop> { if envelops.len() == 1 { let selected_envelop = &envelops[0]; success!("Auto selected envelop: #{} {}", 1, selected_envelop.r#type.get_upper_name()); + util::read_line("Press enter to continue: "); return Ok(selected_envelop); } diff --git a/src/config.rs b/src/config.rs index c2a8b42..e1c1e16 100644 --- a/src/config.rs +++ b/src/config.rs @@ -72,6 +72,10 @@ impl TinyEncryptConfig { Ok(config) } + pub fn find_by_kid(&self, kid: &str) -> Option<&TinyEncryptConfigEnvelop> { + self.envelops.iter().find(|e| e.kid == kid) + } + pub fn find_envelops(&self, profile: &Option) -> XResult> { let profile = profile.as_ref().map(String::as_str).unwrap_or("default"); debugging!("Profile: {}", profile); diff --git a/src/util.rs b/src/util.rs index 5ec4896..2dd3db0 100644 --- a/src/util.rs +++ b/src/util.rs @@ -133,3 +133,11 @@ pub fn zeroize(object: impl Zeroize) { let mut object = object; object.zeroize(); } + +pub fn read_line(ln: &str) { + print!("{}", ln); + io::stdout().flush().ok(); + let mut buff = String::new(); + let _ = io::stdin().read_line(&mut buff).expect("Read line from stdin"); +} +