From 3e2a3cc7f32b1b356122436af2af6317860f6526 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Thu, 28 Dec 2023 23:00:29 +0800 Subject: [PATCH] feat: keychain-name, but tests not passed --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/cmd_initkeychain.rs | 12 +++++++----- src/util_keychainstatic.rs | 23 ++++++++++++++++------- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f0b1fa..387a244 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1753,7 +1753,7 @@ dependencies = [ [[package]] name = "tiny-encrypt" -version = "1.7.0" +version = "1.7.1" dependencies = [ "aes-gcm-stream", "base64", diff --git a/Cargo.toml b/Cargo.toml index 93cb037..889fdf5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tiny-encrypt" -version = "1.7.0" +version = "1.7.1" 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 9ad633c..a65a321 100644 --- a/src/cmd_initkeychain.rs +++ b/src/cmd_initkeychain.rs @@ -19,9 +19,9 @@ pub struct CmdInitKeychain { #[arg(long, short = 'E')] pub expose_secure_enclave_private_key: bool, - // /// Keychain name, or default - // #[arg(long, short = 'c')] - // pub keychain_name: Option, + /// Keychain name, or default [--keychain-name not works yet] + #[arg(long, short = 'c')] + pub keychain_name: Option, /// Service name, or default: tiny-encrypt #[arg(long, short = 's')] @@ -55,6 +55,7 @@ pub fn keychain_key_se(cmd_init_keychain: CmdInitKeychain) -> XResult<()> { return simple_error!("Secure enclave is not supported."); } + let keychain_name = cmd_init_keychain.keychain_name.as_ref().map(String::as_str).unwrap_or(""); let service_name = cmd_init_keychain.server_name.as_deref().unwrap_or(DEFAULT_SERVICE_NAME); let key_name = &cmd_init_keychain.key_name; @@ -64,7 +65,7 @@ pub fn keychain_key_se(cmd_init_keychain: CmdInitKeychain) -> XResult<()> { let saved_arg0 = if cmd_init_keychain.expose_secure_enclave_private_key { private_key_base64 } else { - let keychain_key = KeychainKey::from_default_keychain(service_name, key_name); + let keychain_key = KeychainKey::from(keychain_name, service_name, key_name); keychain_key.set_password(private_key_base64.as_bytes())?; keychain_key.to_str() }; @@ -84,9 +85,10 @@ pub fn keychain_key_se(cmd_init_keychain: CmdInitKeychain) -> XResult<()> { } pub fn keychain_key_static(cmd_init_keychain: CmdInitKeychain) -> XResult<()> { + let keychain_name = cmd_init_keychain.keychain_name.as_ref().map(String::as_str).unwrap_or(""); let service_name = cmd_init_keychain.server_name.as_deref().unwrap_or(DEFAULT_SERVICE_NAME); let key_name = &cmd_init_keychain.key_name; - let keychain_key = KeychainKey::from_default_keychain(service_name, key_name); + let keychain_key = KeychainKey::from(keychain_name, service_name, key_name); let mut envelop_type = match &cmd_init_keychain.algorithm { None => TinyEncryptEnvelopType::StaticX25519, diff --git a/src/util_keychainstatic.rs b/src/util_keychainstatic.rs index 4905042..e28e0c7 100644 --- a/src/util_keychainstatic.rs +++ b/src/util_keychainstatic.rs @@ -3,7 +3,7 @@ use pqcrypto_kyber::kyber1024::Ciphertext as Kyber1024Ciphertext; use pqcrypto_kyber::kyber1024::PublicKey as Kyber1024PublicKey; use pqcrypto_kyber::kyber1024::SecretKey as Kyber1024SecretKey; use rust_util::{debugging, opt_result, opt_value_result, simple_error, XResult}; -use security_framework::os::macos::keychain::SecKeychain; +use security_framework::os::macos::keychain::{CreateOptions, SecKeychain}; use x25519_dalek::{PublicKey, StaticSecret}; use zeroize::Zeroize; @@ -138,11 +138,8 @@ impl KeychainStaticSecret { } impl KeychainKey { - pub fn from_default_keychain(service_name: &str, key_name: &str) -> Self { - Self::from("", service_name, key_name) - } - pub fn from(keychain_name: &str, service_name: &str, key_name: &str) -> Self { + debugging!("Keychain key: {} - {} - {}", keychain_name, service_name, key_name); Self { keychain_name: keychain_name.to_string(), service_name: service_name.to_string(), @@ -179,6 +176,7 @@ impl KeychainKey { pub fn get_password(&self) -> XResult>> { let sec_keychain = self.get_keychain()?; + debugging!("Try find generic password: {}.{}", &self.service_name, &self.key_name); match sec_keychain.find_generic_password(&self.service_name, &self.key_name) { Ok((item_password, _keychain_item)) => { Ok(Some(item_password.as_ref().to_vec())) @@ -204,9 +202,20 @@ impl KeychainKey { fn get_keychain(&self) -> XResult { if !self.keychain_name.is_empty() { - return simple_error!("Keychain name must be empty."); + // TODO --keychain-name test failed + debugging!("Open or create keychain: {}", &self.keychain_name); + let keychain_path = format!("{}.keychain", &self.keychain_name); + debugging!("Keychain path: {}", &keychain_path); + match SecKeychain::open(&keychain_path) { + Ok(sec_keychain) => Ok(sec_keychain), + Err(e) => match CreateOptions::new().prompt_user(true).create(&keychain_path) { + Ok(sec_keychain) => Ok(sec_keychain), + Err(ce) => simple_error!("Open keychain: {}, failed: {}, create also failed: {}", &self.keychain_name, e, ce) + } + } + } else { + Ok(opt_result!(SecKeychain::default(), "Get keychain failed: {}")) } - Ok(opt_result!(SecKeychain::default(), "Get keychain failed: {}")) } }