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/// Managed wrapper around Apple's `LAPublicKey`.
68#[derive(Debug)]
69pub struct LAPublicKey {
70    handle: OwnedHandle,
71}
72
73impl LAPublicKey {
74    pub(crate) fn from_raw(raw: std::ptr::NonNull<core::ffi::c_void>) -> Self {
75        Self {
76            handle: OwnedHandle::new(raw, ffi::la_public_key::la_public_key_release),
77        }
78    }
79
80    /// Export the public-key bytes.
81    ///
82    /// # Errors
83    ///
84    /// Returns a mapped framework or bridge error if export fails.
85    pub fn export_bytes(&self) -> Result<Vec<u8>> {
86        bridge_bytes(|out, out_len, error_out| unsafe {
87            ffi::la_public_key::la_public_key_export_bytes(
88                self.handle.as_ptr(),
89                out,
90                out_len,
91                error_out,
92            )
93        })
94    }
95
96    /// Check whether an algorithm can encrypt with this key.
97    ///
98    /// # Errors
99    ///
100    /// Returns an error if the Swift bridge rejects the request.
101    pub fn can_encrypt_using(&self, algorithm: &SecKeyAlgorithm) -> Result<bool> {
102        let algorithm = cstring(algorithm.raw_name())?;
103        bridge_bool(|out, error_out| unsafe {
104            ffi::la_public_key::la_public_key_can_encrypt_using_algorithm(
105                self.handle.as_ptr(),
106                algorithm.as_ptr(),
107                out,
108                error_out,
109            )
110        })
111    }
112
113    /// Encrypt data with this key.
114    ///
115    /// # Errors
116    ///
117    /// Returns a mapped framework or bridge error if encryption fails.
118    pub fn encrypt(&self, data: &[u8], algorithm: &SecKeyAlgorithm) -> Result<Vec<u8>> {
119        let algorithm = cstring(algorithm.raw_name())?;
120        bridge_bytes(|out, out_len, error_out| unsafe {
121            ffi::la_public_key::la_public_key_encrypt_data(
122                self.handle.as_ptr(),
123                data.as_ptr(),
124                data.len(),
125                algorithm.as_ptr(),
126                out,
127                out_len,
128                error_out,
129            )
130        })
131    }
132
133    /// Check whether an algorithm can verify signatures with this key.
134    ///
135    /// # Errors
136    ///
137    /// Returns an error if the Swift bridge rejects the request.
138    pub fn can_verify_using(&self, algorithm: &SecKeyAlgorithm) -> Result<bool> {
139        let algorithm = cstring(algorithm.raw_name())?;
140        bridge_bool(|out, error_out| unsafe {
141            ffi::la_public_key::la_public_key_can_verify_using_algorithm(
142                self.handle.as_ptr(),
143                algorithm.as_ptr(),
144                out,
145                error_out,
146            )
147        })
148    }
149
150    /// Verify a signature with this key.
151    ///
152    /// # Errors
153    ///
154    /// Returns a mapped framework or bridge error if verification fails.
155    pub fn verify(
156        &self,
157        signed_data: &[u8],
158        signature: &[u8],
159        algorithm: &SecKeyAlgorithm,
160    ) -> Result<()> {
161        let algorithm = cstring(algorithm.raw_name())?;
162        bridge_unit(|error_out| unsafe {
163            ffi::la_public_key::la_public_key_verify_data(
164                self.handle.as_ptr(),
165                signed_data.as_ptr(),
166                signed_data.len(),
167                signature.as_ptr(),
168                signature.len(),
169                algorithm.as_ptr(),
170                error_out,
171            )
172        })
173    }
174}