feat: v0.2.2, auto find PIV slot id

This commit is contained in:
2023-10-09 00:42:30 +08:00
parent 196d500c51
commit 6833a1a7d3
5 changed files with 48 additions and 12 deletions

2
Cargo.lock generated
View File

@@ -2063,7 +2063,7 @@ dependencies = [
[[package]]
name = "tiny-encrypt"
version = "0.2.1"
version = "0.2.2"
dependencies = [
"aes-gcm-stream",
"base64",

View File

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

View File

@@ -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<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());
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 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: {}");
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)
}
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 {
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<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)?;
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<String>, 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<OpenPgp> {
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 {
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);
}

View File

@@ -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<String>) -> XResult<Vec<&TinyEncryptConfigEnvelop>> {
let profile = profile.as_ref().map(String::as_str).unwrap_or("default");
debugging!("Profile: {}", profile);

View File

@@ -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");
}