feat: v1.2.4, ML-KEM ECDH
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "swift-secure-enclave-tool-rs"
|
name = "swift-secure-enclave-tool-rs"
|
||||||
version = "1.2.3"
|
version = "1.2.4"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors = ["Hatter Jiang"]
|
authors = ["Hatter Jiang"]
|
||||||
repository = "https://git.hatter.ink/hatter/swift-secure-enclave-tool-rs"
|
repository = "https://git.hatter.ink/hatter/swift-secure-enclave-tool-rs"
|
||||||
|
|||||||
94
examples/generate_mlkem_keypair.rs
Normal file
94
examples/generate_mlkem_keypair.rs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
use base64::engine::general_purpose::STANDARD;
|
||||||
|
use base64::Engine;
|
||||||
|
use swift_secure_enclave_tool_rs::{generate_mlkem_keypair, is_secure_enclave_supported, private_key_mlkem_ecdh, recover_mlkem_keypair, ControlFlag, KeyMaterial, KeyMlKem};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!(
|
||||||
|
"Secure Enclave supported: {}",
|
||||||
|
is_secure_enclave_supported().unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mlkem_key_material = generate_mlkem_keypair(KeyMlKem::MlKem768, ControlFlag::None).unwrap();
|
||||||
|
print_key_material("Signing key [none]", &mlkem_key_material);
|
||||||
|
|
||||||
|
let recover_mlkem_key_material = recover_mlkem_keypair(
|
||||||
|
KeyMlKem::MlKem768,
|
||||||
|
&mlkem_key_material.private_key_representation,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
print_key_material("Signing key [none]", &recover_mlkem_key_material);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
let mlkem_key_material =
|
||||||
|
generate_mlkem_keypair(KeyMlKem::MlKem1024, ControlFlag::None).unwrap();
|
||||||
|
print_key_material("Signing key [none]", &mlkem_key_material);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// ONLY runs on MacBook M4 Air
|
||||||
|
use base64::engine::general_purpose::STANDARD;
|
||||||
|
let shared_secret = private_key_mlkem_ecdh(KeyMlKem::MlKem768,
|
||||||
|
&STANDARD.decode("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\
|
||||||
|
JDARvc2duAQEBMAcMAm9hAQEBMAgMA29rZAEBAQ==").unwrap(),
|
||||||
|
&STANDARD.decode("h47sMRkMBJ4XCF932REsgU6245kAZtLl8OlrtxCKpTxf+g8td\
|
||||||
|
VHrXhVGAQyA2cP/YdpI3KdhCnn3xMqAR73Iu6nc4GoEvDHxvI/E3CvBEI+/gfqACWb0VTrX6H\
|
||||||
|
ks4tRZ3vDhzkTCwdjXV7udO62eN4JHLUoH3ml5O9rPLZHwP1dEkXIwfWuXY2fjLxpcTuoWhw3\
|
||||||
|
3K3mS4NeGSm1WAJdFojVo8sRiH5NuOI/GXFHY+Hm1CKRou/kQCS+1wN+5qXDDYAf1sVIR7ZdF\
|
||||||
|
bSnaWPijzkvVJEHR1cQmerpHThcd+zjrYGBCo6Rd4LlN8cfTuad+d88yTcUwLZfMhL6akTZTu\
|
||||||
|
AVQllFMhdxIQQnCsK2iI8/MRCG0tJJm91YKz2voUDOZcQBetULSFzVnsi8fIJ8hhP1yzHJkyU\
|
||||||
|
bKiYiJW5uZBJ1ye9SEYvWBTWQdpmEMKuM55vUuZq9tGYkja2oT9rkhrI1bGMy5RN0mauOsHCM\
|
||||||
|
8OvCe8TeggZeAD8INv9sCkBgm9Hk4gjUkIV6e//pshbwSXasgdzB02teP/K5OfmELP+IK75Pz\
|
||||||
|
sgPSPWuTfMWlCK4xjE9seCZjqCB8lQ0/gQE6TnKGPPYEjFHP6q89HgDUMDqa4h8YXV2XHWLro\
|
||||||
|
LMXrWG/lLkPIPI1vJT3+Hij4eON/3IMK713nEUKzNVwaANtIqP+Mp3zIRORSOFI+KRjdfdGBS\
|
||||||
|
3ciBtVr7rIc+38/uQQKXLl1ELLmc6r569UXgelKy+H4W8koFdMOrJXb1YH7uM+zCV2hfZ8D+R\
|
||||||
|
SOETd9NZEjGOHVCLDALbuxwgbwRgBNBDIoS7eIRFo3lIQO0kRlsS5n47UeyqeL2/vKtblGP/p\
|
||||||
|
t6OUprgM21JISHLvc9Ezl3UQhl9QHjCdHEiL1W3vzncxluu9Z39bwf7JX9vLafImrPoWKPAu/\
|
||||||
|
V89mf6cX6ly/stGzzp3tCxuGUopsNWJ760rXzPkxHqSNOPU9tWxKD94bNJgtztGGMBp7/HGFI\
|
||||||
|
2ftdZE5JU/a+e8R2VLTXAeG6ByhrTmD008KPiKK72QBRYuwC7MvxHLyIn2BhnoHO6KDcUhpLJ\
|
||||||
|
sPPWc/odxWLU72XAg2MD3yZnsQodYphVbeQiFH/qUscTTcjSYp0xCeiPoXDwtqyCySKkRHvr6\
|
||||||
|
xtbECTTS6M0Q+Ahf7A2vZrEAUKAktPmX15F0ctl13/XMH1766uf8ptSns0vTeO6RaS5Fv1SOh\
|
||||||
|
Yc7WXoPhink1SE4VQe47bvWskJ3QJZC7AsEe8dZjoifFCNwK1VYBhvzQXs3ZYcVsjtArjXJOd\
|
||||||
|
TJiVKHhz2fcoMjtGIa2UtNRt/YVhfBvwa1LQJWko8wV5YNUuRxx+YNcTEs+rjXfpY1l+9laNs\
|
||||||
|
vTCYrPODXud9wFKR8R7zAA1+thSyUvLgdwTylgBp38G74tNBxk70Fh8E9C09D809Clipj7dib\
|
||||||
|
vpz1ANsgnqx9yv0=").unwrap()
|
||||||
|
).unwrap();
|
||||||
|
println!("Shared secret: {}", hex::encode(&shared_secret));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_key_material(prefix: &str, key_material: &KeyMaterial) {
|
||||||
|
println!("\n{}", prefix);
|
||||||
|
println!(
|
||||||
|
"\nPublic key:\n{}",
|
||||||
|
STANDARD.encode(&key_material.public_key_der)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"\nPrivate key representation:\n{}",
|
||||||
|
STANDARD.encode(&key_material.private_key_representation)
|
||||||
|
);
|
||||||
|
}
|
||||||
64
src/lib.rs
64
src/lib.rs
@@ -14,6 +14,12 @@ pub enum KeyPurpose {
|
|||||||
KeyAgreement,
|
KeyAgreement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum KeyMlKem {
|
||||||
|
MlKem768,
|
||||||
|
MlKem1024,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum ControlFlag {
|
pub enum ControlFlag {
|
||||||
None,
|
None,
|
||||||
@@ -100,7 +106,7 @@ struct IsSupportSecureEnclaveResult {
|
|||||||
struct KeyPairResult {
|
struct KeyPairResult {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub success: bool,
|
pub success: bool,
|
||||||
pub public_key_point_base64: String,
|
pub public_key_point_base64: Option<String>,
|
||||||
pub public_key_base64: String,
|
pub public_key_base64: String,
|
||||||
pub data_representation_base64: String,
|
pub data_representation_base64: String,
|
||||||
}
|
}
|
||||||
@@ -164,6 +170,22 @@ pub fn generate_keypair(
|
|||||||
parse_keypair_result(&cmd_stdout)
|
parse_keypair_result(&cmd_stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_mlkem_keypair(
|
||||||
|
key_ml_kem: KeyMlKem,
|
||||||
|
control_flag: ControlFlag,
|
||||||
|
) -> XResult<KeyMaterial> {
|
||||||
|
let mut cmd = Command::new(get_swift_secure_enclave_tool_cmd());
|
||||||
|
cmd.arg(match key_ml_kem {
|
||||||
|
KeyMlKem::MlKem768 => "generate_mlkem768_ecdh_keypair",
|
||||||
|
KeyMlKem::MlKem1024 => "generate_mlkem1024_ecdh_keypair",
|
||||||
|
});
|
||||||
|
cmd.arg("--control-flag");
|
||||||
|
cmd.arg(control_flag.to_str());
|
||||||
|
|
||||||
|
let cmd_stdout = run_command_stdout(cmd)?;
|
||||||
|
parse_keypair_result(&cmd_stdout)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn recover_keypair(
|
pub fn recover_keypair(
|
||||||
key_purpose: KeyPurpose,
|
key_purpose: KeyPurpose,
|
||||||
private_key_representation: &[u8],
|
private_key_representation: &[u8],
|
||||||
@@ -180,6 +202,22 @@ pub fn recover_keypair(
|
|||||||
parse_keypair_result(&cmd_stdout)
|
parse_keypair_result(&cmd_stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn recover_mlkem_keypair(
|
||||||
|
key_ml_kem: KeyMlKem,
|
||||||
|
private_key_representation: &[u8],
|
||||||
|
) -> XResult<KeyMaterial> {
|
||||||
|
let mut cmd = Command::new(get_swift_secure_enclave_tool_cmd());
|
||||||
|
cmd.arg(match key_ml_kem {
|
||||||
|
KeyMlKem::MlKem768 => "recover_mlkem768_public_key",
|
||||||
|
KeyMlKem::MlKem1024 => "recover_mlkem1024_public_key",
|
||||||
|
});
|
||||||
|
cmd.arg("--private-key");
|
||||||
|
cmd.arg(STANDARD.encode(private_key_representation));
|
||||||
|
|
||||||
|
let cmd_stdout = run_command_stdout(cmd)?;
|
||||||
|
parse_keypair_result(&cmd_stdout)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn private_key_sign(private_key_representation: &[u8], content: &[u8]) -> XResult<Vec<u8>> {
|
pub fn private_key_sign(private_key_representation: &[u8], content: &[u8]) -> XResult<Vec<u8>> {
|
||||||
private_key_sign_digested(private_key_representation, content, DigestType::Raw)
|
private_key_sign_digested(private_key_representation, content, DigestType::Raw)
|
||||||
}
|
}
|
||||||
@@ -220,6 +258,25 @@ pub fn private_key_ecdh(
|
|||||||
parse_ecdh_result(&cmd_stdout)
|
parse_ecdh_result(&cmd_stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn private_key_mlkem_ecdh(
|
||||||
|
key_ml_kem: KeyMlKem,
|
||||||
|
private_key_representation: &[u8],
|
||||||
|
ephemera_public_key: &[u8],
|
||||||
|
) -> XResult<Vec<u8>> {
|
||||||
|
let mut cmd = Command::new(get_swift_secure_enclave_tool_cmd());
|
||||||
|
cmd.arg(match key_ml_kem {
|
||||||
|
KeyMlKem::MlKem768 => "compute_mlkem768_ecdh",
|
||||||
|
KeyMlKem::MlKem1024 => "compute_mlkem1024_ecdh",
|
||||||
|
});
|
||||||
|
cmd.arg("--private-key");
|
||||||
|
cmd.arg(STANDARD.encode(private_key_representation));
|
||||||
|
cmd.arg("--ephemera-public-key");
|
||||||
|
cmd.arg(STANDARD.encode(ephemera_public_key));
|
||||||
|
|
||||||
|
let cmd_stdout = run_command_stdout(cmd)?;
|
||||||
|
parse_ecdh_result(&cmd_stdout)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn external_sign(
|
pub fn external_sign(
|
||||||
external_command: &str,
|
external_command: &str,
|
||||||
parameter: &str,
|
parameter: &str,
|
||||||
@@ -317,7 +374,10 @@ fn run_command(mut cmd: Command) -> XResult<Output> {
|
|||||||
fn parse_keypair_result(cmd_stdout: &str) -> XResult<KeyMaterial> {
|
fn parse_keypair_result(cmd_stdout: &str) -> XResult<KeyMaterial> {
|
||||||
if is_success(&cmd_stdout)? {
|
if is_success(&cmd_stdout)? {
|
||||||
let key_pair_result: KeyPairResult = from_str(&cmd_stdout)?;
|
let key_pair_result: KeyPairResult = from_str(&cmd_stdout)?;
|
||||||
let public_key_point = STANDARD.decode(&key_pair_result.public_key_point_base64)?;
|
let public_key_point = match &key_pair_result.public_key_point_base64 {
|
||||||
|
Some(public_key_point_base64) => STANDARD.decode(public_key_point_base64)?,
|
||||||
|
None => vec![],
|
||||||
|
};
|
||||||
let public_key_der = STANDARD.decode(&key_pair_result.public_key_base64)?;
|
let public_key_der = STANDARD.decode(&key_pair_result.public_key_base64)?;
|
||||||
let private_key_representation =
|
let private_key_representation =
|
||||||
STANDARD.decode(&key_pair_result.data_representation_base64)?;
|
STANDARD.decode(&key_pair_result.data_representation_base64)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user