feat: v1.7.0, support GPG encrypt and decrypt
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1753,7 +1753,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tiny-encrypt"
|
||||
version = "1.6.1"
|
||||
version = "1.7.0"
|
||||
dependencies = [
|
||||
"aes-gcm-stream",
|
||||
"base64",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tiny-encrypt"
|
||||
version = "1.6.1"
|
||||
version = "1.7.0"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "A simple and tiny file encrypt tool"
|
||||
|
||||
@@ -20,10 +20,7 @@ use yubikey::piv::{AlgorithmId, decrypt_data};
|
||||
use yubikey::YubiKey;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use crate::{
|
||||
cmd_encrypt, config, consts, crypto_simple,
|
||||
util, util_enc_file, util_env, util_envelop, util_file, util_pgp, util_piv,
|
||||
};
|
||||
use crate::{cmd_encrypt, config, consts, crypto_simple, util, util_enc_file, util_env, util_envelop, util_file, util_gpg, util_pgp, util_piv};
|
||||
use crate::compress::GzStreamDecoder;
|
||||
use crate::config::TinyEncryptConfig;
|
||||
use crate::consts::{
|
||||
@@ -461,6 +458,7 @@ pub fn try_decrypt_key(config: &Option<TinyEncryptConfig>,
|
||||
match envelop.r#type {
|
||||
TinyEncryptEnvelopType::PgpRsa => try_decrypt_key_pgp_rsa(envelop, pin),
|
||||
TinyEncryptEnvelopType::PgpX25519 => try_decrypt_key_ecdh_pgp_x25519(envelop, pin),
|
||||
TinyEncryptEnvelopType::Gpg => try_decrypt_key_gpg(envelop),
|
||||
#[cfg(feature = "macos")]
|
||||
TinyEncryptEnvelopType::StaticX25519 => try_decrypt_key_ecdh_static_x25519(config, envelop),
|
||||
TinyEncryptEnvelopType::PivP256 | TinyEncryptEnvelopType::PivP384 => try_decrypt_piv_key_ecdh(config, envelop, pin, slot),
|
||||
@@ -613,6 +611,10 @@ fn try_decrypt_key_ecdh_pgp_x25519(envelop: &TinyEncryptEnvelop, pin: &Option<St
|
||||
Ok(decrypted_key)
|
||||
}
|
||||
|
||||
fn try_decrypt_key_gpg(envelop: &TinyEncryptEnvelop) -> XResult<Vec<u8>> {
|
||||
Ok(util_gpg::gpg_decrypt(&envelop.encrypted_key)?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "macos")]
|
||||
fn try_decrypt_key_ecdh_static_x25519(config: &Option<TinyEncryptConfig>, envelop: &TinyEncryptEnvelop) -> XResult<Vec<u8>> {
|
||||
let wrap_key = WrapKey::parse(&envelop.encrypted_key)?;
|
||||
|
||||
@@ -10,7 +10,7 @@ use rsa::Pkcs1v15Encrypt;
|
||||
use rust_util::{debugging, failure, iff, information, opt_result, simple_error, success, util_size, XResult};
|
||||
use rust_util::util_time::UnixEpochTime;
|
||||
|
||||
use crate::{crypto_cryptor, crypto_simple, util, util_enc_file, util_env};
|
||||
use crate::{crypto_cryptor, crypto_simple, util, util_enc_file, util_env, util_gpg};
|
||||
use crate::compress::GzStreamEncoder;
|
||||
use crate::config::{TinyEncryptConfig, TinyEncryptConfigEnvelop};
|
||||
use crate::consts::{
|
||||
@@ -23,13 +23,13 @@ use crate::consts::{
|
||||
SALT_COMMENT, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT,
|
||||
};
|
||||
use crate::crypto_cryptor::{Cryptor, KeyNonce};
|
||||
use crate::util_rsa;
|
||||
use crate::spec::{
|
||||
EncEncryptedMeta, EncMetadata,
|
||||
TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta,
|
||||
};
|
||||
use crate::util_ecdh::{ecdh_kyber1024, ecdh_p256, ecdh_p384, ecdh_x25519};
|
||||
use crate::util_progress::Progress;
|
||||
use crate::util_rsa;
|
||||
use crate::wrap_key::{WrapKey, WrapKeyHeader};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
@@ -284,6 +284,9 @@ fn encrypt_envelops(cryptor: Cryptor, key: &[u8], envelops: &[&TinyEncryptConfig
|
||||
TinyEncryptEnvelopType::PgpRsa | TinyEncryptEnvelopType::PivRsa => {
|
||||
encrypted_envelops.push(encrypt_envelop_rsa(key, envelop)?);
|
||||
}
|
||||
TinyEncryptEnvelopType::Gpg => {
|
||||
encrypted_envelops.push(encrypt_envelop_gpg(key, envelop)?);
|
||||
}
|
||||
TinyEncryptEnvelopType::PgpX25519 | TinyEncryptEnvelopType::StaticX25519 => {
|
||||
encrypted_envelops.push(encrypt_envelop_ecdh_x25519(cryptor, key, envelop)?);
|
||||
}
|
||||
@@ -382,6 +385,16 @@ fn encrypt_envelop_rsa(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResul
|
||||
})
|
||||
}
|
||||
|
||||
fn encrypt_envelop_gpg(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult<TinyEncryptEnvelop> {
|
||||
let encrypted_key = opt_result!(util_gpg::gpg_encrypt(&envelop.public_part, key), "GPG encrypt failed: {}");
|
||||
Ok(TinyEncryptEnvelop {
|
||||
r#type: envelop.r#type,
|
||||
kid: envelop.kid.clone(),
|
||||
desc: None,
|
||||
encrypted_key,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_compress_level(cmd_encrypt: &CmdEncrypt) -> Option<u32> {
|
||||
if cmd_encrypt.compress || util_env::get_default_compress().unwrap_or(false) {
|
||||
Some(cmd_encrypt.compress_level.unwrap_or_else(|| Compression::default().level()))
|
||||
|
||||
@@ -20,6 +20,7 @@ pub struct TinyEncryptMeta {
|
||||
pub version: String,
|
||||
pub created: u64,
|
||||
pub user_agent: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub latest_user_agent: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub comment: Option<String>,
|
||||
@@ -73,6 +74,9 @@ pub enum TinyEncryptEnvelopType {
|
||||
// OpenPGP Card X25519
|
||||
#[serde(rename = "pgp-x25519")]
|
||||
PgpX25519,
|
||||
// GPG Command Line
|
||||
#[serde(rename = "gpg")]
|
||||
Gpg,
|
||||
// Keychain Static X25519 (less secure)
|
||||
#[serde(rename = "static-x25519")]
|
||||
StaticX25519,
|
||||
@@ -108,6 +112,7 @@ impl TinyEncryptEnvelopType {
|
||||
match self {
|
||||
TinyEncryptEnvelopType::PgpRsa => "pgp-rsa",
|
||||
TinyEncryptEnvelopType::PgpX25519 => "pgp-x25519",
|
||||
TinyEncryptEnvelopType::Gpg => "gpg",
|
||||
TinyEncryptEnvelopType::StaticX25519 => "static-x25519",
|
||||
TinyEncryptEnvelopType::StaticKyber1024 => "static-kyber1024",
|
||||
TinyEncryptEnvelopType::KeyP256 => "key-p256",
|
||||
@@ -124,6 +129,7 @@ impl TinyEncryptEnvelopType {
|
||||
TinyEncryptEnvelopType::StaticX25519
|
||||
| TinyEncryptEnvelopType::StaticKyber1024
|
||||
| TinyEncryptEnvelopType::KeyP256
|
||||
| TinyEncryptEnvelopType::Gpg
|
||||
| TinyEncryptEnvelopType::Kms => true,
|
||||
TinyEncryptEnvelopType::PgpRsa
|
||||
| TinyEncryptEnvelopType::PgpX25519
|
||||
@@ -145,6 +151,7 @@ impl TinyEncryptEnvelopType {
|
||||
| TinyEncryptEnvelopType::Age => true,
|
||||
TinyEncryptEnvelopType::StaticX25519
|
||||
| TinyEncryptEnvelopType::StaticKyber1024
|
||||
| TinyEncryptEnvelopType::Gpg // GPG is unknown(hardware/software)
|
||||
| TinyEncryptEnvelopType::Kms => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ pub const TINY_ENCRYPT_ENV_NO_PROGRESS: &str = "TINY_ENCRYPT_NO_PROGRESS";
|
||||
pub const TINY_ENCRYPT_ENV_PIN: &str = "TINY_ENCRYPT_PIN";
|
||||
pub const TINY_ENCRYPT_ENV_KEY_ID: &str = "TINY_ENCRYPT_KEY_ID";
|
||||
pub const TINY_ENCRYPT_ENV_AUTO_SELECT_KEY_IDS: &str = "TINY_ENCRYPT_AUTO_SELECT_KEY_IDS";
|
||||
pub const TINY_ENCRYPT_ENV_GPG_COMMAND: &str = "TINY_ENCRYPT_GPG_COMMAND";
|
||||
|
||||
pub fn get_default_encryption_algorithm() -> Option<&'static str> {
|
||||
let env_default_algorithm = env::var(TINY_ENCRYPT_ENV_DEFAULT_ALGORITHM).ok();
|
||||
@@ -34,6 +35,10 @@ pub fn get_key_id() -> Option<String> {
|
||||
env::var(TINY_ENCRYPT_ENV_KEY_ID).ok()
|
||||
}
|
||||
|
||||
pub fn get_gpg_cmd() -> Option<String> {
|
||||
env::var(TINY_ENCRYPT_ENV_GPG_COMMAND).ok()
|
||||
}
|
||||
|
||||
pub fn get_auto_select_key_ids() -> Option<Vec<String>> {
|
||||
env::var(TINY_ENCRYPT_ENV_AUTO_SELECT_KEY_IDS).ok().map(|key_ids| {
|
||||
key_ids.split(',').map(ToString::to_string).collect::<Vec<_>>()
|
||||
|
||||
@@ -41,6 +41,8 @@ use std::process::{Command, Stdio};
|
||||
|
||||
use rust_util::{opt_result, opt_value_result, simple_error, XResult};
|
||||
|
||||
use crate::util_env;
|
||||
|
||||
pub fn gpg_encrypt(key_id: &str, message: &[u8]) -> XResult<String> {
|
||||
let message_hex = hex::encode(message);
|
||||
let echo = opt_result!(Command::new("echo").arg(&message_hex)
|
||||
@@ -48,7 +50,7 @@ pub fn gpg_encrypt(key_id: &str, message: &[u8]) -> XResult<String> {
|
||||
.spawn(), "echo message failed: {}");
|
||||
let echo_stdout = opt_value_result!(echo.stdout, "Get echo stdout failed: none");
|
||||
|
||||
let mut cmd = Command::new("gpg");
|
||||
let mut cmd = Command::new(&get_gpg_cmd());
|
||||
let encrypt_result = cmd
|
||||
.args([
|
||||
"-e", "-a", "--no-comment",
|
||||
@@ -62,7 +64,7 @@ pub fn gpg_encrypt(key_id: &str, message: &[u8]) -> XResult<String> {
|
||||
let stderr = String::from_utf8_lossy(&encrypt_output.stderr).to_string();
|
||||
if !encrypt_output.status.success() {
|
||||
return simple_error!(
|
||||
"GPG encrypt failed: {:?}, stdout: {}, stderr: {}",
|
||||
"GPG encrypt failed: {:?}\n- stdout: {}\n- stderr: {}",
|
||||
encrypt_output.status.code(), stdout, stderr
|
||||
);
|
||||
}
|
||||
@@ -75,7 +77,7 @@ pub fn gpg_decrypt(message: &str) -> XResult<Vec<u8>> {
|
||||
.spawn(), "echo message failed: {}");
|
||||
let echo_stdout = opt_value_result!(echo.stdout, "Get echo stdout failed: none");
|
||||
|
||||
let mut cmd = Command::new("gpg");
|
||||
let mut cmd = Command::new(&get_gpg_cmd());
|
||||
let encrypt_result = cmd
|
||||
.arg("-d")
|
||||
.stdin(Stdio::from(echo_stdout))
|
||||
@@ -85,10 +87,14 @@ pub fn gpg_decrypt(message: &str) -> XResult<Vec<u8>> {
|
||||
let stderr = String::from_utf8_lossy(&decrypt_output.stderr).to_string();
|
||||
if !decrypt_output.status.success() {
|
||||
return simple_error!(
|
||||
"GPG decrypt failed: {:?}, stdout: {}, stderr: {}",
|
||||
"GPG decrypt failed: {:?}\n- stdout: {}\n- stderr: {}",
|
||||
decrypt_output.status.code(), stdout, stderr
|
||||
);
|
||||
}
|
||||
let decrypted = opt_result!(hex::decode(&stdout.trim()), "Decode decrypted message failed: {}");
|
||||
Ok(decrypted)
|
||||
}
|
||||
|
||||
fn get_gpg_cmd() -> String {
|
||||
util_env::get_gpg_cmd().unwrap_or("gpg".to_string())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user