bssl_crypto/cipher/
mod.rs1extern crate alloc;
16
17use crate::{CSlice, CSliceMut};
18use alloc::{vec, vec::Vec};
19use bssl_sys::EVP_CIPHER;
20use core::marker::PhantomData;
21
22pub mod aes_ctr;
24
25pub mod aes_cbc;
27
28#[derive(Debug)]
30pub struct CipherError;
31
32pub trait StreamCipher {
34 type Key: AsRef<[u8]>;
36
37 type Nonce: AsRef<[u8]>;
40
41 fn new(key: &Self::Key, iv: &Self::Nonce) -> Self;
43
44 fn apply_keystream(&mut self, buffer: &mut [u8]) -> Result<(), CipherError>;
47}
48
49pub trait BlockCipher {
51 type Key: AsRef<[u8]>;
53
54 type Nonce: AsRef<[u8]>;
57
58 fn new_encrypt(key: &Self::Key, iv: &Self::Nonce) -> Self;
60
61 fn new_decrypt(key: &Self::Key, iv: &Self::Nonce) -> Self;
63
64 fn encrypt_padded(self, buffer: &[u8]) -> Result<Vec<u8>, CipherError>;
67
68 fn decrypt_padded(self, buffer: &[u8]) -> Result<Vec<u8>, CipherError>;
71}
72
73trait EvpCipherType {
77 type Key: AsRef<[u8]>;
78 type Nonce: AsRef<[u8]>;
79 fn evp_cipher() -> *const EVP_CIPHER;
80}
81
82struct EvpAes128Ctr;
83impl EvpCipherType for EvpAes128Ctr {
84 type Key = [u8; 16];
85 type Nonce = [u8; 16];
86 fn evp_cipher() -> *const EVP_CIPHER {
87 unsafe { bssl_sys::EVP_aes_128_ctr() }
90 }
91}
92
93struct EvpAes256Ctr;
94impl EvpCipherType for EvpAes256Ctr {
95 type Key = [u8; 32];
96 type Nonce = [u8; 16];
97 fn evp_cipher() -> *const EVP_CIPHER {
98 unsafe { bssl_sys::EVP_aes_256_ctr() }
101 }
102}
103
104struct EvpAes128Cbc;
105impl EvpCipherType for EvpAes128Cbc {
106 type Key = [u8; 16];
107 type Nonce = [u8; 16];
108 fn evp_cipher() -> *const EVP_CIPHER {
109 unsafe { bssl_sys::EVP_aes_128_cbc() }
112 }
113}
114
115struct EvpAes256Cbc;
116impl EvpCipherType for EvpAes256Cbc {
117 type Key = [u8; 32];
118 type Nonce = [u8; 16];
119 fn evp_cipher() -> *const EVP_CIPHER {
120 unsafe { bssl_sys::EVP_aes_256_cbc() }
123 }
124}
125
126enum CipherInitPurpose {
127 Encrypt,
128 Decrypt,
129}
130
131struct Cipher<C: EvpCipherType> {
133 ctx: *mut bssl_sys::EVP_CIPHER_CTX,
134 _marker: PhantomData<C>,
135}
136
137impl<C: EvpCipherType> Cipher<C> {
138 fn new(key: &C::Key, iv: &C::Nonce, purpose: CipherInitPurpose) -> Self {
139 let ctx = unsafe { bssl_sys::EVP_CIPHER_CTX_new() };
142 assert!(!ctx.is_null());
143
144 let key_cslice = CSlice::from(key.as_ref());
145 let iv_cslice = CSlice::from(iv.as_ref());
146
147 let result = match purpose {
151 CipherInitPurpose::Encrypt => unsafe {
152 bssl_sys::EVP_EncryptInit_ex(
153 ctx,
154 C::evp_cipher(),
155 core::ptr::null_mut(),
156 key_cslice.as_ptr(),
157 iv_cslice.as_ptr(),
158 )
159 },
160 CipherInitPurpose::Decrypt => unsafe {
161 bssl_sys::EVP_DecryptInit_ex(
162 ctx,
163 C::evp_cipher(),
164 core::ptr::null_mut(),
165 key_cslice.as_ptr(),
166 iv_cslice.as_ptr(),
167 )
168 },
169 };
170 assert_eq!(result, 1);
171
172 Self {
173 ctx,
174 _marker: Default::default(),
175 }
176 }
177
178 fn cipher_mode(&self) -> u32 {
179 unsafe { bssl_sys::EVP_CIPHER_CTX_mode(self.ctx) }
182 }
183
184 fn apply_keystream_in_place(&mut self, buffer: &mut [u8]) -> Result<(), CipherError> {
185 assert_eq!(
188 self.cipher_mode(),
189 bssl_sys::EVP_CIPH_CTR_MODE as u32,
190 "Cannot use apply_keystream_in_place for non-CTR modes"
191 );
192 let mut cslice_buf_mut = CSliceMut::from(buffer);
193 let mut out_len = 0;
194
195 let result = unsafe {
197 bssl_sys::EVP_EncryptUpdate_ex(
198 self.ctx,
199 cslice_buf_mut.as_mut_ptr(),
200 &mut out_len,
201 cslice_buf_mut.len(),
202 cslice_buf_mut.as_mut_ptr(),
203 cslice_buf_mut.len(),
204 )
205 };
206 if result == 1 {
207 assert_eq!(out_len, cslice_buf_mut.len());
208 Ok(())
209 } else {
210 Err(CipherError)
211 }
212 }
213
214 #[allow(clippy::expect_used)]
215 fn encrypt(self, buffer: &[u8]) -> Result<Vec<u8>, CipherError> {
216 let block_size_u32 = unsafe { bssl_sys::EVP_CIPHER_CTX_block_size(self.ctx) };
218 let block_size: usize = block_size_u32
219 .try_into()
220 .expect("Block size should always fit in usize");
221 let max_encrypt_total_output_size = buffer.len() + block_size;
222 let mut output_vec = vec![0_u8; max_encrypt_total_output_size];
223 let update_out_len = {
225 let mut cslice_out_buf_mut = CSliceMut::from(&mut output_vec[..]);
226 let mut update_out_len = 0;
227
228 let cslice_in_buf = CSlice::from(buffer);
229
230 let update_result = unsafe {
232 bssl_sys::EVP_EncryptUpdate_ex(
233 self.ctx,
234 cslice_out_buf_mut.as_mut_ptr(),
235 &mut update_out_len,
236 cslice_out_buf_mut.len(),
237 cslice_in_buf.as_ptr(),
238 cslice_in_buf.len(),
239 )
240 };
241 if update_result != 1 {
242 return Err(CipherError);
243 }
244 update_out_len
245 };
246
247 {
249 #[allow(clippy::indexing_slicing)]
252 let mut cslice_finalize_buf_mut = CSliceMut::from(&mut output_vec[update_out_len..]);
253 let mut final_out_len = 0;
254 let final_result = unsafe {
256 bssl_sys::EVP_EncryptFinal_ex2(
257 self.ctx,
258 cslice_finalize_buf_mut.as_mut_ptr(),
259 &mut final_out_len,
260 cslice_finalize_buf_mut.len(),
261 )
262 };
263 if final_result == 1 {
264 output_vec.truncate(update_out_len + final_out_len)
265 } else {
266 return Err(CipherError);
267 }
268 }
269 Ok(output_vec)
270 }
271
272 #[allow(clippy::expect_used)]
273 fn decrypt(self, in_buffer: &[u8]) -> Result<Vec<u8>, CipherError> {
274 let mut output_vec = vec![0_u8; in_buffer.len()];
276
277 let update_out_len = {
279 let mut cslice_out_buf_mut = CSliceMut::from(&mut output_vec[..]);
280 let mut update_out_len = 0;
281
282 let cslice_in_buf = CSlice::from(in_buffer);
283
284 let update_result = unsafe {
286 bssl_sys::EVP_DecryptUpdate_ex(
287 self.ctx,
288 cslice_out_buf_mut.as_mut_ptr(),
289 &mut update_out_len,
290 cslice_out_buf_mut.len(),
291 cslice_in_buf.as_ptr(),
292 cslice_in_buf.len(),
293 )
294 };
295 if update_result != 1 {
296 return Err(CipherError);
297 }
298 update_out_len
299 };
300
301 {
303 #[allow(clippy::indexing_slicing)]
306 let mut cslice_final_buf_mut = CSliceMut::from(&mut output_vec[update_out_len..]);
307 let mut final_out_len = 0;
308 let final_result = unsafe {
310 bssl_sys::EVP_DecryptFinal_ex2(
311 self.ctx,
312 cslice_final_buf_mut.as_mut_ptr(),
313 &mut final_out_len,
314 cslice_final_buf_mut.len(),
315 )
316 };
317
318 if final_result == 1 {
319 output_vec.truncate(update_out_len + final_out_len)
320 } else {
321 return Err(CipherError);
322 }
323 }
324 Ok(output_vec)
325 }
326}
327
328impl<C: EvpCipherType> Drop for Cipher<C> {
329 fn drop(&mut self) {
330 unsafe { bssl_sys::EVP_CIPHER_CTX_free(self.ctx) }
333 }
334}
335
336#[cfg(test)]
337mod test {
338 use crate::cipher::{CipherInitPurpose, EvpAes128Cbc, EvpAes128Ctr};
339
340 use super::Cipher;
341
342 #[test]
343 fn test_cipher_mode() {
344 assert_eq!(
345 Cipher::<EvpAes128Ctr>::new(&[0; 16], &[0; 16], CipherInitPurpose::Encrypt)
346 .cipher_mode(),
347 bssl_sys::EVP_CIPH_CTR_MODE as u32
348 );
349
350 assert_eq!(
351 Cipher::<EvpAes128Cbc>::new(&[0; 16], &[0; 16], CipherInitPurpose::Encrypt)
352 .cipher_mode(),
353 bssl_sys::EVP_CIPH_CBC_MODE as u32
354 );
355 }
356
357 #[should_panic]
358 #[test]
359 fn test_apply_keystream_on_cbc() {
360 let mut cipher =
361 Cipher::<EvpAes128Cbc>::new(&[0; 16], &[0; 16], CipherInitPurpose::Encrypt);
362 let mut buf = [0; 16];
363 let _ = cipher.apply_keystream_in_place(&mut buf); }
365}