swift_secure_enclave_tool_rs/
lib.rs1use base64::engine::general_purpose::STANDARD;
2use base64::Engine;
3use rust_util::{debugging, opt_result, simple_error, XResult};
4use std::process::{Command, Output};
5
6const SWIFT_SECURE_ENCLAVE_TOOL_CMD: &str = "swift-secure-enclave-tool";
7
8#[derive(Debug, Clone, Copy)]
9pub enum KeyPurpose {
10 Signing,
11 KeyAgreement,
12}
13
14#[derive(Debug)]
15pub struct KeyMaterial {
16 pub public_key_point: Vec<u8>,
17 pub public_key_der: Vec<u8>,
18 pub private_key_representation: Vec<u8>,
19}
20
21pub fn is_secure_enclave_supported() -> XResult<bool> {
22 let mut cmd = Command::new(SWIFT_SECURE_ENCLAVE_TOOL_CMD);
23 cmd.arg("is_support_secure_enclave");
24
25 let cmd_stdout = run_command_stdout(cmd)?;
26 if cmd_stdout.starts_with("ok:") {
27 let result = cmd_stdout.chars().skip(3).collect::<String>();
28 Ok(result == "true")
29 } else {
30 simple_error!("Invalid is_secure_enclave_supported result: {}", cmd_stdout)
31 }
32}
33
34#[deprecated]
35pub fn generate_ecdsa_keypair(key_purpose: KeyPurpose, require_bio: bool) -> XResult<KeyMaterial> {
36 generate_keypair(key_purpose, require_bio)
37}
38
39pub fn generate_keypair(key_purpose: KeyPurpose, require_bio: bool) -> XResult<KeyMaterial> {
40 let mut cmd = Command::new(SWIFT_SECURE_ENCLAVE_TOOL_CMD);
41 cmd.arg(match key_purpose {
42 KeyPurpose::Signing => "generate_p256_ecsign_keypair",
43 KeyPurpose::KeyAgreement => "generate_p256_ecdh_keypair",
44 });
45 cmd.arg(format!("{}", require_bio));
46
47 let cmd_stdout = run_command_stdout(cmd)?;
48 parse_keypair_result(&cmd_stdout)
49}
50
51#[deprecated]
52pub fn recover_ecdsa_keypair(
53 key_purpose: KeyPurpose,
54 private_key_representation: &[u8],
55) -> XResult<KeyMaterial> {
56 recover_keypair(key_purpose, private_key_representation)
57}
58
59pub fn recover_keypair(
60 key_purpose: KeyPurpose,
61 private_key_representation: &[u8],
62) -> XResult<KeyMaterial> {
63 let mut cmd = Command::new(SWIFT_SECURE_ENCLAVE_TOOL_CMD);
64 cmd.arg(match key_purpose {
65 KeyPurpose::Signing => "recover_p256_ecsign_public_key",
66 KeyPurpose::KeyAgreement => "recover_p256_ecdh_public_key",
67 });
68 cmd.arg(STANDARD.encode(private_key_representation));
69
70 let cmd_stdout = run_command_stdout(cmd)?;
71 parse_keypair_result(&cmd_stdout)
72}
73
74#[deprecated]
75pub fn private_key_ecdsa_sign(
76 private_key_representation: &[u8],
77 content: &[u8],
78) -> XResult<Vec<u8>> {
79 private_key_sign(private_key_representation, content)
80}
81
82pub fn private_key_sign(private_key_representation: &[u8], content: &[u8]) -> XResult<Vec<u8>> {
83 let mut cmd = Command::new(SWIFT_SECURE_ENCLAVE_TOOL_CMD);
84 cmd.arg("compute_p256_ecsign");
85 cmd.arg(STANDARD.encode(private_key_representation));
86 cmd.arg(STANDARD.encode(content));
87
88 let cmd_stdout = run_command_stdout(cmd)?;
89 if cmd_stdout.starts_with("ok:") {
90 let result = cmd_stdout.chars().skip(3).collect::<String>();
91 Ok(STANDARD.decode(result)?)
92 } else {
93 simple_error!("Invalid private_key_ecdsa_sign result: {}", cmd_stdout)
94 }
95}
96
97pub fn private_key_ecdh(
99 private_key_representation: &[u8],
100 ephemera_public_key: &[u8],
101) -> XResult<Vec<u8>> {
102 let mut cmd = Command::new(SWIFT_SECURE_ENCLAVE_TOOL_CMD);
103 cmd.arg("compute_p256_ecdh");
104 cmd.arg(STANDARD.encode(private_key_representation));
105 cmd.arg(STANDARD.encode(ephemera_public_key));
106
107 let cmd_stdout = run_command_stdout(cmd)?;
108 if cmd_stdout.starts_with("ok:SharedSecret:") {
109 let result = cmd_stdout.chars().skip(16).collect::<String>();
110 Ok(hex::decode(result.trim())?)
111 } else {
112 simple_error!("Invalid compute_p256_ecdh result: {}", cmd_stdout)
113 }
114}
115
116fn run_command_stdout(cmd: Command) -> XResult<String> {
117 let output = run_command(cmd)?;
118 let stdout_text = opt_result!(String::from_utf8(output.stdout), "Parse stdout failed:{}");
119 Ok(stdout_text.trim().to_string())
120}
121
122fn run_command(mut cmd: Command) -> XResult<Output> {
123 debugging!("Run command: {:?}", cmd);
124 let output = cmd.output();
125 match output {
126 Err(e) => simple_error!("Run command failed: {:?}", e),
127 Ok(output) => {
128 debugging!("Output: {:?}", output);
129 if !output.status.success() {
130 simple_error!("Run command not success: {:?}", output.status.code())
131 } else {
132 Ok(output)
133 }
134 }
135 }
136}
137
138fn parse_keypair_result(cmd_stdout: &str) -> XResult<KeyMaterial> {
139 if cmd_stdout.starts_with("ok:") {
140 let result = cmd_stdout.chars().skip(3).collect::<String>();
141 let parts = result.split(",").collect::<Vec<_>>();
142 let public_key_point = STANDARD.decode(parts[0])?;
143 let public_key_der = STANDARD.decode(parts[1])?;
144 let private_key_representation = STANDARD.decode(parts[2])?;
145 Ok(KeyMaterial {
146 public_key_point,
147 public_key_der,
148 private_key_representation,
149 })
150 } else {
151 simple_error!("Invalid result: {}", cmd_stdout)
152 }
153}