feat: v0.2.4, add config subcommand

This commit is contained in:
2023-10-10 22:28:05 +08:00
parent fe226d9b75
commit a68f5e0e00
7 changed files with 204 additions and 18 deletions

74
Cargo.lock generated
View File

@@ -231,6 +231,12 @@ version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "bytecount"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad152d03a2c813c80bb94fedbf3a3f02b28f793e39e7c214c8a0bcc196343de7"
[[package]]
name = "byteorder"
version = "1.5.0"
@@ -1289,6 +1295,17 @@ dependencies = [
"sha2",
]
[[package]]
name = "papergrid"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2ccbe15f2b6db62f9a9871642746427e297b0ceb85f9a7f1ee5ff47d184d0c8"
dependencies = [
"bytecount",
"fnv",
"unicode-width",
]
[[package]]
name = "pbkdf2"
version = "0.12.2"
@@ -1405,6 +1422,30 @@ dependencies = [
"elliptic-curve",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.68"
@@ -1979,6 +2020,30 @@ dependencies = [
"libc",
]
[[package]]
name = "tabled"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfe9c3632da101aba5131ed63f9eed38665f8b3c68703a6bb18124835c1a5d22"
dependencies = [
"papergrid",
"tabled_derive",
"unicode-width",
]
[[package]]
name = "tabled_derive"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99f688a08b54f4f02f0a3c382aefdb7884d3d69609f785bd253dc033243e3fe4"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "tempfile"
version = "3.8.0"
@@ -2063,7 +2128,7 @@ dependencies = [
[[package]]
name = "tiny-encrypt"
version = "0.2.3"
version = "0.2.4"
dependencies = [
"aes-gcm-stream",
"base64",
@@ -2084,6 +2149,7 @@ dependencies = [
"serde_json",
"sha256",
"simpledateformat",
"tabled",
"x25519-dalek",
"x509-parser",
"yubikey",
@@ -2214,6 +2280,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "unicode-xid"
version = "0.2.4"

View File

@@ -1,6 +1,6 @@
[package]
name = "tiny-encrypt"
version = "0.2.3"
version = "0.2.4"
edition = "2021"
license = "MIT"
description = "A simple and tiny file encrypt tool"
@@ -27,6 +27,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sha256 = "1.4"
simpledateformat = "0.1"
tabled = "0.14"
x25519-dalek = "2.0"
x509-parser = "0.15"
yubikey = { version = "0.8", features = ["untested"] }

View File

@@ -46,13 +46,12 @@ Encrypt config `~/.tinyencrypt/config-rs.json`:
Supported PKI encryption types:
| Type | Description |
|------------|------------------------|
| pgp | OpenPGP RSA PKCS1-v1.5 |
| pgp-x25519 | ECDH X25519 |
| ecdh | ECDH P256 |
| ecdh-p384 | ECDH P384 |
| Type | Algorithm | Description |
|------------|-----------------|------------------------|
| pgp | PKCS1-v1.5 | OpenPGP Encryption Key |
| pgp-x25519 | ECDH(X25519) | OpenPGP Encryption Key |
| ecdh | ECDH(secp256r1) | PIV Slot |
| ecdh-p384 | ECDH(secp384r1) | PIV Slot |
Smart Card(Yubikey) protected ECDH Encryption description:

66
src/cmd_config.rs Normal file
View File

@@ -0,0 +1,66 @@
use std::collections::HashMap;
use clap::Args;
use rust_util::XResult;
use tabled::{Table, Tabled};
use tabled::settings::Style;
use crate::config::TinyEncryptConfig;
use crate::util::TINY_ENC_CONFIG_FILE;
#[derive(Tabled)]
struct ConfigProfile {
profiles: String,
keys: String,
}
#[derive(Debug, Args)]
pub struct CmdConfig {}
pub fn config(_cmd_version: CmdConfig) -> XResult<()> {
let config = TinyEncryptConfig::load(TINY_ENC_CONFIG_FILE)?;
let mut reverse_map = HashMap::new();
for (p, v) in &config.profiles {
let p = p;
let mut v2 = v.clone();
v2.sort();
let vs = v2.join(",");
match reverse_map.get_mut(&vs) {
None => { reverse_map.insert(vs, vec![(p, v)]); }
Some(vec) => { vec.push((p, v)); }
}
}
let mut config_profiles = vec![];
for pvs in reverse_map.values() {
let mut ps: Vec<_> = pvs.iter().map(|pv| pv.0).collect();
ps.sort();
let pp = ps.iter().map(|s| s.to_string()).collect::<Vec<_>>().join(", ");
let kids = pvs[0].1;
let mut ks = Vec::with_capacity(kids.len());
for kid in kids {
match config.find_by_kid(kid) {
None => {
ks.push(format!("[ERROR] Key not found: {}", kid));
}
Some(envelop) => {
let desc = envelop.desc.as_ref()
.map(|desc| format!(", Desc: {}", desc))
.unwrap_or_else(|| "".to_string());
ks.push(format!("{}{}", envelop.kid, desc));
}
}
}
config_profiles.push(ConfigProfile {
profiles: pp,
keys: ks.join("\n"),
});
}
let mut table = Table::new(config_profiles);
table.with(Style::modern());
println!("{}", table.to_string());
Ok(())
}

View File

@@ -2,25 +2,30 @@ use std::{fs, io};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::str::FromStr;
use std::time::Instant;
use clap::Args;
use openpgp_card::{OpenPgp, OpenPgpTransaction};
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::x509::SubjectPublicKeyInfo;
use yubikey::piv::{AlgorithmId, decrypt_data, RetiredSlotId, SlotId};
use yubikey::piv::{AlgorithmId, decrypt_data};
use yubikey::YubiKey;
use zeroize::Zeroize;
use crate::{card, file, util};
use crate::{card, file, util, util_piv};
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_P384, ENC_AES256_GCM_X25519, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT};
use crate::util::{
ENC_AES256_GCM_P256, ENC_AES256_GCM_P384, ENC_AES256_GCM_X25519,
TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT,
};
use crate::wrap_key::WrapKey;
#[derive(Debug, Args)]
@@ -194,10 +199,11 @@ fn try_decrypt_key_ecdh(config: &Option<TinyEncryptConfig>,
let epk_bytes = subject_public_key_info.subject_public_key.as_ref();
let mut yk = opt_result!(YubiKey::open(), "YubiKey not found: {}");
let retired_slot_id = opt_result!(RetiredSlotId::from_str(&slot), "Slot not found: {}");
let slot_id = SlotId::Retired(retired_slot_id);
let slot_id = util_piv::get_slot_id(&slot)?;
opt_result!(yk.verify_pin(pin.as_bytes()), "YubiKey verify pin failed: {}");
let algo_id = iff!(expected_enc_type == ENC_AES256_GCM_P256, AlgorithmId::EccP256, AlgorithmId::EccP384);
let algo_id = iff!(
expected_enc_type == ENC_AES256_GCM_P256, AlgorithmId::EccP256, AlgorithmId::EccP384
);
let shared_secret = opt_result!(decrypt_data(
&mut yk,
&epk_bytes,
@@ -322,7 +328,9 @@ fn select_envelop(meta: &TinyEncryptMeta) -> XResult<&TinyEncryptEnvelop> {
envelops.iter().enumerate().for_each(|(i, envelop)| {
let kid = iff!(envelop.kid.is_empty(), "".into(), format!(", Kid: {}", envelop.kid));
let desc = envelop.desc.as_ref().map(|desc| format!(", Desc: {}", desc)).unwrap_or_else(|| "".to_string());
let desc = envelop.desc.as_ref()
.map(|desc| format!(", Desc: {}", desc))
.unwrap_or_else(|| "".to_string());
println!("#{} {}{}{}", i + 1,
envelop.r#type.get_upper_name(),
kid,

View File

@@ -2,6 +2,7 @@ extern crate core;
use clap::{Parser, Subcommand};
use rust_util::XResult;
use crate::cmd_config::CmdConfig;
use crate::cmd_decrypt::CmdDecrypt;
use crate::cmd_encrypt::CmdEncrypt;
@@ -9,6 +10,7 @@ use crate::cmd_info::CmdInfo;
use crate::cmd_version::CmdVersion;
mod util;
mod util_piv;
mod util_ecdh;
mod util_p384;
mod util_x25519;
@@ -21,6 +23,7 @@ mod wrap_key;
mod file;
mod card;
mod cmd_version;
mod cmd_config;
mod cmd_info;
mod cmd_decrypt;
mod cmd_encrypt;
@@ -47,6 +50,9 @@ enum Commands {
/// Show version
#[command(short_flag = 'v')]
Version(CmdVersion),
/// Show Config
#[command(short_flag = 'c')]
Config(CmdConfig),
}
fn main() -> XResult<()> {
@@ -56,5 +62,6 @@ fn main() -> XResult<()> {
Commands::Decrypt(cmd_decrypt) => cmd_decrypt::decrypt(cmd_decrypt),
Commands::Info(cmd_info) => cmd_info::info(cmd_info),
Commands::Version(cmd_version) => cmd_version::version(cmd_version),
Commands::Config(cmd_config) => cmd_config::config(cmd_config),
}
}

33
src/util_piv.rs Normal file
View File

@@ -0,0 +1,33 @@
use rust_util::{simple_error, XResult};
use yubikey::piv::{RetiredSlotId, SlotId};
pub fn get_slot_id(slot: &str) -> XResult<SlotId> {
let slot_lower = slot.to_lowercase();
Ok(match slot_lower.as_str() {
"9a" | "auth" | "authentication" => SlotId::Authentication,
"9c" | "sign" | "signature" => SlotId::Signature,
"9d" | "keym" | "keymanagement" => SlotId::KeyManagement,
"9e" | "card" | "cardauthentication" => SlotId::CardAuthentication,
"r1" | "82" => SlotId::Retired(RetiredSlotId::R1),
"r2" | "83" => SlotId::Retired(RetiredSlotId::R2),
"r3" | "84" => SlotId::Retired(RetiredSlotId::R3),
"r4" | "85" => SlotId::Retired(RetiredSlotId::R4),
"r5" | "86" => SlotId::Retired(RetiredSlotId::R5),
"r6" | "87" => SlotId::Retired(RetiredSlotId::R6),
"r7" | "88" => SlotId::Retired(RetiredSlotId::R7),
"r8" | "89" => SlotId::Retired(RetiredSlotId::R8),
"r9" | "8a" => SlotId::Retired(RetiredSlotId::R9),
"r10" | "8b" => SlotId::Retired(RetiredSlotId::R10),
"r11" | "8c" => SlotId::Retired(RetiredSlotId::R11),
"r12" | "8d" => SlotId::Retired(RetiredSlotId::R12),
"r13" | "8e" => SlotId::Retired(RetiredSlotId::R13),
"r14" | "8f" => SlotId::Retired(RetiredSlotId::R14),
"r15" | "90" => SlotId::Retired(RetiredSlotId::R15),
"r16" | "91" => SlotId::Retired(RetiredSlotId::R16),
"r17" | "92" => SlotId::Retired(RetiredSlotId::R17),
"r18" | "93" => SlotId::Retired(RetiredSlotId::R18),
"r19" | "94" => SlotId::Retired(RetiredSlotId::R19),
"r20" | "95" => SlotId::Retired(RetiredSlotId::R20),
_ => return simple_error!("Unknown slot: {}", slot),
})
}