feat: v0.2.3, supports p384

This commit is contained in:
2023-10-10 00:59:59 +08:00
parent 308c6561bc
commit a64649451c
8 changed files with 71 additions and 32 deletions

3
Cargo.lock generated
View File

@@ -2063,7 +2063,7 @@ dependencies = [
[[package]]
name = "tiny-encrypt"
version = "0.2.2"
version = "0.2.3"
dependencies = [
"aes-gcm-stream",
"base64",
@@ -2074,6 +2074,7 @@ dependencies = [
"openpgp-card",
"openpgp-card-pcsc",
"p256",
"p384",
"rand",
"reqwest",
"rpassword",

View File

@@ -1,6 +1,6 @@
[package]
name = "tiny-encrypt"
version = "0.2.2"
version = "0.2.3"
edition = "2021"
license = "MIT"
description = "A simple and tiny file encrypt tool"
@@ -8,28 +8,29 @@ description = "A simple and tiny file encrypt tool"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
aes-gcm-stream = "0.2.0"
base64 = "0.21.0"
chrono = "0.4.23"
clap = { version = "4.1.4", features = ["derive"] }
flate2 = "1.0.27"
hex = "0.4.3"
openpgp-card = "0.3.7"
openpgp-card-pcsc = "0.3.0"
p256 = { version = "0.13.2", features = ["pem", "ecdh", "pkcs8"] }
rand = "0.8.5"
reqwest = { version = "0.11.14", features = ["blocking", "rustls", "rustls-tls"] }
rpassword = "7.2.0"
rsa = { version = "0.9.2", features = ["pem"] }
rust_util = "0.6.42"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.93"
sha256 = "1.4.0"
simpledateformat = "0.1.4"
x25519-dalek = "2.0.0"
x509-parser = "0.15.1"
yubikey = { version = "0.8.0", features = ["untested"] }
zeroize = "1.6.0"
aes-gcm-stream = "0.2"
base64 = "0.21"
chrono = "0.4"
clap = { version = "4.1", features = ["derive"] }
flate2 = "1.0"
hex = "0.4"
openpgp-card = "0.3"
openpgp-card-pcsc = "0.3"
p256 = { version = "0.13", features = ["pem", "ecdh", "pkcs8"] }
p384 = { version = "0.13", features = ["pem", "ecdh", "pkcs8"] }
rand = "0.8"
reqwest = { version = "0.11", features = ["blocking", "rustls", "rustls-tls"] }
rpassword = "7.2"
rsa = { version = "0.9", features = ["pem"] }
rust_util = "0.6"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sha256 = "1.4"
simpledateformat = "0.1"
x25519-dalek = "2.0"
x509-parser = "0.15"
yubikey = { version = "0.8", features = ["untested"] }
zeroize = "1.6"
[profile.release]
codegen-units = 1

View File

@@ -11,8 +11,8 @@ 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::YubiKey;
use yubikey::piv::{AlgorithmId, decrypt_data, RetiredSlotId, SlotId};
use yubikey::YubiKey;
use zeroize::Zeroize;
use crate::{card, file, util};
@@ -20,7 +20,7 @@ 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_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)]
@@ -168,7 +168,8 @@ fn try_decrypt_key(config: &Option<TinyEncryptConfig>,
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(config, envelop, pin, slot),
TinyEncryptEnvelopType::Ecdh => try_decrypt_key_ecdh(config, envelop, pin, ENC_AES256_GCM_P256, slot),
TinyEncryptEnvelopType::EcdhP384 => try_decrypt_key_ecdh(config, envelop, pin, ENC_AES256_GCM_P384, slot),
unknown_type => {
return simple_error!("Unknown or not supported type: {}", unknown_type.get_name());
}
@@ -178,10 +179,11 @@ fn try_decrypt_key(config: &Option<TinyEncryptConfig>,
fn try_decrypt_key_ecdh(config: &Option<TinyEncryptConfig>,
envelop: &TinyEncryptEnvelop,
pin: &Option<String>,
expected_enc_type: &str,
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);
if wrap_key.header.enc.as_str() != expected_enc_type {
return simple_error!("Unsupported header requires: {}, actual: {}", expected_enc_type, &wrap_key.header.enc);
}
let e_pub_key = &wrap_key.header.e_pub_key;
let e_pub_key_bytes = opt_result!(util::decode_base64_url_no_pad(e_pub_key), "Invalid envelop: {}");
@@ -195,10 +197,11 @@ fn try_decrypt_key_ecdh(config: &Option<TinyEncryptConfig>,
let retired_slot_id = opt_result!(RetiredSlotId::from_str(&slot), "Slot not found: {}");
let slot_id = SlotId::Retired(retired_slot_id);
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 shared_secret = opt_result!(decrypt_data(
&mut yk,
&epk_bytes,
AlgorithmId::EccP256,
algo_id,
slot_id,
), "Decrypt via PIV card failed: {}");
let key = util::simple_kdf(shared_secret.as_slice());

View File

@@ -10,13 +10,13 @@ use rsa::Pkcs1v15Encrypt;
use rust_util::{debugging, failure, information, opt_result, simple_error, success, util_msg, warning, XResult};
use zeroize::Zeroize;
use crate::{util, util_ecdh, util_x25519};
use crate::{util, util_ecdh, util_p384, util_x25519};
use crate::compress::GzStreamEncoder;
use crate::config::{TinyEncryptConfig, TinyEncryptConfigEnvelop};
use crate::crypto_aes::aes_gcm_encrypt;
use crate::crypto_rsa::parse_spki;
use crate::spec::{EncMetadata, TINY_ENCRYPT_VERSION_10, TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta};
use crate::util::{ENC_AES256_GCM_P256, ENC_AES256_GCM_X25519, TINY_ENC_CONFIG_FILE};
use crate::util::{ENC_AES256_GCM_P256, ENC_AES256_GCM_P384, ENC_AES256_GCM_X25519, TINY_ENC_CONFIG_FILE};
use crate::wrap_key::{WrapKey, WrapKeyHeader};
#[derive(Debug, Args)]
@@ -239,6 +239,9 @@ fn encrypt_envelops(key: &[u8], envelops: &[&TinyEncryptConfigEnvelop]) -> XResu
TinyEncryptEnvelopType::Ecdh => {
encrypted_envelops.push(encrypt_envelop_ecdh(key, envelop)?);
}
TinyEncryptEnvelopType::EcdhP384 => {
encrypted_envelops.push(encrypt_envelop_ecdh_p384(key, envelop)?);
}
_ => return simple_error!("Not supported type: {:?}", envelop.r#type),
}
}
@@ -252,6 +255,13 @@ fn encrypt_envelop_ecdh(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResu
encrypt_envelop_shared_secret(key, &shared_secret, &ephemeral_spki, ENC_AES256_GCM_P256, envelop)
}
fn encrypt_envelop_ecdh_p384(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult<TinyEncryptEnvelop> {
let public_key_point_hex = &envelop.public_part;
let (shared_secret, ephemeral_spki) = util_p384::compute_p384_shared_secret(public_key_point_hex)?;
encrypt_envelop_shared_secret(key, &shared_secret, &ephemeral_spki, ENC_AES256_GCM_P384, envelop)
}
fn encrypt_envelop_ecdh_x25519(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult<TinyEncryptEnvelop> {
let public_key_point_hex = &envelop.public_part;
let (shared_secret, ephemeral_spki) = util_x25519::compute_x25519_shared_secret(public_key_point_hex)?;

View File

@@ -10,6 +10,7 @@ use crate::cmd_version::CmdVersion;
mod util;
mod util_ecdh;
mod util_p384;
mod util_x25519;
mod compress;
mod config;

View File

@@ -56,6 +56,8 @@ pub enum TinyEncryptEnvelopType {
Age,
#[serde(rename = "ecdh")]
Ecdh,
#[serde(rename = "ecdh-p384")]
EcdhP384,
#[serde(rename = "kms")]
Kms,
}
@@ -70,6 +72,7 @@ impl TinyEncryptEnvelopType {
TinyEncryptEnvelopType::PgpX25519 => "pgp-x25519",
TinyEncryptEnvelopType::Age => "age",
TinyEncryptEnvelopType::Ecdh => "ecdh",
TinyEncryptEnvelopType::EcdhP384 => "ecdh-p384",
TinyEncryptEnvelopType::Kms => "kms",
}
}

View File

@@ -9,6 +9,7 @@ use rust_util::{simple_error, warning, XResult};
use zeroize::Zeroize;
pub const ENC_AES256_GCM_P256: &str = "aes256-gcm-p256";
pub const ENC_AES256_GCM_P384: &str = "aes256-gcm-p384";
pub const ENC_AES256_GCM_X25519: &str = "aes256-gcm-x25519";
pub const TINY_ENC_FILE_EXT: &str = ".tinyenc";
pub const TINY_ENC_CONFIG_FILE: &str = "~/.tinyencrypt/config-rs.json";

19
src/util_p384.rs Normal file
View File

@@ -0,0 +1,19 @@
use p384::ecdh::EphemeralSecret;
use rand::rngs::OsRng;
use rust_util::{opt_result, XResult};
use p384::pkcs8::EncodePublicKey;
use p384::{EncodedPoint, PublicKey};
use p384::elliptic_curve::sec1::FromEncodedPoint;
pub fn compute_p384_shared_secret(public_key_point_hex: &str) -> XResult<(Vec<u8>, Vec<u8>)> {
let public_key_point_bytes = opt_result!(hex::decode(public_key_point_hex), "Parse public key point hex failed: {}");
let encoded_point = opt_result!(EncodedPoint::from_bytes(&public_key_point_bytes), "Parse public key point failed: {}");
let public_key = PublicKey::from_encoded_point(&encoded_point).unwrap();
let esk = EphemeralSecret::random(&mut OsRng);
let epk = esk.public_key();
let shared_secret = esk.diffie_hellman(&public_key);
let epk_public_key_der = opt_result!(epk.to_public_key_der(), "Convert epk to SPKI failed: {}");
Ok((shared_secret.raw_secret_bytes().as_slice().to_vec(), epk_public_key_der.to_vec()))
}