security_framework/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 security_framework_sys::encrypt_transform::*;
10use security_framework_sys::transform::kSecTransformInputAttributeName;
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> {
151 unsafe {
152 let mut error = ptr::null_mut();
153 let transform = SecEncryptTransformCreate(key.as_concrete_TypeRef(), &mut error);
154 if transform.is_null() {
155 return Err(CFError::wrap_under_create_rule(error));
156 }
157 let transform = SecTransform::wrap_under_create_rule(transform);
158
159 self.finish(transform, data)
160 }
161 }
162
163 pub fn decrypt(&self, key: &SecKey, data: &CFData) -> Result<CFData, CFError> {
166 unsafe {
167 let mut error = ptr::null_mut();
168 let transform = SecDecryptTransformCreate(key.as_concrete_TypeRef(), &mut error);
169 if transform.is_null() {
170 return Err(CFError::wrap_under_create_rule(error));
171 }
172 let transform = SecTransform::wrap_under_create_rule(transform);
173
174 self.finish(transform, data)
175 }
176 }
177
178 fn finish(&self, mut transform: SecTransform, data: &CFData) -> Result<CFData, CFError> {
179 unsafe {
180 if let Some(ref padding) = self.padding {
181 let key = CFString::wrap_under_get_rule(kSecPaddingKey);
182 transform.set_attribute(&key, &padding.to_str())?;
183 }
184
185 if let Some(ref mode) = self.mode {
186 let key = CFString::wrap_under_get_rule(kSecEncryptionMode);
187 transform.set_attribute(&key, &mode.to_str())?;
188 }
189
190 if let Some(ref iv) = self.iv {
191 let key = CFString::wrap_under_get_rule(kSecIVKey);
192 transform.set_attribute(&key, iv)?;
193 }
194
195 let key = CFString::wrap_under_get_rule(kSecTransformInputAttributeName);
196 transform.set_attribute(&key, data)?;
197
198 let result = transform.execute()?;
199 Ok(CFData::wrap_under_get_rule(result.as_CFTypeRef() as CFDataRef))
200 }
201 }
202}
203
204#[cfg(test)]
205mod test {
206 use hex::FromHex;
207
208 use super::*;
209 use crate::os::macos::item::KeyType;
210 use crate::os::macos::key::SecKeyExt;
211
212 #[test]
213 fn cbc_mmt_256() {
214 let key = "87725bd43a45608814180773f0e7ab95a3c859d83a2130e884190e44d14c6996";
216 let iv = "e49651988ebbb72eb8bb80bb9abbca34";
217 let ciphertext = "5b97a9d423f4b97413f388d9a341e727bb339f8e18a3fac2f2fb85abdc8f135deb30054a\
218 1afdc9b6ed7da16c55eba6b0d4d10c74e1d9a7cf8edfaeaa684ac0bd9f9d24ba674955c7\
219 9dc6be32aee1c260b558ff07e3a4d49d24162011ff254db8be078e8ad07e648e6bf56793\
220 76cb4321a5ef01afe6ad8816fcc7634669c8c4389295c9241e45fff39f3225f7745032da\
221 eebe99d4b19bcb215d1bfdb36eda2c24";
222 let plaintext = "bfe5c6354b7a3ff3e192e05775b9b75807de12e38a626b8bf0e12d5fff78e4f1775aa7d79\
223 2d885162e66d88930f9c3b2cdf8654f56972504803190386270f0aa43645db187af41fcea\
224 639b1f8026ccdd0c23e0de37094a8b941ecb7602998a4b2604e69fc04219585d854600e0a\
225 d6f99a53b2504043c08b1c3e214d17cde053cbdf91daa999ed5b47c37983ba3ee254bc5c7\
226 93837daaa8c85cfc12f7f54f699f";
227
228 let key = Vec::<u8>::from_hex(key).unwrap();
229 let key = CFData::from_buffer(&key);
230 let key = SecKey::from_data(KeyType::aes(), &key).unwrap();
231
232 let iv = Vec::<u8>::from_hex(iv).unwrap();
233
234 let ciphertext = Vec::<u8>::from_hex(ciphertext).unwrap();
235
236 let plaintext = Vec::<u8>::from_hex(plaintext).unwrap();
237
238 let decrypted = Builder::new()
239 .padding(Padding::none())
240 .iv(CFData::from_buffer(&iv))
241 .decrypt(&key, &CFData::from_buffer(&ciphertext))
242 .unwrap();
243
244 assert_eq!(plaintext, decrypted.bytes());
245
246 let encrypted = Builder::new()
247 .padding(Padding::none())
248 .iv(CFData::from_buffer(&iv))
249 .encrypt(&key, &CFData::from_buffer(&plaintext))
250 .unwrap();
251
252 assert_eq!(ciphertext, encrypted.bytes());
253 }
254}