From 7ee38b8ac5ce6ca33c1acff2c2a3c66f41cf4d1e Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 10 Dec 2023 12:32:46 +0800 Subject: [PATCH] feat: v1.4.3, init static x25519 when exists --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/cmd_initkeychain.rs | 28 ++++++++++++++++++---------- src/util_keychainstatic.rs | 15 ++++++++++++--- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1268869..d2c9e1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1700,7 +1700,7 @@ dependencies = [ [[package]] name = "tiny-encrypt" -version = "1.4.2" +version = "1.4.3" dependencies = [ "aes-gcm-stream", "base64", diff --git a/Cargo.toml b/Cargo.toml index 441b38f..3873a75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tiny-encrypt" -version = "1.4.2" +version = "1.4.3" edition = "2021" license = "MIT" description = "A simple and tiny file encrypt tool" diff --git a/src/cmd_initkeychain.rs b/src/cmd_initkeychain.rs index 1f43396..bbc6d2e 100644 --- a/src/cmd_initkeychain.rs +++ b/src/cmd_initkeychain.rs @@ -1,5 +1,5 @@ use clap::Args; -use rust_util::{debugging, information, opt_result, opt_value_result, simple_error, success, XResult}; +use rust_util::{debugging, information, opt_result, opt_value_result, simple_error, success, warning, XResult}; use security_framework::os::macos::keychain::SecKeychain; use crate::config::TinyEncryptConfigEnvelop; @@ -7,6 +7,7 @@ use crate::spec::TinyEncryptEnvelopType; #[cfg(feature = "secure-enclave")] use crate::util_keychainkey; use crate::util_keychainstatic; +use crate::util_keychainstatic::X25519StaticSecret; #[derive(Debug, Args)] pub struct CmdInitKeychain { @@ -66,18 +67,25 @@ pub fn keychain_key_static(cmd_init_keychain: CmdInitKeychain) -> XResult<()> { let service_name = cmd_init_keychain.server_name.as_deref().unwrap_or(DEFAULT_SERVICE_NAME); let sec_keychain = opt_result!(SecKeychain::default(), "Get keychain failed: {}"); let key_name = opt_value_result!(&cmd_init_keychain.key_name, "Key name is required."); - if sec_keychain.find_generic_password(service_name, key_name).is_ok() { - return simple_error!("Static x25519 exists: {}.{}", service_name, &key_name); - } - let (keychain_key, public_key) = util_keychainstatic::generate_static_x25519_secret(); - opt_result!( - sec_keychain.set_generic_password(service_name, key_name, keychain_key.as_bytes()), - "Write static x25519 failed: {}" - ); + let public_key = match sec_keychain.find_generic_password(service_name, key_name) { + Ok((static_x25519, _)) => { + warning!("Key already exists: {}.{}", service_name, key_name); + let x25519_static_secret = X25519StaticSecret::parse_bytes(&static_x25519.as_ref())?; + x25519_static_secret.to_public_key()? + } + Err(_) => { + let (keychain_key, public_key) = util_keychainstatic::generate_static_x25519_secret(); + debugging!("Keychain key : {}", keychain_key); + opt_result!( + sec_keychain.set_generic_password(service_name, key_name, keychain_key.as_bytes()), + "Write static x25519 failed: {}" + ); + public_key + } + }; let public_key_hex = hex::encode(public_key.as_bytes()); - debugging!("Keychain key : {}", keychain_key); success!("Keychain name: {}", &key_name); success!("Public key : {}", &public_key_hex); diff --git a/src/util_keychainstatic.rs b/src/util_keychainstatic.rs index fdc5912..f8b5d63 100644 --- a/src/util_keychainstatic.rs +++ b/src/util_keychainstatic.rs @@ -16,6 +16,11 @@ impl Zeroize for X25519StaticSecret { } impl X25519StaticSecret { + pub fn parse_bytes(bs: &[u8]) -> XResult { + let key_str = opt_result!(String::from_utf8(bs.to_vec()), "Parse static x25519 failed: {}"); + Self::parse(&key_str) + } + pub fn parse(key: &str) -> XResult { if !key.starts_with(X2559_PLAIN_PREFIX) { return simple_error!("Not X25519 plain key"); @@ -47,16 +52,20 @@ impl X25519StaticSecret { inner_secret.zeroize(); Ok(static_secret) } + + pub fn to_public_key(&self) -> XResult { + let static_secret = self.to_static_secret()?; + let public_key: PublicKey = (&static_secret).into(); + Ok(public_key) + } } pub fn decrypt_data(service_name: &str, key_name: &str, ephemeral_public_key_bytes: &[u8]) -> XResult> { 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 x25519_static_secret = X25519StaticSecret::parse_bytes(static_x25519.as_ref())?; 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: {}");