feat: v0.2.2, auto find PIV slot id
This commit is contained in:
Generated
+1
-1
@@ -2063,7 +2063,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiny-encrypt"
|
name = "tiny-encrypt"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm-stream",
|
"aes-gcm-stream",
|
||||||
"base64",
|
"base64",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tiny-encrypt"
|
name = "tiny-encrypt"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
description = "A simple and tiny file encrypt tool"
|
description = "A simple and tiny file encrypt tool"
|
||||||
|
|||||||
+34
-10
@@ -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 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::prelude::FromDer;
|
||||||
use x509_parser::x509::SubjectPublicKeyInfo;
|
use x509_parser::x509::SubjectPublicKeyInfo;
|
||||||
use yubikey::piv::{AlgorithmId, decrypt_data, RetiredSlotId, SlotId};
|
|
||||||
use yubikey::YubiKey;
|
use yubikey::YubiKey;
|
||||||
|
use yubikey::piv::{AlgorithmId, decrypt_data, RetiredSlotId, SlotId};
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use crate::{card, file, util};
|
use crate::{card, file, util};
|
||||||
use crate::compress::GzStreamDecoder;
|
use crate::compress::GzStreamDecoder;
|
||||||
|
use crate::config::TinyEncryptConfig;
|
||||||
use crate::crypto_aes::aes_gcm_decrypt;
|
use crate::crypto_aes::aes_gcm_decrypt;
|
||||||
use crate::spec::{TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta};
|
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;
|
use crate::wrap_key::WrapKey;
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
@@ -39,13 +40,15 @@ pub struct CmdDecrypt {
|
|||||||
|
|
||||||
pub fn decrypt(cmd_decrypt: CmdDecrypt) -> XResult<()> {
|
pub fn decrypt(cmd_decrypt: CmdDecrypt) -> XResult<()> {
|
||||||
debugging!("Cmd decrypt: {:?}", cmd_decrypt);
|
debugging!("Cmd decrypt: {:?}", cmd_decrypt);
|
||||||
|
let config = TinyEncryptConfig::load(TINY_ENC_CONFIG_FILE).ok();
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut succeed_count = 0;
|
let mut succeed_count = 0;
|
||||||
let mut failed_count = 0;
|
let mut failed_count = 0;
|
||||||
let mut total_len = 0_u64;
|
let mut total_len = 0_u64;
|
||||||
for path in &cmd_decrypt.paths {
|
for path in &cmd_decrypt.paths {
|
||||||
let start_decrypt_single = Instant::now();
|
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) => {
|
Ok(len) => {
|
||||||
succeed_count += 1;
|
succeed_count += 1;
|
||||||
total_len += len;
|
total_len += len;
|
||||||
@@ -74,7 +77,11 @@ pub fn decrypt(cmd_decrypt: CmdDecrypt) -> XResult<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrypt_single(path: &PathBuf, pin: &Option<String>, slot: &Option<String>, cmd_decrypt: &CmdDecrypt) -> XResult<u64> {
|
pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
|
||||||
|
path: &PathBuf,
|
||||||
|
pin: &Option<String>,
|
||||||
|
slot: &Option<String>,
|
||||||
|
cmd_decrypt: &CmdDecrypt) -> XResult<u64> {
|
||||||
let path_display = format!("{}", path.display());
|
let path_display = format!("{}", path.display());
|
||||||
util::require_tiny_enc_file_and_exists(path)?;
|
util::require_tiny_enc_file_and_exists(path)?;
|
||||||
|
|
||||||
@@ -87,7 +94,7 @@ pub fn decrypt_single(path: &PathBuf, pin: &Option<String>, slot: &Option<String
|
|||||||
|
|
||||||
let selected_envelop = select_envelop(&meta)?;
|
let selected_envelop = select_envelop(&meta)?;
|
||||||
|
|
||||||
let key = try_decrypt_key(selected_envelop, pin, slot)?;
|
let key = try_decrypt_key(config, selected_envelop, pin, slot)?;
|
||||||
let nonce = opt_result!(util::decode_base64(&meta.nonce), "Decode nonce failed: {}");
|
let nonce = opt_result!(util::decode_base64(&meta.nonce), "Decode nonce failed: {}");
|
||||||
|
|
||||||
debugging!("Decrypt key: {}", hex::encode(&key));
|
debugging!("Decrypt key: {}", hex::encode(&key));
|
||||||
@@ -154,18 +161,24 @@ fn decrypt_file(file_in: &mut File, file_out: &mut File, key: &[u8], nonce: &[u8
|
|||||||
Ok(total_len)
|
Ok(total_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_decrypt_key(envelop: &TinyEncryptEnvelop, pin: &Option<String>, slot: &Option<String>) -> XResult<Vec<u8>> {
|
fn try_decrypt_key(config: &Option<TinyEncryptConfig>,
|
||||||
|
envelop: &TinyEncryptEnvelop,
|
||||||
|
pin: &Option<String>,
|
||||||
|
slot: &Option<String>) -> XResult<Vec<u8>> {
|
||||||
match envelop.r#type {
|
match envelop.r#type {
|
||||||
TinyEncryptEnvelopType::Pgp => try_decrypt_key_pgp(envelop, pin),
|
TinyEncryptEnvelopType::Pgp => try_decrypt_key_pgp(envelop, pin),
|
||||||
TinyEncryptEnvelopType::PgpX25519 => try_decrypt_key_ecdh_pgp_x25519(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 => {
|
unknown_type => {
|
||||||
return simple_error!("Unknown or not supported type: {}", unknown_type.get_name());
|
return simple_error!("Unknown or not supported type: {}", unknown_type.get_name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_decrypt_key_ecdh(envelop: &TinyEncryptEnvelop, pin: &Option<String>, slot: &Option<String>) -> XResult<Vec<u8>> {
|
fn try_decrypt_key_ecdh(config: &Option<TinyEncryptConfig>,
|
||||||
|
envelop: &TinyEncryptEnvelop,
|
||||||
|
pin: &Option<String>,
|
||||||
|
slot: &Option<String>) -> XResult<Vec<u8>> {
|
||||||
let wrap_key = WrapKey::parse(&envelop.encrypted_key)?;
|
let wrap_key = WrapKey::parse(&envelop.encrypted_key)?;
|
||||||
if wrap_key.header.enc.as_str() != ENC_AES256_GCM_P256 {
|
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);
|
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<String>, slot
|
|||||||
let e_pub_key_bytes = opt_result!(util::decode_base64_url_no_pad(e_pub_key), "Invalid envelop: {}");
|
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 (_, 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 pin = read_pin(pin);
|
||||||
let epk_bytes = subject_public_key_info.subject_public_key.as_ref();
|
let epk_bytes = subject_public_key_info.subject_public_key.as_ref();
|
||||||
|
|
||||||
@@ -252,10 +265,20 @@ fn get_openpgp() -> XResult<OpenPgp> {
|
|||||||
Ok(OpenPgp::new(card))
|
Ok(OpenPgp::new(card))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_slot(slot: &Option<String>) -> XResult<String> {
|
fn read_slot(config: &Option<TinyEncryptConfig>, kid: &str, slot: &Option<String>) -> XResult<String> {
|
||||||
match slot {
|
match slot {
|
||||||
Some(slot) => Ok(slot.to_string()),
|
Some(slot) => Ok(slot.to_string()),
|
||||||
None => {
|
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 ...): ");
|
print!("Input slot(eg 82, 83 ...): ");
|
||||||
io::stdout().flush().ok();
|
io::stdout().flush().ok();
|
||||||
let mut buff = String::new();
|
let mut buff = String::new();
|
||||||
@@ -294,6 +317,7 @@ fn select_envelop(meta: &TinyEncryptMeta) -> XResult<&TinyEncryptEnvelop> {
|
|||||||
if envelops.len() == 1 {
|
if envelops.len() == 1 {
|
||||||
let selected_envelop = &envelops[0];
|
let selected_envelop = &envelops[0];
|
||||||
success!("Auto selected envelop: #{} {}", 1, selected_envelop.r#type.get_upper_name());
|
success!("Auto selected envelop: #{} {}", 1, selected_envelop.r#type.get_upper_name());
|
||||||
|
util::read_line("Press enter to continue: ");
|
||||||
return Ok(selected_envelop);
|
return Ok(selected_envelop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,10 @@ impl TinyEncryptConfig {
|
|||||||
Ok(config)
|
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<String>) -> XResult<Vec<&TinyEncryptConfigEnvelop>> {
|
pub fn find_envelops(&self, profile: &Option<String>) -> XResult<Vec<&TinyEncryptConfigEnvelop>> {
|
||||||
let profile = profile.as_ref().map(String::as_str).unwrap_or("default");
|
let profile = profile.as_ref().map(String::as_str).unwrap_or("default");
|
||||||
debugging!("Profile: {}", profile);
|
debugging!("Profile: {}", profile);
|
||||||
|
|||||||
@@ -133,3 +133,11 @@ pub fn zeroize(object: impl Zeroize) {
|
|||||||
let mut object = object;
|
let mut object = object;
|
||||||
object.zeroize();
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user