Skip to main content

localauthentication/
la_public_key.rs

1//! `LAPublicKey` wrappers.
2
3use crate::ffi;
4use crate::la_error::Result;
5use crate::private::{bridge_bool, bridge_bytes, bridge_unit, cstring, OwnedHandle};
6
7/// String-backed `SecKeyAlgorithm` wrapper used by the `LocalAuthentication` key APIs.
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct SecKeyAlgorithm(String);
10
11impl SecKeyAlgorithm {
12    /// Create an algorithm from the raw `SecKeyAlgorithm` name.
13    #[must_use]
14    pub fn from_raw_name(name: impl Into<String>) -> Self {
15        Self(name.into())
16    }
17
18    /// Borrow the raw `SecKeyAlgorithm` name.
19    #[must_use]
20    pub fn raw_name(&self) -> &str {
21        &self.0
22    }
23
24    /// `SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256`.
25    #[must_use]
26    pub fn ecdsa_signature_message_x962_sha256() -> Self {
27        Self::from_raw_name("algid:sign:ECDSA:message-X962:SHA256")
28    }
29
30    /// `SecKeyAlgorithm.ecdsaSignatureDigestX962SHA256`.
31    #[must_use]
32    pub fn ecdsa_signature_digest_x962_sha256() -> Self {
33        Self::from_raw_name("algid:sign:ECDSA:digest-X962:SHA256")
34    }
35
36    /// `SecKeyAlgorithm.eciesEncryptionStandardVariableIVX963SHA256AESGCM`.
37    #[must_use]
38    pub fn ecies_encryption_standard_variable_iv_x963_sha256_aes_gcm() -> Self {
39        Self::from_raw_name("algid:encrypt:ECIES:ECDH:KDFX963:SHA256:AESGCM-KDFIV")
40    }
41
42    /// `SecKeyAlgorithm.eciesEncryptionCofactorVariableIVX963SHA256AESGCM`.
43    #[must_use]
44    pub fn ecies_encryption_cofactor_variable_iv_x963_sha256_aes_gcm() -> Self {
45        Self::from_raw_name("algid:encrypt:ECIES:ECDHC:KDFX963:SHA256:AESGCM-KDFIV")
46    }
47
48    /// `SecKeyAlgorithm.ecdhKeyExchangeCofactorX963SHA256`.
49    #[must_use]
50    pub fn ecdh_key_exchange_cofactor_x963_sha256() -> Self {
51        Self::from_raw_name("algid:keyexchange:ECDHC:KDFX963:SHA256")
52    }
53}
54
55impl From<&str> for SecKeyAlgorithm {
56    fn from(value: &str) -> Self {
57        Self::from_raw_name(value)
58    }
59}
60
61impl From<String> for SecKeyAlgorithm {
62    fn from(value: String) -> Self {
63        Self::from_raw_name(value)
64    }
65}
66
67/// Typed wrapper for the `SecKeyKeyExchangeParameter*` dictionary accepted by `LAPrivateKey::exchange_keys_with_public_key`.
68#[derive(Debug, Clone, Default, PartialEq, Eq)]
69pub struct SecKeyExchangeParameters {
70    requested_size: Option<usize>,
71    shared_info: Option<Vec<u8>>,
72}
73
74impl SecKeyExchangeParameters {
75    /// Create an empty parameter dictionary.
76    #[must_use]
77    pub fn new() -> Self {
78        Self::default()
79    }
80
81    /// Create a dictionary that requests a derived key of the supplied length.
82    #[must_use]
83    pub const fn with_requested_size(requested_size: usize) -> Self {
84        Self {
85            requested_size: Some(requested_size),
86            shared_info: None,
87        }
88    }
89
90    /// Override the requested derived-key length.
91    #[must_use]
92    pub const fn requested_size(mut self, requested_size: usize) -> Self {
93        self.requested_size = Some(requested_size);
94        self
95    }
96
97    /// Attach additional shared info for algorithms that support KDF context data.
98    #[must_use]
99    pub fn with_shared_info(mut self, shared_info: impl Into<Vec<u8>>) -> Self {
100        self.shared_info = Some(shared_info.into());
101        self
102    }
103
104    /// Clear any previously configured shared info.
105    #[must_use]
106    pub fn without_shared_info(mut self) -> Self {
107        self.shared_info = None;
108        self
109    }
110
111    #[must_use]
112    pub(crate) const fn requested_size_value(&self) -> Option<usize> {
113        self.requested_size
114    }
115
116    #[must_use]
117    pub(crate) fn shared_info_value(&self) -> Option<&[u8]> {
118        self.shared_info.as_deref()
119    }
120}
121
122/// Managed wrapper around Apple's `LAPublicKey`.
123#[derive(Debug)]
124pub struct LAPublicKey {
125    handle: OwnedHandle,
126}
127
128impl LAPublicKey {
129    pub(crate) fn from_raw(raw: std::ptr::NonNull<core::ffi::c_void>) -> Self {
130        Self {
131            handle: OwnedHandle::new(raw, ffi::la_public_key::la_public_key_release),
132        }
133    }
134
135    /// Export the public-key bytes.
136    ///
137    /// # Errors
138    ///
139    /// Returns a mapped framework or bridge error if export fails.
140    pub fn export_bytes(&self) -> Result<Vec<u8>> {
141        bridge_bytes(|out, out_len, error_out| unsafe {
142            ffi::la_public_key::la_public_key_export_bytes(
143                self.handle.as_ptr(),
144                out,
145                out_len,
146                error_out,
147            )
148        })
149    }
150
151    /// Check whether an algorithm can encrypt with this key.
152    ///
153    /// # Errors
154    ///
155    /// Returns an error if the Swift bridge rejects the request.
156    pub fn can_encrypt_using(&self, algorithm: &SecKeyAlgorithm) -> Result<bool> {
157        let algorithm = cstring(algorithm.raw_name())?;
158        bridge_bool(|out, error_out| unsafe {
159            ffi::la_public_key::la_public_key_can_encrypt_using_algorithm(
160                self.handle.as_ptr(),
161                algorithm.as_ptr(),
162                out,
163                error_out,
164            )
165        })
166    }
167
168    /// Encrypt data with this key.
169    ///
170    /// # Errors
171    ///
172    /// Returns a mapped framework or bridge error if encryption fails.
173    pub fn encrypt(&self, data: &[u8], algorithm: &SecKeyAlgorithm) -> Result<Vec<u8>> {
174        let algorithm = cstring(algorithm.raw_name())?;
175        bridge_bytes(|out, out_len, error_out| unsafe {
176            ffi::la_public_key::la_public_key_encrypt_data(
177                self.handle.as_ptr(),
178                data.as_ptr(),
179                data.len(),
180                algorithm.as_ptr(),
181                out,
182                out_len,
183                error_out,
184            )
185        })
186    }
187
188    /// Check whether an algorithm can verify signatures with this key.
189    ///
190    /// # Errors
191    ///
192    /// Returns an error if the Swift bridge rejects the request.
193    pub fn can_verify_using(&self, algorithm: &SecKeyAlgorithm) -> Result<bool> {
194        let algorithm = cstring(algorithm.raw_name())?;
195        bridge_bool(|out, error_out| unsafe {
196            ffi::la_public_key::la_public_key_can_verify_using_algorithm(
197                self.handle.as_ptr(),
198                algorithm.as_ptr(),
199                out,
200                error_out,
201            )
202        })
203    }
204
205    /// Verify a signature with this key.
206    ///
207    /// # Errors
208    ///
209    /// Returns a mapped framework or bridge error if verification fails.
210    pub fn verify(
211        &self,
212        signed_data: &[u8],
213        signature: &[u8],
214        algorithm: &SecKeyAlgorithm,
215    ) -> Result<()> {
216        let algorithm = cstring(algorithm.raw_name())?;
217        bridge_unit(|error_out| unsafe {
218            ffi::la_public_key::la_public_key_verify_data(
219                self.handle.as_ptr(),
220                signed_data.as_ptr(),
221                signed_data.len(),
222                signature.as_ptr(),
223                signature.len(),
224                algorithm.as_ptr(),
225                error_out,
226            )
227        })
228    }
229}