1use std::{ffi::c_void, fmt::Display};
8
9#[repr(C)]
10#[derive(Copy, Clone)]
11enum Operation {
12 Encrypt = 0,
13 Decrypt = 1,
14}
15
16#[repr(u32)]
17#[non_exhaustive]
18#[derive(Copy, Clone, Debug, PartialEq)]
19pub enum Mode {
20 ECB = 1,
21 CBC = 2,
22 CFB = 3,
23 CTR = 4,
24 OFB = 7,
27 XTS = 8,
28 CFB8 = 10,
31}
32
33#[repr(u32)]
34#[derive(Copy, Clone, Debug, PartialEq)]
35#[non_exhaustive]
36pub enum Padding {
37 None = 0,
38 PKCS7 = 1,
39}
40
41type CCCryptorRef = *mut c_void;
42
43extern "C" {
44 fn CCCryptorCreateWithMode(
45 operation: Operation,
46 mode: u32,
47 config: u32,
48 padding: Padding,
49 iv: *const c_void,
50 key: *const c_void,
51 key_length: usize,
52 tweak: *const c_void,
53 tweak_length: usize,
54 rounds: usize,
55 options: u32,
56 handle: *mut CCCryptorRef,
57 ) -> Status;
58
59 fn CCCryptorRelease(handle: CCCryptorRef) -> Status;
60
61 fn CCCryptorUpdate(
62 handle: CCCryptorRef,
63 input: *const c_void,
64 input_len: usize,
65 output: *mut c_void,
66 output_len: usize,
67 written: *mut usize,
68 ) -> Status;
69
70 fn CCCryptorFinal(
71 handle: CCCryptorRef,
72 output: *mut c_void,
73 output_len: usize,
74 written: *mut usize,
75 ) -> Status;
76
77 fn CCCryptorGetOutputLength(handle: CCCryptorRef, input_len: usize, finishing: bool) -> usize;
78}
79
80#[derive(Debug, PartialEq)]
81#[non_exhaustive]
82pub enum CryptorError {
83 Param,
84 Memory,
85 Alignment,
86 Decode,
87 Unimplemented,
88 RNGFailure,
89 Unspecified,
90 CallSequence,
91 KeySize,
92 Key,
93 InitializationVectorPresent,
94 Unexpected(i32),
95}
96
97impl std::error::Error for CryptorError {}
98
99impl Display for CryptorError {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 let s = match self {
102 Self::Param => "illegal parameter value",
103 Self::Memory => "memory allocation failed",
104 Self::Alignment => "input size was nit aligned properly",
105 Self::Decode => "input data did not encode or decrypt properly",
106 Self::Unimplemented => "function not implemented for the current algorithm",
107 Self::RNGFailure => "random number generated failed",
108 Self::Unspecified => "an unspecified failure occurred",
109 Self::CallSequence => "call sequence failure",
110 Self::KeySize => "key size is invalid",
111 Self::Key => "key is invalid",
112 Self::InitializationVectorPresent => "ECB mode does not support initialization vectors",
113 Self::Unexpected(code) => {
114 let s = format!("unexpected error {}", code);
115 return f.write_str(&s);
116 }
117 };
118
119 f.write_str(s)
120 }
121}
122
123#[allow(dead_code)]
124#[derive(Copy, Clone, Debug, PartialEq)]
125#[repr(i32)]
126enum Status {
127 Success = 0,
128 ParamError = -4300,
129 BufferTooSmall = -4301,
130 MemoryFailure = -4302,
131 AlignmentError = -4303,
132 DecodeError = -4304,
133 Unimplemented = -4305,
134 Overflow = -4306,
135 RNGFailure = -4307,
136 UnspecifiedError = -4308,
137 CallSequenceError = -4309,
138 KeySizeError = -4310,
139 InvalidKey = -4311,
140}
141
142impl Into<CryptorError> for Status {
143 fn into(self) -> CryptorError {
144 match self {
145 Status::Success => unreachable!(),
146 Status::ParamError => CryptorError::Param,
147 Status::MemoryFailure => CryptorError::Memory,
148 Status::AlignmentError => CryptorError::Alignment,
149 Status::DecodeError => CryptorError::Decode,
150 Status::Unimplemented => CryptorError::Unimplemented,
151 Status::RNGFailure => CryptorError::RNGFailure,
152 Status::UnspecifiedError => CryptorError::Unspecified,
153 Status::CallSequenceError => CryptorError::CallSequence,
154 Status::KeySizeError => CryptorError::KeySize,
155 Status::InvalidKey => CryptorError::Key,
156 _ => CryptorError::Unexpected(self as i32),
157 }
158 }
159}
160
161#[non_exhaustive]
162#[derive(Clone, Copy, Debug, PartialEq)]
163pub enum Config<'a> {
175 AES128 {
176 mode: Mode,
177 iv: Option<&'a [u8; 16]>,
178 key: &'a [u8; 16],
179 },
180 AES192 {
181 mode: Mode,
182 iv: Option<&'a [u8; 16]>,
183 key: &'a [u8; 24],
184 },
185 AES256 {
186 mode: Mode,
187 iv: Option<&'a [u8; 16]>,
188 key: &'a [u8; 32],
189 },
190 DES {
191 mode: Mode,
192 iv: Option<&'a [u8; 8]>,
193 key: &'a [u8; 8],
194 },
195 TDES {
196 mode: Mode,
197 iv: Option<&'a [u8; 8]>,
198 key: &'a [u8; 24],
199 },
200 CAST {
201 mode: Mode,
202 iv: Option<&'a [u8; 8]>,
203 key: &'a [u8],
205 padding: Padding,
206 },
207 RC4 {
208 key: &'a [u8],
210 },
211 RC2 {
212 mode: Mode,
213 iv: Option<&'a [u8; 8]>,
214 key: &'a [u8],
216 },
217 Blowfish {
218 mode: Mode,
219 iv: Option<&'a [u8; 8]>,
220 key: &'a [u8],
222 },
223}
224
225impl<'a> From<&Config<'a>> for u32 {
226 fn from(config: &Config) -> Self {
227 match config {
228 Config::AES128 { .. } => 0,
229 Config::AES192 { .. } => 0,
230 Config::AES256 { .. } => 0,
231 Config::DES { .. } => 1,
232 Config::TDES { .. } => 2,
233 Config::CAST { .. } => 3,
234 Config::RC4 { .. } => 4,
235 Config::RC2 { .. } => 5,
236 Config::Blowfish { .. } => 6,
237 }
238 }
239}
240
241impl<'a> Config<'a> {
242 fn padding(&self) -> Padding {
243 match self {
244 Config::CAST { padding, .. } => *padding,
245 _ => Padding::None,
246 }
247 }
248
249 fn rounds(&self) -> usize {
250 0
251 }
252
253 const fn mode(&self) -> u32 {
254 match self {
255 Config::AES128 { mode, .. } => *mode as u32,
256 Config::AES192 { mode, .. } => *mode as u32,
257 Config::AES256 { mode, .. } => *mode as u32,
258 Config::DES { mode, .. } => *mode as u32,
259 Config::TDES { mode, .. } => *mode as u32,
260 Config::CAST { mode, .. } => *mode as u32,
261 Config::RC4 { .. } => 9,
262 Config::RC2 { mode, .. } => *mode as u32,
263 Config::Blowfish { mode, .. } => *mode as u32,
264 }
265 }
266
267 fn iv_ptr(&self) -> Result<*const u8, CryptorError> {
268 let (mode, ptr) = match self {
269 Config::AES128 { mode, iv, .. } if iv.is_some() => (mode, iv.unwrap().as_ptr()),
270 Config::AES192 { mode, iv, .. } if iv.is_some() => (mode, iv.unwrap().as_ptr()),
271 Config::AES256 { mode, iv, .. } if iv.is_some() => (mode, iv.unwrap().as_ptr()),
272 Config::DES { mode, iv, .. } if iv.is_some() => (mode, iv.unwrap().as_ptr()),
273 Config::CAST { mode, iv, .. } if iv.is_some() => (mode, iv.unwrap().as_ptr()),
274 Config::RC2 { mode, iv, .. } if iv.is_some() => (mode, iv.unwrap().as_ptr()),
275 Config::Blowfish { mode, iv, .. } if iv.is_some() => (mode, iv.unwrap().as_ptr()),
276 _ => return Ok(std::ptr::null()),
277 };
278
279 if mode == &Mode::ECB {
280 Err(CryptorError::InitializationVectorPresent)
281 } else {
282 Ok(ptr)
283 }
284 }
285
286 fn key(&self) -> &[u8] {
287 match self {
288 Config::AES128 { key, .. } => *key,
289 Config::AES192 { key, .. } => *key,
290 Config::AES256 { key, .. } => *key,
291 Config::DES { key, .. } => *key,
292 Config::TDES { key, .. } => *key,
293 Config::CAST { key, .. } => *key,
294 Config::RC4 { key, .. } => *key,
295 Config::RC2 { key, .. } => *key,
296 Config::Blowfish { key, .. } => *key,
297 }
298 }
299}
300
301#[derive(Debug)]
314pub struct Cryptor {
315 handle: CCCryptorRef,
316}
317
318impl<'a> Drop for Cryptor {
319 fn drop(&mut self) {
320 unsafe {
321 CCCryptorRelease(self.handle);
322 }
323 }
324}
325
326impl Cryptor {
327 fn new<'a>(config: &Config<'a>, operation: Operation) -> Result<Cryptor, CryptorError> {
328 let mut handle: CCCryptorRef = std::ptr::null_mut();
329
330 let status = unsafe {
331 CCCryptorCreateWithMode(
332 operation,
333 config.mode(),
334 config.into(),
335 config.padding(),
336 config.iv_ptr()? as *const c_void,
337 config.key().as_ptr() as *const c_void,
338 config.key().len(),
339 std::ptr::null(),
341 0,
342 config.rounds(),
343 0,
344 &mut handle as *mut *mut c_void,
345 )
346 };
347
348 if status != Status::Success {
349 return Err(status.into());
350 }
351
352 Ok(Cryptor { handle })
353 }
354
355 pub fn new_encryptor<'a>(config: &Config<'a>) -> Result<Self, CryptorError> {
356 Self::new(config, Operation::Encrypt)
357 }
358
359 pub fn new_decryptor<'a>(config: &Config<'a>) -> Result<Self, CryptorError> {
360 Self::new(config, Operation::Decrypt)
361 }
362
363 pub fn update(
366 &self,
367 input: impl AsRef<[u8]>,
368 output: &mut Vec<u8>,
369 ) -> Result<(), CryptorError> {
370 let input = input.as_ref();
371 let mut written = 0usize;
372
373 output.resize(
374 unsafe { CCCryptorGetOutputLength(self.handle, input.len(), false) },
375 0,
376 );
377
378 let status = unsafe {
379 CCCryptorUpdate(
380 self.handle,
381 input.as_ptr() as *const c_void,
382 input.len(),
383 output.as_mut_ptr() as *mut c_void,
384 output.capacity(),
385 &mut written as *mut usize,
386 )
387 };
388
389 if status != Status::Success {
390 output.clear();
391 return Err(status.into());
392 }
393
394 output.resize(written, 0);
395
396 Ok(())
397 }
398
399 pub fn finish(self, output: &mut Vec<u8>) -> Result<(), CryptorError> {
402 let mut written = 0usize;
403
404 let status = unsafe {
405 CCCryptorFinal(
406 self.handle,
407 output.as_mut_ptr() as *mut c_void,
408 output.capacity(),
409 &mut written as *mut usize,
410 )
411 };
412
413 if status != Status::Success {
414 output.clear();
415 return Err(status.into());
416 }
417
418 output.resize(written, 0);
419
420 Ok(())
421 }
422}
423
424impl Cryptor {
425 pub fn encrypt<'a>(
426 config: &Config<'a>,
427 input: impl AsRef<[u8]>,
428 ) -> Result<Vec<u8>, CryptorError> {
429 let mut output = Vec::new();
430 Cryptor::new_encryptor(config)?.update(input, &mut output)?;
431 Ok(output)
432 }
433
434 pub fn decrypt<'a>(
435 config: &Config<'a>,
436 input: impl AsRef<[u8]>,
437 ) -> Result<Vec<u8>, CryptorError> {
438 let mut output = Vec::new();
439 Cryptor::new_decryptor(config)?.update(input, &mut output)?;
440 Ok(output)
441 }
442}