apple_security/os/macos/
encrypt_transform.rs1use core_foundation::base::TCFType;
4use core_foundation::data::CFData;
5use core_foundation::error::CFError;
6use core_foundation::string::CFString;
7use core_foundation_sys::data::CFDataRef;
8use core_foundation_sys::string::CFStringRef;
9use apple_security_sys::encrypt_transform::*;
10use apple_security_sys::transform::*;
11use std::ptr;
12
13use crate::key::SecKey;
14use crate::os::macos::transform::SecTransform;
15
16#[derive(Debug, Copy, Clone)]
17pub struct Padding(CFStringRef);
19
20impl Padding {
21 #[inline(always)]
23 #[must_use]
24 pub fn none() -> Self {
25 unsafe { Self(kSecPaddingNoneKey) }
26 }
27
28 #[inline(always)]
30 #[must_use]
31 pub fn pkcs1() -> Self {
32 unsafe { Self(kSecPaddingPKCS1Key) }
33 }
34
35 #[inline(always)]
37 #[must_use]
38 pub fn pkcs5() -> Self {
39 unsafe { Self(kSecPaddingPKCS5Key) }
40 }
41
42 #[inline(always)]
44 #[must_use]
45 pub fn pkcs7() -> Self {
46 unsafe { Self(kSecPaddingPKCS7Key) }
47 }
48
49 #[inline(always)]
51 #[must_use]
52 pub fn oaep() -> Self {
53 unsafe { Self(kSecPaddingOAEPKey) }
54 }
55
56 #[inline]
57 fn to_str(self) -> CFString {
58 unsafe { CFString::wrap_under_get_rule(self.0) }
59 }
60}
61
62#[derive(Debug, Copy, Clone)]
66pub struct Mode(CFStringRef);
67
68#[allow(missing_docs)]
69impl Mode {
70 #[inline(always)]
71 #[must_use]
72 pub fn none() -> Self {
73 unsafe { Self(kSecModeNoneKey) }
74 }
75
76 #[inline(always)]
77 #[must_use]
78 pub fn ecb() -> Self {
79 unsafe { Self(kSecModeECBKey) }
80 }
81
82 #[inline(always)]
83 #[must_use]
84 pub fn cbc() -> Self {
85 unsafe { Self(kSecModeCBCKey) }
86 }
87
88 #[inline(always)]
89 #[must_use]
90 pub fn cfb() -> Self {
91 unsafe { Self(kSecModeCFBKey) }
92 }
93
94 #[inline(always)]
95 #[must_use]
96 pub fn ofb() -> Self {
97 unsafe { Self(kSecModeOFBKey) }
98 }
99
100 fn to_str(self) -> CFString {
101 unsafe { CFString::wrap_under_get_rule(self.0) }
102 }
103}
104
105#[derive(Default)]
107pub struct Builder {
108 padding: Option<Padding>,
109 mode: Option<Mode>,
110 iv: Option<CFData>,
111}
112
113impl Builder {
114 #[inline(always)]
116 #[must_use]
117 pub fn new() -> Self {
118 Self::default()
119 }
120
121 #[inline(always)]
125 pub fn padding(&mut self, padding: Padding) -> &mut Self {
126 self.padding = Some(padding);
127 self
128 }
129
130 #[inline(always)]
134 pub fn mode(&mut self, mode: Mode) -> &mut Self {
135 self.mode = Some(mode);
136 self
137 }
138
139 #[inline(always)]
143 pub fn iv(&mut self, iv: CFData) -> &mut Self {
144 self.iv = Some(iv);
145 self
146 }
147
148 pub fn encrypt(&self, key: &SecKey, data: &CFData) -> Result<CFData, CFError> {
150 unsafe {
151 let mut error = ptr::null_mut();
152 let transform = SecEncryptTransformCreate(key.as_concrete_TypeRef(), &mut error);
153 if transform.is_null() {
154 return Err(CFError::wrap_under_create_rule(error));
155 }
156 let transform = SecTransform::wrap_under_create_rule(transform);
157
158 self.finish(transform, data)
159 }
160 }
161
162 pub fn decrypt(&self, key: &SecKey, data: &CFData) -> Result<CFData, CFError> {
164 unsafe {
165 let mut error = ptr::null_mut();
166 let transform = SecDecryptTransformCreate(key.as_concrete_TypeRef(), &mut error);
167 if transform.is_null() {
168 return Err(CFError::wrap_under_create_rule(error));
169 }
170 let transform = SecTransform::wrap_under_create_rule(transform);
171
172 self.finish(transform, data)
173 }
174 }
175
176 fn finish(&self, mut transform: SecTransform, data: &CFData) -> Result<CFData, CFError> {
177 unsafe {
178 if let Some(ref padding) = self.padding {
179 let key = CFString::wrap_under_get_rule(kSecPaddingKey);
180 transform.set_attribute(&key, &padding.to_str())?;
181 }
182
183 if let Some(ref mode) = self.mode {
184 let key = CFString::wrap_under_get_rule(kSecEncryptionMode);
185 transform.set_attribute(&key, &mode.to_str())?;
186 }
187
188 if let Some(ref iv) = self.iv {
189 let key = CFString::wrap_under_get_rule(kSecIVKey);
190 transform.set_attribute(&key, iv)?;
191 }
192
193 let key = CFString::wrap_under_get_rule(kSecTransformInputAttributeName);
194 transform.set_attribute(&key, data)?;
195
196 let result = transform.execute()?;
197 Ok(CFData::wrap_under_get_rule(
198 result.as_CFTypeRef() as CFDataRef
199 ))
200 }
201 }
202}
203
204#[cfg(test)]
205mod test {
206 use core_foundation::data::CFData;
207 use hex::FromHex;
208
209 use super::*;
210 use crate::key::SecKey;
211 use crate::os::macos::item::KeyType;
212 use crate::os::macos::key::SecKeyExt;
213
214 #[test]
215 fn cbc_mmt_256() {
216 let key = "87725bd43a45608814180773f0e7ab95a3c859d83a2130e884190e44d14c6996";
218 let iv = "e49651988ebbb72eb8bb80bb9abbca34";
219 let ciphertext = "5b97a9d423f4b97413f388d9a341e727bb339f8e18a3fac2f2fb85abdc8f135deb30054a\
220 1afdc9b6ed7da16c55eba6b0d4d10c74e1d9a7cf8edfaeaa684ac0bd9f9d24ba674955c7\
221 9dc6be32aee1c260b558ff07e3a4d49d24162011ff254db8be078e8ad07e648e6bf56793\
222 76cb4321a5ef01afe6ad8816fcc7634669c8c4389295c9241e45fff39f3225f7745032da\
223 eebe99d4b19bcb215d1bfdb36eda2c24";
224 let plaintext = "bfe5c6354b7a3ff3e192e05775b9b75807de12e38a626b8bf0e12d5fff78e4f1775aa7d79\
225 2d885162e66d88930f9c3b2cdf8654f56972504803190386270f0aa43645db187af41fcea\
226 639b1f8026ccdd0c23e0de37094a8b941ecb7602998a4b2604e69fc04219585d854600e0a\
227 d6f99a53b2504043c08b1c3e214d17cde053cbdf91daa999ed5b47c37983ba3ee254bc5c7\
228 93837daaa8c85cfc12f7f54f699f";
229
230 let key = Vec::<u8>::from_hex(key).unwrap();
231 let key = CFData::from_buffer(&key);
232 let key = SecKey::from_data(KeyType::aes(), &key).unwrap();
233
234 let iv = Vec::<u8>::from_hex(iv).unwrap();
235
236 let ciphertext = Vec::<u8>::from_hex(ciphertext).unwrap();
237
238 let plaintext = Vec::<u8>::from_hex(plaintext).unwrap();
239
240 let decrypted = Builder::new()
241 .padding(Padding::none())
242 .iv(CFData::from_buffer(&iv))
243 .decrypt(&key, &CFData::from_buffer(&ciphertext))
244 .unwrap();
245
246 assert_eq!(plaintext, decrypted.bytes());
247
248 let encrypted = Builder::new()
249 .padding(Padding::none())
250 .iv(CFData::from_buffer(&iv))
251 .encrypt(&key, &CFData::from_buffer(&plaintext))
252 .unwrap();
253
254 assert_eq!(ciphertext, encrypted.bytes());
255 }
256}