From 0bdb89ad25e241605362366cdf69aeabdab9b551 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 8 Oct 2023 00:49:17 +0800 Subject: [PATCH 1/3] feat: v0.2.0-dev, encrypt supports x25519 --- Cargo.lock | 69 +++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 3 +- src/cmd_encrypt.rs | 22 +++++++++++++-- src/main.rs | 1 + src/spec.rs | 3 ++ src/util_x25519.rs | 19 +++++++++++++ 6 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 src/util_x25519.rs diff --git a/Cargo.lock b/Cargo.lock index 75a8e4a..ccae7fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -390,6 +390,33 @@ dependencies = [ "typenum", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "data-encoding" version = "2.4.0" @@ -574,6 +601,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" + [[package]] name = "flagset" version = "0.4.4" @@ -1339,6 +1372,12 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "platforms" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" + [[package]] name = "polyval" version = "0.6.1" @@ -1579,6 +1618,15 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rusticata-macros" version = "4.1.0" @@ -1709,6 +1757,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" + [[package]] name = "serde" version = "1.0.188" @@ -2009,7 +2063,7 @@ dependencies = [ [[package]] name = "tiny-encrypt" -version = "0.1.2" +version = "0.2.0-dev" dependencies = [ "aes-gcm-stream", "base64", @@ -2029,6 +2083,7 @@ dependencies = [ "serde_json", "sha256", "simpledateformat", + "x25519-dalek", "x509-parser", "yubikey", "zeroize", @@ -2428,6 +2483,18 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "x25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + [[package]] name = "x509-cert" version = "0.2.4" diff --git a/Cargo.toml b/Cargo.toml index 264bc99..e4ee0e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tiny-encrypt" -version = "0.1.2" +version = "0.2.0-dev" edition = "2021" license = "MIT" description = "A simple and tiny file encrypt tool" @@ -26,6 +26,7 @@ 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" diff --git a/src/cmd_encrypt.rs b/src/cmd_encrypt.rs index dce9a1e..872e01e 100644 --- a/src/cmd_encrypt.rs +++ b/src/cmd_encrypt.rs @@ -10,7 +10,7 @@ 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}; +use crate::{util, util_ecdh, util_x25519}; use crate::compress::GzStreamEncoder; use crate::config::{TinyEncryptConfig, TinyEncryptConfigEnvelop}; use crate::crypto_aes::aes_gcm_encrypt; @@ -233,6 +233,9 @@ fn encrypt_envelops(key: &[u8], envelops: &[&TinyEncryptConfigEnvelop]) -> XResu TinyEncryptEnvelopType::Pgp => { encrypted_envelops.push(encrypt_envelop_pgp(key, envelop)?); } + TinyEncryptEnvelopType::PgpX25519 => { + encrypted_envelops.push(encrypt_envelop_ecdh_x25519(key, envelop)?); + } TinyEncryptEnvelopType::Ecdh => { encrypted_envelops.push(encrypt_envelop_ecdh(key, envelop)?); } @@ -245,7 +248,22 @@ fn encrypt_envelops(key: &[u8], envelops: &[&TinyEncryptConfigEnvelop]) -> XResu fn encrypt_envelop_ecdh(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult { let public_key_point_hex = &envelop.public_part; let (shared_secret, ephemeral_spki) = util_ecdh::compute_shared_secret(public_key_point_hex)?; - let shared_key = util::simple_kdf(shared_secret.as_slice()); + + encrypt_envelop_shared_secret(key, &shared_secret, &ephemeral_spki, envelop) +} + +fn encrypt_envelop_ecdh_x25519(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult { + let public_key_point_hex = &envelop.public_part; + let (shared_secret, ephemeral_spki) = util_x25519::compute_x25519_shared_secret(public_key_point_hex)?; + + encrypt_envelop_shared_secret(key, &shared_secret, &ephemeral_spki, envelop) +} + +fn encrypt_envelop_shared_secret(key: &[u8], + shared_secret: &[u8], + ephemeral_spki: &[u8], + envelop: &TinyEncryptConfigEnvelop) -> XResult { + let shared_key = util::simple_kdf(shared_secret); let (_, nonce) = util::make_key256_and_nonce(); let encrypted_key = aes_gcm_encrypt(&shared_key, &nonce, key)?; diff --git a/src/main.rs b/src/main.rs index 90e89ba..2df3bce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use crate::cmd_info::CmdInfo; mod util; mod util_ecdh; +mod util_x25519; mod compress; mod config; mod spec; diff --git a/src/spec.rs b/src/spec.rs index 03bd0d9..54de156 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -50,6 +50,8 @@ pub struct TinyEncryptEnvelop { pub enum TinyEncryptEnvelopType { #[serde(rename = "pgp")] Pgp, + #[serde(rename = "pgp-x25519")] + PgpX25519, #[serde(rename = "age")] Age, #[serde(rename = "ecdh")] @@ -65,6 +67,7 @@ impl TinyEncryptEnvelopType { pub fn get_name(&self) -> &'static str { match self { TinyEncryptEnvelopType::Pgp => "pgp", + TinyEncryptEnvelopType::PgpX25519 => "pgp-x25519", TinyEncryptEnvelopType::Age => "age", TinyEncryptEnvelopType::Ecdh => "ecdh", TinyEncryptEnvelopType::Kms => "kms", diff --git a/src/util_x25519.rs b/src/util_x25519.rs new file mode 100644 index 0000000..694d040 --- /dev/null +++ b/src/util_x25519.rs @@ -0,0 +1,19 @@ +use rand::rngs::OsRng; +use rust_util::{opt_result, simple_error, XResult}; +use x25519_dalek::{EphemeralSecret, PublicKey}; + +pub fn compute_x25519_shared_secret(public_key_point_hex: &str) -> XResult<(Vec, Vec)> { + let public_key_bytes = opt_result!(hex::decode(public_key_point_hex), "Parse X25519 public key hex failed: {}"); + if public_key_bytes.len() != 32 { + return simple_error!("Parse X25519 key failed: not 32 bytes"); + } + let public_key_bytes: [u8; 32] = public_key_bytes.try_into().unwrap(); + let public_key_card = PublicKey::from(public_key_bytes); + + let ephemeral_secret = EphemeralSecret::random_from_rng(OsRng); + let ephemeral_public = PublicKey::from(&ephemeral_secret); + + let shared_secret = ephemeral_secret.diffie_hellman(&public_key_card); + + Ok((shared_secret.as_bytes().to_vec(), ephemeral_public.as_bytes().to_vec())) +} \ No newline at end of file From 4d01ea49e2a4a822b92846e1af8db2eafd324a18 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 8 Oct 2023 00:53:25 +0800 Subject: [PATCH 2/3] feat: v0.2.0-dev, x25519 encryption --- src/cmd_encrypt.rs | 9 +++++---- src/util.rs | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cmd_encrypt.rs b/src/cmd_encrypt.rs index 872e01e..3af58be 100644 --- a/src/cmd_encrypt.rs +++ b/src/cmd_encrypt.rs @@ -16,7 +16,7 @@ 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, TINY_ENC_CONFIG_FILE}; +use crate::util::{ENC_AES256_GCM_P256, ENC_AES256_GCM_X25519, TINY_ENC_CONFIG_FILE}; use crate::wrap_key::{WrapKey, WrapKeyHeader}; #[derive(Debug, Args)] @@ -249,19 +249,20 @@ fn encrypt_envelop_ecdh(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResu let public_key_point_hex = &envelop.public_part; let (shared_secret, ephemeral_spki) = util_ecdh::compute_shared_secret(public_key_point_hex)?; - encrypt_envelop_shared_secret(key, &shared_secret, &ephemeral_spki, envelop) + encrypt_envelop_shared_secret(key, &shared_secret, &ephemeral_spki, ENC_AES256_GCM_P256, envelop) } fn encrypt_envelop_ecdh_x25519(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult { let public_key_point_hex = &envelop.public_part; let (shared_secret, ephemeral_spki) = util_x25519::compute_x25519_shared_secret(public_key_point_hex)?; - encrypt_envelop_shared_secret(key, &shared_secret, &ephemeral_spki, envelop) + encrypt_envelop_shared_secret(key, &shared_secret, &ephemeral_spki, ENC_AES256_GCM_X25519, envelop) } fn encrypt_envelop_shared_secret(key: &[u8], shared_secret: &[u8], ephemeral_spki: &[u8], + enc_type: &str, envelop: &TinyEncryptConfigEnvelop) -> XResult { let shared_key = util::simple_kdf(shared_secret); let (_, nonce) = util::make_key256_and_nonce(); @@ -271,7 +272,7 @@ fn encrypt_envelop_shared_secret(key: &[u8], let wrap_key = WrapKey { header: WrapKeyHeader { kid: Some(envelop.kid.clone()), - enc: ENC_AES256_GCM_P256.to_string(), + enc: enc_type.to_string(), e_pub_key: util::encode_base64_url_no_pad(&ephemeral_spki), }, nonce, diff --git a/src/util.rs b/src/util.rs index e913202..5ec4896 100644 --- a/src/util.rs +++ b/src/util.rs @@ -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_X25519: &str = "aes256-gcm-x25519"; pub const TINY_ENC_FILE_EXT: &str = ".tinyenc"; pub const TINY_ENC_CONFIG_FILE: &str = "~/.tinyencrypt/config-rs.json"; From 3243b2aade5f3b09d4731cd3ee162d5f78f9b606 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 8 Oct 2023 22:13:59 +0800 Subject: [PATCH 3/3] feat: v0.2.0, supports openpgp x25519 --- Cargo.lock | 14 ++++----- Cargo.toml | 2 +- src/cmd_decrypt.rs | 71 +++++++++++++++++++++++++++++++++------------- src/config.rs | 20 +++++++++++-- 4 files changed, 78 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ccae7fc..047728f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1019,9 +1019,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linux-raw-sys" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db" +checksum = "45786cec4d5e54a224b15cb9f06751883103a27c19c93eda09b0b4f5f08fefac" [[package]] name = "log" @@ -1147,9 +1147,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", "libm", @@ -1920,9 +1920,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" @@ -2063,7 +2063,7 @@ dependencies = [ [[package]] name = "tiny-encrypt" -version = "0.2.0-dev" +version = "0.2.0" dependencies = [ "aes-gcm-stream", "base64", diff --git a/Cargo.toml b/Cargo.toml index e4ee0e2..496128f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tiny-encrypt" -version = "0.2.0-dev" +version = "0.2.0" edition = "2021" license = "MIT" description = "A simple and tiny file encrypt tool" diff --git a/src/cmd_decrypt.rs b/src/cmd_decrypt.rs index 7a59402..05124a0 100644 --- a/src/cmd_decrypt.rs +++ b/src/cmd_decrypt.rs @@ -6,8 +6,8 @@ use std::str::FromStr; use std::time::Instant; use clap::Args; +use openpgp_card::{OpenPgp, OpenPgpTransaction}; use openpgp_card::crypto_data::Cryptogram; -use openpgp_card::OpenPgp; 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; @@ -19,7 +19,7 @@ use crate::{card, file, util}; use crate::compress::GzStreamDecoder; use crate::crypto_aes::aes_gcm_decrypt; use crate::spec::{TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta}; -use crate::util::{ENC_AES256_GCM_P256, TINY_ENC_FILE_EXT}; +use crate::util::{ENC_AES256_GCM_P256, ENC_AES256_GCM_X25519, TINY_ENC_FILE_EXT}; use crate::wrap_key::WrapKey; #[derive(Debug, Args)] @@ -157,6 +157,7 @@ fn decrypt_file(file_in: &mut File, file_out: &mut File, key: &[u8], nonce: &[u8 fn try_decrypt_key(envelop: &TinyEncryptEnvelop, pin: &Option, slot: &Option) -> XResult> { 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(envelop, pin, slot), unknown_type => { return simple_error!("Unknown or not supported type: {}", unknown_type.get_name()); @@ -167,7 +168,7 @@ fn try_decrypt_key(envelop: &TinyEncryptEnvelop, pin: &Option, slot: &Op fn try_decrypt_key_ecdh(envelop: &TinyEncryptEnvelop, pin: &Option, slot: &Option) -> XResult> { let wrap_key = WrapKey::parse(&envelop.encrypted_key)?; if wrap_key.header.enc.as_str() != ENC_AES256_GCM_P256 { - return simple_error!("Unsupported header enc."); + return simple_error!("Unsupported header requires: {}, actual: {}", ENC_AES256_GCM_P256, &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: {}"); @@ -181,35 +182,46 @@ fn try_decrypt_key_ecdh(envelop: &TinyEncryptEnvelop, pin: &Option, slot 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 decrypted_shared_secret = opt_result!(decrypt_data( + let shared_secret = opt_result!(decrypt_data( &mut yk, &epk_bytes, AlgorithmId::EccP256, slot_id, ), "Decrypt via PIV card failed: {}"); - let key = util::simple_kdf(decrypted_shared_secret.as_slice()); + let key = util::simple_kdf(shared_secret.as_slice()); let decrypted_key = aes_gcm_decrypt(&key, &wrap_key.nonce, &wrap_key.encrypted_data)?; util::zeroize(key); + util::zeroize(shared_secret); + Ok(decrypted_key) +} + +fn try_decrypt_key_ecdh_pgp_x25519(envelop: &TinyEncryptEnvelop, pin: &Option) -> XResult> { + let wrap_key = WrapKey::parse(&envelop.encrypted_key)?; + if wrap_key.header.enc.as_str() != ENC_AES256_GCM_X25519 { + return simple_error!("Unsupported header requires: {}, actual: {}", ENC_AES256_GCM_X25519, &wrap_key.header.enc); + } + let e_pub_key = &wrap_key.header.e_pub_key; + let epk_bytes = opt_result!(util::decode_base64_url_no_pad(e_pub_key), "Invalid envelop: {}"); + + let mut pgp = get_openpgp()?; + let mut trans = opt_result!(pgp.transaction(), "Open card failed: {}"); + + read_and_verify_openpgp_pin(&mut trans, pin)?; + + let shared_secret = trans.decipher(Cryptogram::ECDH(&epk_bytes))?; + + let key = util::simple_kdf(shared_secret.as_slice()); + let decrypted_key = aes_gcm_decrypt(&key, &wrap_key.nonce, &wrap_key.encrypted_data)?; + util::zeroize(key); + util::zeroize(shared_secret); Ok(decrypted_key) } fn try_decrypt_key_pgp(envelop: &TinyEncryptEnvelop, pin: &Option) -> XResult> { - let card = match card::get_card() { - Err(e) => { - failure!("Get PGP card failed: {}", e); - return simple_error!("Get card failed: {}", e); - } - Ok(card) => card - }; - let mut pgp = OpenPgp::new(card); + let mut pgp = get_openpgp()?; let mut trans = opt_result!(pgp.transaction(), "Open card failed: {}"); - let pin = read_pin(pin); - if let Err(e) = trans.verify_pw1_user(pin.as_ref()) { - failure!("Verify user pin failed: {}", e); - return simple_error!("User pin verify failed: {}", e); - } - success!("User pin verify success!"); + read_and_verify_openpgp_pin(&mut trans, pin)?; let pgp_envelop = &envelop.encrypted_key; debugging!("PGP envelop: {}", &pgp_envelop); @@ -219,6 +231,27 @@ fn try_decrypt_key_pgp(envelop: &TinyEncryptEnvelop, pin: &Option) -> XR Ok(key) } +fn read_and_verify_openpgp_pin(trans: &mut OpenPgpTransaction, pin: &Option) -> XResult<()> { + let pin = read_pin(pin); + if let Err(e) = trans.verify_pw1_user(pin.as_ref()) { + failure!("Verify user pin failed: {}", e); + return simple_error!("User pin verify failed: {}", e); + } + success!("User pin verify success!"); + Ok(()) +} + +fn get_openpgp() -> XResult { + let card = match card::get_card() { + Err(e) => { + failure!("Get PGP card failed: {}", e); + return simple_error!("Get card failed: {}", e); + } + Ok(card) => card + }; + Ok(OpenPgp::new(card)) +} + fn read_slot(slot: &Option) -> XResult { match slot { Some(slot) => Ok(slot.to_string()), diff --git a/src/config.rs b/src/config.rs index f366c86..c2a8b42 100644 --- a/src/config.rs +++ b/src/config.rs @@ -43,6 +43,7 @@ pub struct TinyEncryptConfigEnvelop { pub r#type: TinyEncryptEnvelopType, pub kid: String, pub desc: Option, + pub args: Option>, pub public_part: String, } @@ -52,8 +53,23 @@ impl TinyEncryptConfig { let config_contents = opt_result!( fs::read_to_string(&resolved_file), "Read file: {}, failed: {}", file ); - // TODO Replace with Human JSON - Ok(opt_result!(serde_json::from_str(&config_contents), "Parse file: {}, failed: {}", file)) + let mut config: TinyEncryptConfig = opt_result!( + serde_json::from_str(&config_contents),"Parse file: {}, failed: {}", file); + let mut splitted_profiles = HashMap::new(); + for (k, v) in config.profiles.into_iter() { + if !k.contains(",") { + splitted_profiles.insert(k, v); + } else { + k.split(",") + .map(|k| k.trim()) + .filter(|k| k.len() > 0) + .for_each(|k| { + splitted_profiles.insert(k.to_string(), v.clone()); + }); + } + } + config.profiles = splitted_profiles; + Ok(config) } pub fn find_envelops(&self, profile: &Option) -> XResult> {