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