feat: v1.1.0, add static x25519 support
This commit is contained in:
@@ -9,7 +9,7 @@ use std::time::{Instant, SystemTime};
|
||||
use clap::Args;
|
||||
use flate2::Compression;
|
||||
use openpgp_card::crypto_data::Cryptogram;
|
||||
use rust_util::{debugging, failure, iff, information, opt_result, println_ex, simple_error, success, util_cmd, util_msg, util_size, util_time, warning, XResult};
|
||||
use rust_util::{debugging, failure, iff, information, opt_result, opt_value_result, println_ex, simple_error, success, util_cmd, util_msg, util_size, util_time, warning, XResult};
|
||||
use rust_util::util_time::UnixEpochTime;
|
||||
use x509_parser::prelude::FromDer;
|
||||
use x509_parser::x509::SubjectPublicKeyInfo;
|
||||
@@ -18,6 +18,8 @@ use yubikey::YubiKey;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use crate::{cmd_encrypt, consts, crypto_simple, util, util_enc_file, util_env, util_envelop, util_file, util_pgp, util_piv};
|
||||
#[cfg(feature = "macos")]
|
||||
use crate::util_keychainpasskey;
|
||||
use crate::compress::GzStreamDecoder;
|
||||
use crate::config::TinyEncryptConfig;
|
||||
use crate::consts::{
|
||||
@@ -61,9 +63,12 @@ pub struct CmdDecrypt {
|
||||
/// Digest file
|
||||
#[arg(long, short = 'D')]
|
||||
pub digest_file: bool,
|
||||
// Edit file
|
||||
/// Edit file
|
||||
#[arg(long, short = 'E')]
|
||||
pub edit_file: bool,
|
||||
// Readonly
|
||||
#[arg(long)]
|
||||
pub readonly: bool,
|
||||
/// Digest algorithm (sha1, sha256[default], sha384, sha512 ...)
|
||||
#[arg(long, short = 'A')]
|
||||
pub digest_algorithm: Option<String>,
|
||||
@@ -196,6 +201,10 @@ pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
|
||||
|
||||
let do_edit_file = || -> XResult<()> {
|
||||
let temp_file_content_bytes = run_file_editor_and_wait_content(&editor, &temp_file, secure_editor, &temp_encryption_key_nonce)?;
|
||||
if cmd_decrypt.readonly {
|
||||
information!("Readonly, do not check temp file is changed.");
|
||||
return Ok(());
|
||||
}
|
||||
let temp_file_content_bytes = if secure_editor {
|
||||
let mut decryptor = temp_cryptor.decryptor(&temp_key_nonce)?;
|
||||
decryptor.decrypt(&temp_file_content_bytes)?
|
||||
@@ -421,6 +430,8 @@ pub 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),
|
||||
#[cfg(feature = "macos")]
|
||||
TinyEncryptEnvelopType::StaticX25519 => try_decrypt_key_ecdh_static_x25519(config, envelop),
|
||||
TinyEncryptEnvelopType::Ecdh | TinyEncryptEnvelopType::EcdhP384 => try_decrypt_key_ecdh(config, envelop, pin, slot),
|
||||
unknown_type => simple_error!("Unknown or unsupported type: {}", unknown_type.get_name()),
|
||||
}
|
||||
@@ -491,6 +502,36 @@ fn try_decrypt_key_ecdh_pgp_x25519(envelop: &TinyEncryptEnvelop, pin: &Option<St
|
||||
Ok(decrypted_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)?;
|
||||
let cryptor = match wrap_key.header.enc.as_str() {
|
||||
ENC_AES256_GCM_X25519 => Cryptor::Aes256Gcm,
|
||||
ENC_CHACHA20_POLY1305_X25519 => Cryptor::ChaCha20Poly1305,
|
||||
_ => return simple_error!("Unsupported header enc: {}", &wrap_key.header.enc),
|
||||
};
|
||||
let e_pub_key_bytes = wrap_key.header.get_e_pub_key_bytes()?;
|
||||
let config = opt_value_result!(config, "Tiny encrypt config is not found");
|
||||
let config_envelop = opt_value_result!(
|
||||
config.find_by_kid(&envelop.kid), "Cannot find config for: {}", &envelop.kid);
|
||||
let config_envelop_args = opt_value_result!(&config_envelop.args, "No arguments found for: {}", &envelop.kid);
|
||||
if config_envelop_args.len() < 3 {
|
||||
return simple_error!("Not enough arguments for: {}", &envelop.kid);
|
||||
}
|
||||
let service_name = &config_envelop_args[1];
|
||||
let key_name = &config_envelop_args[2];
|
||||
let shared_secret = opt_result!(
|
||||
util_keychainpasskey::decrypt_data(service_name, key_name, &e_pub_key_bytes), "Decrypt static x25519 failed: {}");
|
||||
|
||||
let key = util::simple_kdf(shared_secret.as_slice());
|
||||
let key_nonce = KeyNonce { k: &key, n: &wrap_key.nonce };
|
||||
let decrypted_key = crypto_simple::decrypt(
|
||||
cryptor, &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<String>) -> XResult<Vec<u8>> {
|
||||
let mut pgp = util_pgp::get_openpgp()?;
|
||||
let mut trans = opt_result!(pgp.transaction(), "Connect OpenPGP card failed: {}");
|
||||
@@ -523,7 +564,9 @@ pub fn select_envelop<'a>(meta: &'a TinyEncryptMeta, key_id: &Option<String>, co
|
||||
if envelops.len() == 1 {
|
||||
let selected_envelop = &envelops[0];
|
||||
success!("Auto selected envelop: #{} {}", 1, util_envelop::format_envelop(selected_envelop, config));
|
||||
util::read_line("Press enter to continue: ");
|
||||
if !selected_envelop.r#type.auto_select() {
|
||||
util::read_line("Press enter to continue: ");
|
||||
}
|
||||
return Ok(selected_envelop);
|
||||
}
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ fn encrypt_envelops(cryptor: Cryptor, key: &[u8], envelops: &[&TinyEncryptConfig
|
||||
TinyEncryptEnvelopType::Pgp => {
|
||||
encrypted_envelops.push(encrypt_envelop_pgp(key, envelop)?);
|
||||
}
|
||||
TinyEncryptEnvelopType::PgpX25519 => {
|
||||
TinyEncryptEnvelopType::PgpX25519 | TinyEncryptEnvelopType::StaticX25519 => {
|
||||
encrypted_envelops.push(encrypt_envelop_ecdh_x25519(cryptor, key, envelop)?);
|
||||
}
|
||||
TinyEncryptEnvelopType::Ecdh => {
|
||||
|
||||
@@ -40,6 +40,7 @@ impl Drop for CmdExecEnv {
|
||||
}
|
||||
|
||||
pub fn exec_env(cmd_exec_env: CmdExecEnv) -> XResult<()> {
|
||||
util_msg::set_logger_std_out(false);
|
||||
debugging!("Cmd exec env: {:?}", cmd_exec_env);
|
||||
let config = TinyEncryptConfig::load(TINY_ENC_CONFIG_FILE).ok();
|
||||
if cmd_exec_env.arguments.is_empty() {
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
use clap::Args;
|
||||
use rust_util::XResult;
|
||||
use rust_util::{debugging, information, opt_result, simple_error, success, XResult};
|
||||
use security_framework::os::macos::keychain::SecKeychain;
|
||||
|
||||
use crate::config::TinyEncryptConfigEnvelop;
|
||||
use crate::spec::TinyEncryptEnvelopType;
|
||||
use crate::util_keychainpasskey;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct CmdKeychainKey {
|
||||
/// Keychain name, or default
|
||||
#[arg(long, short = 'c')]
|
||||
pub keychain_name: Option<String>,
|
||||
// /// Keychain name, or default
|
||||
// #[arg(long, short = 'c')]
|
||||
// pub keychain_name: Option<String>,
|
||||
/// Service name, or tiny-encrypt
|
||||
#[arg(long, short = 's')]
|
||||
pub server_name: Option<String>,
|
||||
@@ -20,21 +25,38 @@ pub struct CmdKeychainKey {
|
||||
#[allow(dead_code)]
|
||||
const DEFAULT_SERVICE_NAME: &str = "tiny-encrypt";
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum KeyType {
|
||||
P256,
|
||||
P384,
|
||||
X25519,
|
||||
}
|
||||
pub fn keychain_key(cmd_keychain_key: CmdKeychainKey) -> XResult<()> {
|
||||
let service_name = cmd_keychain_key.server_name.as_deref().unwrap_or(DEFAULT_SERVICE_NAME);
|
||||
let sec_keychain = opt_result!(SecKeychain::default(), "Get keychain failed: {}");
|
||||
if sec_keychain.find_generic_password(service_name, &cmd_keychain_key.key_name).is_ok() {
|
||||
return simple_error!("Static x25519 exists: {}.{}", service_name, &cmd_keychain_key.key_name);
|
||||
}
|
||||
|
||||
let (keychain_key, public_key) = util_keychainpasskey::generate_pass_x25519_static_secret();
|
||||
opt_result!(
|
||||
sec_keychain.set_generic_password(service_name, &cmd_keychain_key.key_name, keychain_key.as_bytes()),
|
||||
"Write static x25519 failed: {}"
|
||||
);
|
||||
|
||||
let public_key_hex = hex::encode(public_key.as_bytes());
|
||||
debugging!("Keychain key : {}", keychain_key);
|
||||
success!("Keychain name: {}", &cmd_keychain_key.key_name);
|
||||
success!("Public key : {}", &public_key_hex);
|
||||
|
||||
let config_envelop = TinyEncryptConfigEnvelop {
|
||||
r#type: TinyEncryptEnvelopType::StaticX25519,
|
||||
sid: Some(cmd_keychain_key.key_name.clone()),
|
||||
kid: format!("keychain:{}", &public_key_hex),
|
||||
desc: Some("Keychain static".to_string()),
|
||||
args: Some(vec![
|
||||
"".to_string(),
|
||||
service_name.to_string(),
|
||||
cmd_keychain_key.key_name.clone(),
|
||||
]),
|
||||
public_part: public_key_hex,
|
||||
};
|
||||
|
||||
information!("Config envelop:\n{}", serde_json::to_string_pretty(&config_envelop).unwrap());
|
||||
|
||||
// TODO Under developing
|
||||
// keychain://keychain_name?sn=service_name&kt=kp-p256&kn=key_name&fp=fingerprint
|
||||
// keychain_name -> default
|
||||
// service_name -> tiny-encrypt
|
||||
// kt=kp-p256|kp-p384|kp-x25519 -> keypair P256, P385 or X25519
|
||||
// key_name -> key name in keychain
|
||||
// fingerprint -> hex(SHA256(public_key)[0..4])
|
||||
pub fn keychain_key(_cmd_keychain_key: CmdKeychainKey) -> XResult<()> {
|
||||
println!();
|
||||
Ok(())
|
||||
}
|
||||
@@ -42,9 +42,12 @@ pub struct TinyEncryptConfig {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TinyEncryptConfigEnvelop {
|
||||
pub r#type: TinyEncryptEnvelopType,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sid: Option<String>,
|
||||
pub kid: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub desc: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub args: Option<Vec<String>>,
|
||||
pub public_part: String,
|
||||
}
|
||||
|
||||
17
src/lib.rs
17
src/lib.rs
@@ -1,10 +1,10 @@
|
||||
pub use cmd_config::CmdConfig;
|
||||
pub use cmd_config::config;
|
||||
#[cfg(feature = "smartcard")]
|
||||
#[cfg(feature = "decrypt")]
|
||||
pub use cmd_decrypt::CmdDecrypt;
|
||||
#[cfg(feature = "smartcard")]
|
||||
#[cfg(feature = "decrypt")]
|
||||
pub use cmd_decrypt::decrypt;
|
||||
#[cfg(feature = "smartcard")]
|
||||
#[cfg(feature = "decrypt")]
|
||||
pub use cmd_decrypt::decrypt_single;
|
||||
pub use cmd_directdecrypt::CmdDirectDecrypt;
|
||||
pub use cmd_directdecrypt::direct_decrypt;
|
||||
@@ -21,7 +21,9 @@ pub use cmd_version::version;
|
||||
pub use cmd_initkeychainkey::CmdKeychainKey;
|
||||
#[cfg(feature = "macos")]
|
||||
pub use cmd_initkeychainkey::keychain_key;
|
||||
#[cfg(feature = "decrypt")]
|
||||
pub use cmd_execenv::CmdExecEnv;
|
||||
#[cfg(feature = "decrypt")]
|
||||
pub use cmd_execenv::exec_env;
|
||||
|
||||
|
||||
@@ -30,9 +32,9 @@ mod util;
|
||||
mod util_env;
|
||||
mod util_digest;
|
||||
mod util_progress;
|
||||
#[cfg(feature = "smartcard")]
|
||||
#[cfg(feature = "decrypt")]
|
||||
mod util_piv;
|
||||
#[cfg(feature = "smartcard")]
|
||||
#[cfg(feature = "decrypt")]
|
||||
mod util_pgp;
|
||||
mod util_p256;
|
||||
mod util_p384;
|
||||
@@ -50,11 +52,14 @@ mod util_enc_file;
|
||||
mod cmd_version;
|
||||
mod cmd_config;
|
||||
mod cmd_info;
|
||||
#[cfg(feature = "smartcard")]
|
||||
#[cfg(feature = "decrypt")]
|
||||
mod cmd_decrypt;
|
||||
mod cmd_encrypt;
|
||||
mod cmd_directdecrypt;
|
||||
#[cfg(feature = "macos")]
|
||||
mod cmd_initkeychainkey;
|
||||
#[cfg(feature = "macos")]
|
||||
mod util_keychainpasskey;
|
||||
#[cfg(feature = "decrypt")]
|
||||
mod cmd_execenv;
|
||||
|
||||
|
||||
12
src/main.rs
12
src/main.rs
@@ -3,9 +3,11 @@ extern crate core;
|
||||
use clap::{Parser, Subcommand};
|
||||
use rust_util::XResult;
|
||||
|
||||
use tiny_encrypt::{CmdConfig, CmdDirectDecrypt, CmdEncrypt, CmdExecEnv, CmdInfo, CmdVersion};
|
||||
#[cfg(feature = "smartcard")]
|
||||
use tiny_encrypt::{CmdConfig, CmdDirectDecrypt, CmdEncrypt, CmdInfo, CmdVersion};
|
||||
#[cfg(feature = "decrypt")]
|
||||
use tiny_encrypt::CmdDecrypt;
|
||||
#[cfg(feature = "decrypt")]
|
||||
use tiny_encrypt::CmdExecEnv;
|
||||
#[cfg(feature = "macos")]
|
||||
use tiny_encrypt::CmdKeychainKey;
|
||||
|
||||
@@ -22,7 +24,7 @@ enum Commands {
|
||||
/// Encrypt file(s)
|
||||
#[command(arg_required_else_help = true, short_flag = 'e')]
|
||||
Encrypt(CmdEncrypt),
|
||||
#[cfg(feature = "smartcard")]
|
||||
#[cfg(feature = "decrypt")]
|
||||
/// Decrypt file(s)
|
||||
#[command(arg_required_else_help = true, short_flag = 'd')]
|
||||
Decrypt(CmdDecrypt),
|
||||
@@ -36,6 +38,7 @@ enum Commands {
|
||||
/// Keychain Key [pending implementation]
|
||||
#[command(arg_required_else_help = true, short_flag = 'k')]
|
||||
KeychainKey(CmdKeychainKey),
|
||||
#[cfg(feature = "decrypt")]
|
||||
/// Execute env
|
||||
#[command(arg_required_else_help = true, short_flag = 'X')]
|
||||
ExecEnv(CmdExecEnv),
|
||||
@@ -51,12 +54,13 @@ fn main() -> XResult<()> {
|
||||
let args = Cli::parse();
|
||||
match args.command {
|
||||
Commands::Encrypt(cmd_encrypt) => tiny_encrypt::encrypt(cmd_encrypt),
|
||||
#[cfg(feature = "smartcard")]
|
||||
#[cfg(feature = "decrypt")]
|
||||
Commands::Decrypt(cmd_decrypt) => tiny_encrypt::decrypt(cmd_decrypt),
|
||||
Commands::DirectDecrypt(cmd_direct_decrypt) => tiny_encrypt::direct_decrypt(cmd_direct_decrypt),
|
||||
Commands::Info(cmd_info) => tiny_encrypt::info(cmd_info),
|
||||
#[cfg(feature = "macos")]
|
||||
Commands::KeychainKey(cmd_keychain_key) => tiny_encrypt::keychain_key(cmd_keychain_key),
|
||||
#[cfg(feature = "decrypt")]
|
||||
Commands::ExecEnv(cmd_exec_env) => tiny_encrypt::exec_env(cmd_exec_env),
|
||||
Commands::Version(cmd_version) => tiny_encrypt::version(cmd_version),
|
||||
Commands::Config(cmd_config) => tiny_encrypt::config(cmd_config),
|
||||
|
||||
17
src/spec.rs
17
src/spec.rs
@@ -71,6 +71,9 @@ pub enum TinyEncryptEnvelopType {
|
||||
// OpenPGP X25519
|
||||
#[serde(rename = "pgp-x25519")]
|
||||
PgpX25519,
|
||||
// Static X25519 (less secure)
|
||||
#[serde(rename = "static-x25519")]
|
||||
StaticX25519,
|
||||
// Age, tiny-encrypt-rs is not supported
|
||||
#[serde(rename = "age")]
|
||||
Age,
|
||||
@@ -89,16 +92,30 @@ impl TinyEncryptEnvelopType {
|
||||
pub fn get_upper_name(&self) -> String {
|
||||
self.get_name().to_uppercase()
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> &'static str {
|
||||
match self {
|
||||
TinyEncryptEnvelopType::Pgp => "pgp",
|
||||
TinyEncryptEnvelopType::PgpX25519 => "pgp-x25519",
|
||||
TinyEncryptEnvelopType::StaticX25519 => "static-x25519",
|
||||
TinyEncryptEnvelopType::Age => "age",
|
||||
TinyEncryptEnvelopType::Ecdh => "ecdh",
|
||||
TinyEncryptEnvelopType::EcdhP384 => "ecdh-p384",
|
||||
TinyEncryptEnvelopType::Kms => "kms",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn auto_select(&self) -> bool {
|
||||
match self {
|
||||
TinyEncryptEnvelopType::Pgp => false,
|
||||
TinyEncryptEnvelopType::PgpX25519 => false,
|
||||
TinyEncryptEnvelopType::StaticX25519 => true,
|
||||
TinyEncryptEnvelopType::Age => false,
|
||||
TinyEncryptEnvelopType::Ecdh => false,
|
||||
TinyEncryptEnvelopType::EcdhP384 => false,
|
||||
TinyEncryptEnvelopType::Kms => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
||||
@@ -26,7 +26,7 @@ fn get_envelop_desc(envelop: &TinyEncryptEnvelop, config_envelop: &Option<&TinyE
|
||||
}
|
||||
|
||||
pub fn with_width_type(s: &str) -> String {
|
||||
with_width(s, 10)
|
||||
with_width(s, 13)
|
||||
}
|
||||
|
||||
pub fn with_width(s: &str, width: usize) -> String {
|
||||
|
||||
75
src/util_keychainpasskey.rs
Normal file
75
src/util_keychainpasskey.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use rust_util::{opt_result, simple_error, XResult};
|
||||
use security_framework::os::macos::keychain::SecKeychain;
|
||||
use x25519_dalek::{PublicKey, StaticSecret};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
const X2559_PLAIN_PREFIX: &str = "x25519-plain:";
|
||||
|
||||
pub struct X25519StaticSecret {
|
||||
pub secret: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Zeroize for X25519StaticSecret {
|
||||
fn zeroize(&mut self) {
|
||||
self.secret.zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
impl X25519StaticSecret {
|
||||
pub fn parse(key: &str) -> XResult<Self> {
|
||||
if !key.starts_with(X2559_PLAIN_PREFIX) {
|
||||
return simple_error!("Not X25519 plain key");
|
||||
}
|
||||
let extract_key_hex = &key[X2559_PLAIN_PREFIX.len()..];
|
||||
let extract_key = opt_result!(hex::decode(extract_key_hex), "Decode X25519 plain key failed: {}");
|
||||
Ok(Self {
|
||||
secret: extract_key,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn to_str(&self) -> String {
|
||||
let mut v = String::new();
|
||||
v.push_str(X2559_PLAIN_PREFIX);
|
||||
v.push_str(&hex::encode(&self.secret));
|
||||
v
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Self {
|
||||
Self {
|
||||
secret: bytes.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_static_secret(&self) -> XResult<StaticSecret> {
|
||||
let secret_slice = self.secret.as_slice();
|
||||
let mut inner_secret: [u8; 32] = opt_result!(secret_slice.try_into(), "X25519 secret key error: {}");
|
||||
let static_secret = StaticSecret::from(inner_secret);
|
||||
inner_secret.zeroize();
|
||||
Ok(static_secret)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrypt_data(service_name: &str, key_name: &str, ephemeral_public_key_bytes: &[u8]) -> XResult<Vec<u8>> {
|
||||
let sec_keychain = opt_result!(SecKeychain::default(), "Get keychain failed: {}");
|
||||
let (static_x25519, _) = opt_result!(sec_keychain.find_generic_password(service_name, key_name),
|
||||
"Cannot find static x25519 {}.{}: {}", service_name, key_name);
|
||||
let static_x25519_bytes = static_x25519.as_ref();
|
||||
let static_x25519_str = opt_result!(String::from_utf8(static_x25519_bytes.to_vec()), "Parse static x25519 failed: {}");
|
||||
|
||||
let x25519_static_secret = X25519StaticSecret::parse(&static_x25519_str)?;
|
||||
let static_secret = x25519_static_secret.to_static_secret()?;
|
||||
let inner_ephemeral_public_key: [u8; 32] = opt_result!(
|
||||
ephemeral_public_key_bytes.try_into(), "X25519 public key error: {}");
|
||||
let ephemeral_public_key = PublicKey::from(inner_ephemeral_public_key);
|
||||
let shared_secret = static_secret.diffie_hellman(&ephemeral_public_key);
|
||||
|
||||
Ok(shared_secret.as_bytes().to_vec())
|
||||
}
|
||||
|
||||
pub fn generate_pass_x25519_static_secret() -> (String, PublicKey) {
|
||||
let static_secret = StaticSecret::random();
|
||||
let public_key: PublicKey = (&static_secret).into();
|
||||
let static_secret_bytes = static_secret.as_bytes();
|
||||
let x25519_static_secret = X25519StaticSecret::from_bytes(static_secret_bytes);
|
||||
(x25519_static_secret.to_str(), public_key)
|
||||
}
|
||||
Reference in New Issue
Block a user