feat: v0.2.3, supports p384
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::cmd_version::CmdVersion;
|
||||
|
||||
mod util;
|
||||
mod util_ecdh;
|
||||
mod util_p384;
|
||||
mod util_x25519;
|
||||
mod compress;
|
||||
mod config;
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
19
src/util_p384.rs
Normal 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()))
|
||||
}
|
||||
Reference in New Issue
Block a user