feaat: v1.9.13, add temporary key for simple encrypt
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -2008,7 +2008,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiny-encrypt"
|
name = "tiny-encrypt"
|
||||||
version = "1.9.12"
|
version = "1.9.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm-stream",
|
"aes-gcm-stream",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -2027,6 +2027,7 @@ dependencies = [
|
|||||||
"openpgp-card-pcsc",
|
"openpgp-card-pcsc",
|
||||||
"p256",
|
"p256",
|
||||||
"p384",
|
"p384",
|
||||||
|
"percent-encoding",
|
||||||
"pinentry",
|
"pinentry",
|
||||||
"pqcrypto-kyber",
|
"pqcrypto-kyber",
|
||||||
"pqcrypto-traits",
|
"pqcrypto-traits",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tiny-encrypt"
|
name = "tiny-encrypt"
|
||||||
version = "1.9.12"
|
version = "1.9.13"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
description = "A simple and tiny file encrypt tool"
|
description = "A simple and tiny file encrypt tool"
|
||||||
@@ -54,6 +54,7 @@ ctrlc = "3.4"
|
|||||||
swift-secure-enclave-tool-rs = "1.0"
|
swift-secure-enclave-tool-rs = "1.0"
|
||||||
json5 = "0.4"
|
json5 = "0.4"
|
||||||
external-command-rs = "0.1"
|
external-command-rs = "0.1"
|
||||||
|
percent-encoding = "2.3"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use tabled::{Table, Tabled};
|
|||||||
use tabled::settings::Style;
|
use tabled::settings::Style;
|
||||||
|
|
||||||
use crate::config::TinyEncryptConfig;
|
use crate::config::TinyEncryptConfig;
|
||||||
|
use crate::temporary_key::serialize_config_envelop;
|
||||||
use crate::util_envelop;
|
use crate::util_envelop;
|
||||||
|
|
||||||
#[derive(Tabled, Eq)]
|
#[derive(Tabled, Eq)]
|
||||||
@@ -50,6 +51,9 @@ pub struct CmdConfig {
|
|||||||
/// JSON output
|
/// JSON output
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub json: bool,
|
pub json: bool,
|
||||||
|
/// Temporary key output
|
||||||
|
#[arg(long)]
|
||||||
|
pub temporary_key: bool,
|
||||||
/// Encryption profile (use default when --key-filter is assigned)
|
/// Encryption profile (use default when --key-filter is assigned)
|
||||||
#[arg(long, short = 'p')]
|
#[arg(long, short = 'p')]
|
||||||
pub profile: Option<String>,
|
pub profile: Option<String>,
|
||||||
@@ -71,6 +75,14 @@ pub fn config(cmd_config: CmdConfig) -> XResult<()> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cmd_config.temporary_key {
|
||||||
|
for envelop in &config.envelops {
|
||||||
|
let k = serialize_config_envelop(envelop);
|
||||||
|
println!("{}", k);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if cmd_config.profile.is_some() || cmd_config.key_filter.is_some() {
|
if cmd_config.profile.is_some() || cmd_config.key_filter.is_some() {
|
||||||
return config_key_filter(&cmd_config, &config);
|
return config_key_filter(&cmd_config, &config);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use serde::Serialize;
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
use crate::temporary_key::deserialize_config_envelop;
|
||||||
use crate::util_simple_pbe::SimplePbkdfEncryptionV1;
|
use crate::util_simple_pbe::SimplePbkdfEncryptionV1;
|
||||||
|
|
||||||
// Reference: https://git.hatter.ink/hatter/tiny-encrypt-rs/issues/3
|
// Reference: https://git.hatter.ink/hatter/tiny-encrypt-rs/issues/3
|
||||||
@@ -25,6 +26,10 @@ pub struct CmdSimpleEncrypt {
|
|||||||
#[arg(long, short = 'k')]
|
#[arg(long, short = 'k')]
|
||||||
pub key_filter: Option<String>,
|
pub key_filter: Option<String>,
|
||||||
|
|
||||||
|
/// Temporary key
|
||||||
|
#[arg(long)]
|
||||||
|
pub temporary_key: Option<Vec<String>>,
|
||||||
|
|
||||||
/// Encrypt value from stdin
|
/// Encrypt value from stdin
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub value_stdin: bool,
|
pub value_stdin: bool,
|
||||||
@@ -190,9 +195,26 @@ pub fn simple_decrypt(cmd_simple_decrypt: CmdSimpleDecrypt) -> XResult<()> {
|
|||||||
pub fn inner_simple_encrypt(cmd_simple_encrypt: CmdSimpleEncrypt) -> XResult<()> {
|
pub fn inner_simple_encrypt(cmd_simple_encrypt: CmdSimpleEncrypt) -> XResult<()> {
|
||||||
let config = TinyEncryptConfig::load_default()?;
|
let config = TinyEncryptConfig::load_default()?;
|
||||||
debugging!("Found tiny encrypt config: {:?}", config);
|
debugging!("Found tiny encrypt config: {:?}", config);
|
||||||
let envelops = config.find_envelops(&cmd_simple_encrypt.profile, &cmd_simple_encrypt.key_filter)?;
|
|
||||||
if envelops.is_empty() { return simple_error!("Cannot find any valid envelops"); }
|
let mut envelops = config.find_envelops(
|
||||||
|
&cmd_simple_encrypt.profile,
|
||||||
|
&cmd_simple_encrypt.key_filter)?;
|
||||||
debugging!("Found envelops: {:?}", envelops);
|
debugging!("Found envelops: {:?}", envelops);
|
||||||
|
|
||||||
|
let mut temporary_envelops = vec![];
|
||||||
|
if let Some(temporary_key) = &cmd_simple_encrypt.temporary_key {
|
||||||
|
for t_key in temporary_key {
|
||||||
|
let envelop = opt_result!(deserialize_config_envelop(t_key), "Parse temporary key: {} failed: {}", t_key);
|
||||||
|
temporary_envelops.push(envelop);
|
||||||
|
}
|
||||||
|
// FIXME should check kid not exists
|
||||||
|
for t_envelop in &mut temporary_envelops {
|
||||||
|
envelops.push(t_envelop)
|
||||||
|
}
|
||||||
|
debugging!("Final envelops: {:?}", envelops);
|
||||||
|
}
|
||||||
|
if envelops.is_empty() { return simple_error!("Cannot find any valid envelops"); }
|
||||||
|
|
||||||
let envelop_tkids: Vec<_> = envelops.iter()
|
let envelop_tkids: Vec<_> = envelops.iter()
|
||||||
.map(|e| format!("{}:{}", e.r#type.get_name(), e.kid))
|
.map(|e| format!("{}:{}", e.r#type.get_name(), e.kid))
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::path::PathBuf;
|
|||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
use rust_util::util_env as rust_util_env;
|
use rust_util::util_env as rust_util_env;
|
||||||
use rust_util::util_file::resolve_file_path;
|
use rust_util::util_file::resolve_file_path;
|
||||||
use rust_util::{debugging, opt_result, simple_error, warning, XResult};
|
use rust_util::{debugging, opt_result, warning, XResult};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::consts::{ENV_TINY_ENC_CONFIG_FILE, TINY_ENC_CONFIG_FILE, TINY_ENC_CONFIG_FILE_2, TINY_ENC_CONFIG_FILE_3, TINY_ENC_FILE_EXT};
|
use crate::consts::{ENV_TINY_ENC_CONFIG_FILE, TINY_ENC_CONFIG_FILE, TINY_ENC_CONFIG_FILE_2, TINY_ENC_CONFIG_FILE_3, TINY_ENC_FILE_EXT};
|
||||||
use crate::spec::TinyEncryptEnvelopType;
|
use crate::spec::TinyEncryptEnvelopType;
|
||||||
@@ -257,7 +257,8 @@ impl TinyEncryptConfig {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if key_ids.is_empty() {
|
if key_ids.is_empty() {
|
||||||
return simple_error!("Profile or key filter cannot find any valid envelopes");
|
// return simple_error!("Profile or key filter cannot find any valid envelopes");
|
||||||
|
return Ok(vec![]);
|
||||||
}
|
}
|
||||||
for key_id in &key_ids {
|
for key_id in &key_ids {
|
||||||
for envelop in self.find_by_kid_or_type(key_id) {
|
for envelop in self.find_by_kid_or_type(key_id) {
|
||||||
@@ -267,7 +268,8 @@ impl TinyEncryptConfig {
|
|||||||
|
|
||||||
let mut envelops: Vec<_> = matched_envelops_map.values().copied().collect();
|
let mut envelops: Vec<_> = matched_envelops_map.values().copied().collect();
|
||||||
if envelops.is_empty() {
|
if envelops.is_empty() {
|
||||||
return simple_error!("Profile or key filter cannot find any valid envelopes");
|
// return simple_error!("Profile or key filter cannot find any valid envelopes");
|
||||||
|
return Ok(vec![]);
|
||||||
}
|
}
|
||||||
envelops.sort_by(|e1, e2| {
|
envelops.sort_by(|e1, e2| {
|
||||||
if e1.r#type < e2.r#type {
|
if e1.r#type < e2.r#type {
|
||||||
|
|||||||
@@ -77,4 +77,5 @@ mod cmd_execenv;
|
|||||||
mod util_keychainkey;
|
mod util_keychainkey;
|
||||||
mod util_simple_pbe;
|
mod util_simple_pbe;
|
||||||
mod util_log;
|
mod util_log;
|
||||||
|
mod temporary_key;
|
||||||
|
|
||||||
|
|||||||
19
src/spec.rs
19
src/spec.rs
@@ -132,6 +132,25 @@ impl TinyEncryptEnvelopType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_name(name: &str) -> Option<Self> {
|
||||||
|
match name {
|
||||||
|
"pgp-rsa" => Some(TinyEncryptEnvelopType::PgpRsa),
|
||||||
|
"pgp-x25519" => Some(TinyEncryptEnvelopType::PgpX25519),
|
||||||
|
"gpg" => Some(TinyEncryptEnvelopType::Gpg),
|
||||||
|
"static-x25519" => Some(TinyEncryptEnvelopType::StaticX25519),
|
||||||
|
"static-kyber1024" => Some(TinyEncryptEnvelopType::StaticKyber1024),
|
||||||
|
"key-p256" => Some(TinyEncryptEnvelopType::KeyP256),
|
||||||
|
"ext-p256" => Some(TinyEncryptEnvelopType::ExtP256),
|
||||||
|
"ext-p384" => Some(TinyEncryptEnvelopType::ExtP384),
|
||||||
|
"piv-p256" => Some(TinyEncryptEnvelopType::PivP256),
|
||||||
|
"piv-p384" => Some(TinyEncryptEnvelopType::PivP384),
|
||||||
|
"piv-rsa" => Some(TinyEncryptEnvelopType::PivRsa),
|
||||||
|
"age" => Some(TinyEncryptEnvelopType::Age),
|
||||||
|
"kms" => Some(TinyEncryptEnvelopType::Kms),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn auto_select(&self) -> bool {
|
pub fn auto_select(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
TinyEncryptEnvelopType::StaticX25519
|
TinyEncryptEnvelopType::StaticX25519
|
||||||
|
|||||||
56
src/temporary_key.rs
Normal file
56
src/temporary_key.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// syntax
|
||||||
|
// tiny-encrypt-key:type:sid:key_id:public_part[?key=value]
|
||||||
|
// e.g.
|
||||||
|
// tiny-encrypt-key:ext-p256:ext-key-1:02536aef5742b4288f1b44b3cc96f1556c35e4fac4e8e117e1f7ae091e42d0835b:04536aef5742b4288f1b44b3cc96f1556c35e4fac4e8e117e1f7ae091e42d0835bf3f95d932c22a74a91859bd7fdd8829a02d38cf4ec598b1cf6e02fa09f707a6f
|
||||||
|
|
||||||
|
use crate::config::TinyEncryptConfigEnvelop;
|
||||||
|
use crate::spec::TinyEncryptEnvelopType;
|
||||||
|
use rust_util::{iff, opt_result, opt_value_result, simple_error, XResult};
|
||||||
|
|
||||||
|
const TINY_ENCRYPT_KEY_PREFIX: &str = "tiny-encrypt-key:";
|
||||||
|
|
||||||
|
pub fn serialize_config_envelop(config_envelop: &TinyEncryptConfigEnvelop) -> String {
|
||||||
|
let mut s = String::new();
|
||||||
|
s.push_str(TINY_ENCRYPT_KEY_PREFIX);
|
||||||
|
s.push_str(config_envelop.r#type.get_name());
|
||||||
|
s.push(':');
|
||||||
|
s.push_str(&encode(config_envelop.sid.as_deref().unwrap_or("")));
|
||||||
|
s.push(':');
|
||||||
|
s.push_str(&encode(&config_envelop.kid));
|
||||||
|
s.push(':');
|
||||||
|
s.push_str(&encode(&config_envelop.public_part));
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_config_envelop(k: &str) -> XResult<TinyEncryptConfigEnvelop> {
|
||||||
|
if !k.starts_with(TINY_ENCRYPT_KEY_PREFIX) {
|
||||||
|
return simple_error!("invalid temporary key");
|
||||||
|
}
|
||||||
|
let k_parts = k.split(":").collect::<Vec<_>>();
|
||||||
|
if k_parts.len() != 5 {
|
||||||
|
return simple_error!("invalid temporary key (parts)");
|
||||||
|
}
|
||||||
|
let envelop_type = opt_value_result!(
|
||||||
|
TinyEncryptEnvelopType::from_name(k_parts[1]), "Unknown envelop type: {}", k_parts[1]);
|
||||||
|
Ok(TinyEncryptConfigEnvelop {
|
||||||
|
r#type: envelop_type,
|
||||||
|
sid: iff!(k_parts[2].is_empty(), None, Some(decode(k_parts[2])?)),
|
||||||
|
kid: decode(k_parts[3])?,
|
||||||
|
desc: None,
|
||||||
|
args: None,
|
||||||
|
public_part: decode(k_parts[4])?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode(s: &str) -> String {
|
||||||
|
percent_encoding::utf8_percent_encode(s, percent_encoding::NON_ALPHANUMERIC).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(s: &str) -> XResult<String> {
|
||||||
|
Ok(opt_result!(
|
||||||
|
percent_encoding::percent_decode_str(s).decode_utf8(),
|
||||||
|
"decode: {} failed: {}",
|
||||||
|
s
|
||||||
|
)
|
||||||
|
.to_string())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user