feat: generate se keypair
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
use clap::Args;
|
||||
use rust_util::{debugging, information, opt_result, simple_error, success, XResult};
|
||||
use rust_util::{debugging, information, opt_result, opt_value_result, simple_error, success, XResult};
|
||||
use security_framework::os::macos::keychain::SecKeychain;
|
||||
|
||||
use crate::{util_keychainkey, util_keychainstatic};
|
||||
use crate::config::TinyEncryptConfigEnvelop;
|
||||
use crate::spec::TinyEncryptEnvelopType;
|
||||
use crate::util_keychainstatic;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct CmdKeychainKey {
|
||||
/// Secure Enclave
|
||||
#[arg(long, short = 'S')]
|
||||
pub secure_enclave: bool,
|
||||
// /// Keychain name, or default
|
||||
// #[arg(long, short = 'c')]
|
||||
// pub keychain_name: Option<String>,
|
||||
@@ -16,39 +19,70 @@ pub struct CmdKeychainKey {
|
||||
pub server_name: Option<String>,
|
||||
/// Key name
|
||||
#[arg(long, short = 'n')]
|
||||
pub key_name: String,
|
||||
pub key_name: Option<String>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
const DEFAULT_SERVICE_NAME: &str = "tiny-encrypt";
|
||||
|
||||
pub fn keychain_key(cmd_keychain_key: CmdKeychainKey) -> XResult<()> {
|
||||
if cmd_keychain_key.secure_enclave {
|
||||
keychain_key_se(cmd_keychain_key)
|
||||
} else {
|
||||
keychain_key_static(cmd_keychain_key)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keychain_key_se(cmd_keychain_key: CmdKeychainKey) -> XResult<()> {
|
||||
if !util_keychainkey::is_support_se() {
|
||||
return simple_error!("Secure enclave is not supported.");
|
||||
}
|
||||
let (public_key_hex, private_key_base64) = util_keychainkey::generate_se_p256_keypair()?;
|
||||
|
||||
let config_envelop = TinyEncryptConfigEnvelop {
|
||||
r#type: TinyEncryptEnvelopType::KeyP256,
|
||||
sid: cmd_keychain_key.key_name.clone(),
|
||||
kid: format!("keychain:{}", &public_key_hex),
|
||||
desc: Some("Keychain Secure Enclave".to_string()),
|
||||
args: Some(vec![
|
||||
private_key_base64
|
||||
]),
|
||||
public_part: public_key_hex,
|
||||
};
|
||||
|
||||
information!("Config envelop:\n{}", serde_json::to_string_pretty(&config_envelop).unwrap());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn keychain_key_static(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 key_name = opt_value_result!(&cmd_keychain_key.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, &cmd_keychain_key.key_name, keychain_key.as_bytes()),
|
||||
sec_keychain.set_generic_password(service_name, &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!("Keychain name: {}", &key_name);
|
||||
success!("Public key : {}", &public_key_hex);
|
||||
|
||||
let config_envelop = TinyEncryptConfigEnvelop {
|
||||
r#type: TinyEncryptEnvelopType::StaticX25519,
|
||||
sid: Some(cmd_keychain_key.key_name.clone()),
|
||||
sid: Some(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(),
|
||||
key_name.clone(),
|
||||
]),
|
||||
public_part: public_key_hex,
|
||||
};
|
||||
|
||||
@@ -1,12 +1,34 @@
|
||||
use rust_util::{opt_result, simple_error, XResult};
|
||||
use swift_rs::{Bool, SRString};
|
||||
use swift_rs::swift;
|
||||
|
||||
use crate::util;
|
||||
|
||||
swift!(fn is_support_secure_enclave() -> Bool);
|
||||
swift!(fn print_greeting(name: SRString) -> Bool);
|
||||
swift!(fn generate_secure_enclave_p256_keypair() -> SRString);
|
||||
swift!(fn compute_secure_enclave_p256_ecdh(private_key_base64: SRString, ephemera_public_key_base64: SRString) -> SRString);
|
||||
|
||||
pub fn is_support_se() -> bool {
|
||||
unsafe {
|
||||
print_greeting(SRString::from("hatter"));
|
||||
}
|
||||
unsafe { is_support_secure_enclave() }
|
||||
}
|
||||
|
||||
pub fn generate_se_p256_keypair() -> XResult<(String, String)> {
|
||||
if !is_support_se() {
|
||||
return simple_error!("Secure enclave is not supported.");
|
||||
}
|
||||
let result = unsafe { generate_secure_enclave_p256_keypair() };
|
||||
let result = result.as_str();
|
||||
if !result.starts_with("ok:") {
|
||||
return simple_error!("Generate P256 in secure enclave failed: {}", result);
|
||||
}
|
||||
let public_key_and_private_key = result.chars().skip(3).collect::<String>();
|
||||
let public_key_and_private_keys = public_key_and_private_key.split(",").collect::<Vec<_>>();
|
||||
if public_key_and_private_keys.len() != 2 {
|
||||
return simple_error!("Generate P256 in secure enclave result is bad: {}", public_key_and_private_key);
|
||||
}
|
||||
let public_key = hex::encode(
|
||||
opt_result!(util::decode_base64(public_key_and_private_keys[0]), "Public key is not base64 encoded: {}"));
|
||||
let private_key = public_key_and_private_keys[1].to_string();
|
||||
|
||||
Ok((public_key, private_key))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user