| 1 | //! The symmetric encryption context. |
| 2 | //! |
| 3 | //! # Examples |
| 4 | //! |
| 5 | //! Encrypt data with AES128 CBC |
| 6 | //! |
| 7 | //! ``` |
| 8 | //! use openssl::cipher::Cipher; |
| 9 | //! use openssl::cipher_ctx::CipherCtx; |
| 10 | //! |
| 11 | //! let cipher = Cipher::aes_128_cbc(); |
| 12 | //! let data = b"Some Crypto Text" ; |
| 13 | //! let key = b" \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" ; |
| 14 | //! let iv = b" \x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07" ; |
| 15 | //! |
| 16 | //! let mut ctx = CipherCtx::new().unwrap(); |
| 17 | //! ctx.encrypt_init(Some(cipher), Some(key), Some(iv)).unwrap(); |
| 18 | //! |
| 19 | //! let mut ciphertext = vec![]; |
| 20 | //! ctx.cipher_update_vec(data, &mut ciphertext).unwrap(); |
| 21 | //! ctx.cipher_final_vec(&mut ciphertext).unwrap(); |
| 22 | //! |
| 23 | //! assert_eq!( |
| 24 | //! b" \xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\x87\x4D\ |
| 25 | //! \xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1" , |
| 26 | //! &ciphertext[..], |
| 27 | //! ); |
| 28 | //! ``` |
| 29 | //! |
| 30 | //! Decrypt data with AES128 CBC |
| 31 | //! |
| 32 | //! ``` |
| 33 | //! use openssl::cipher::Cipher; |
| 34 | //! use openssl::cipher_ctx::CipherCtx; |
| 35 | //! |
| 36 | //! let cipher = Cipher::aes_128_cbc(); |
| 37 | //! let data = b" \xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\ |
| 38 | //! \x87\x4D\xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1" ; |
| 39 | //! let key = b" \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" ; |
| 40 | //! let iv = b" \x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07" ; |
| 41 | //! |
| 42 | //! let mut ctx = CipherCtx::new().unwrap(); |
| 43 | //! ctx.decrypt_init(Some(cipher), Some(key), Some(iv)).unwrap(); |
| 44 | //! |
| 45 | //! let mut plaintext = vec![]; |
| 46 | //! ctx.cipher_update_vec(data, &mut plaintext).unwrap(); |
| 47 | //! ctx.cipher_final_vec(&mut plaintext).unwrap(); |
| 48 | //! |
| 49 | //! assert_eq!(b"Some Crypto Text" , &plaintext[..]); |
| 50 | //! ``` |
| 51 | #![warn (missing_docs)] |
| 52 | |
| 53 | use crate::cipher::CipherRef; |
| 54 | use crate::error::ErrorStack; |
| 55 | #[cfg (not(any(boringssl, awslc)))] |
| 56 | use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef}; |
| 57 | use crate::{cvt, cvt_p}; |
| 58 | #[cfg (ossl102)] |
| 59 | use bitflags::bitflags; |
| 60 | use cfg_if::cfg_if; |
| 61 | use foreign_types::{ForeignType, ForeignTypeRef}; |
| 62 | use libc::{c_int, c_uchar}; |
| 63 | use openssl_macros::corresponds; |
| 64 | use std::convert::{TryFrom, TryInto}; |
| 65 | use std::ptr; |
| 66 | |
| 67 | cfg_if! { |
| 68 | if #[cfg(ossl300)] { |
| 69 | use ffi::EVP_CIPHER_CTX_get0_cipher; |
| 70 | } else { |
| 71 | use ffi::EVP_CIPHER_CTX_cipher as EVP_CIPHER_CTX_get0_cipher; |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | foreign_type_and_impl_send_sync! { |
| 76 | type CType = ffi::EVP_CIPHER_CTX; |
| 77 | fn drop = ffi::EVP_CIPHER_CTX_free; |
| 78 | |
| 79 | /// A context object used to perform symmetric encryption operations. |
| 80 | pub struct CipherCtx; |
| 81 | /// A reference to a [`CipherCtx`]. |
| 82 | pub struct CipherCtxRef; |
| 83 | } |
| 84 | |
| 85 | #[cfg (ossl102)] |
| 86 | bitflags! { |
| 87 | /// Flags for `EVP_CIPHER_CTX`. |
| 88 | pub struct CipherCtxFlags : c_int { |
| 89 | /// The flag used to opt into AES key wrap ciphers. |
| 90 | const FLAG_WRAP_ALLOW = ffi::EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | impl CipherCtx { |
| 95 | /// Creates a new context. |
| 96 | #[corresponds (EVP_CIPHER_CTX_new)] |
| 97 | pub fn new() -> Result<Self, ErrorStack> { |
| 98 | ffi::init(); |
| 99 | |
| 100 | unsafe { |
| 101 | let ptr: *mut EVP_CIPHER_CTX = cvt_p(ffi::EVP_CIPHER_CTX_new())?; |
| 102 | Ok(CipherCtx::from_ptr(ptr)) |
| 103 | } |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | impl CipherCtxRef { |
| 108 | #[corresponds (EVP_CIPHER_CTX_copy)] |
| 109 | pub fn copy(&mut self, src: &CipherCtxRef) -> Result<(), ErrorStack> { |
| 110 | unsafe { |
| 111 | cvt(ffi::EVP_CIPHER_CTX_copy(self.as_ptr(), src.as_ptr()))?; |
| 112 | Ok(()) |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | /// Initializes the context for encryption. |
| 117 | /// |
| 118 | /// Normally this is called once to set all of the cipher, key, and IV. However, this process can be split up |
| 119 | /// by first setting the cipher with no key or IV and then setting the key and IV with no cipher. This can be used |
| 120 | /// to, for example, use a nonstandard IV size. |
| 121 | /// |
| 122 | /// # Panics |
| 123 | /// |
| 124 | /// Panics if the key buffer is smaller than the key size of the cipher, the IV buffer is smaller than the IV size |
| 125 | /// of the cipher, or if a key or IV is provided before a cipher. |
| 126 | #[corresponds (EVP_EncryptInit_ex)] |
| 127 | pub fn encrypt_init( |
| 128 | &mut self, |
| 129 | type_: Option<&CipherRef>, |
| 130 | key: Option<&[u8]>, |
| 131 | iv: Option<&[u8]>, |
| 132 | ) -> Result<(), ErrorStack> { |
| 133 | self.cipher_init(type_, key, iv, ffi::EVP_EncryptInit_ex) |
| 134 | } |
| 135 | |
| 136 | /// Initializes the context for decryption. |
| 137 | /// |
| 138 | /// Normally this is called once to set all of the cipher, key, and IV. However, this process can be split up |
| 139 | /// by first setting the cipher with no key or IV and then setting the key and IV with no cipher. This can be used |
| 140 | /// to, for example, use a nonstandard IV size. |
| 141 | /// |
| 142 | /// # Panics |
| 143 | /// |
| 144 | /// Panics if the key buffer is smaller than the key size of the cipher, the IV buffer is smaller than the IV size |
| 145 | /// of the cipher, or if a key or IV is provided before a cipher. |
| 146 | #[corresponds (EVP_DecryptInit_ex)] |
| 147 | pub fn decrypt_init( |
| 148 | &mut self, |
| 149 | type_: Option<&CipherRef>, |
| 150 | key: Option<&[u8]>, |
| 151 | iv: Option<&[u8]>, |
| 152 | ) -> Result<(), ErrorStack> { |
| 153 | self.cipher_init(type_, key, iv, ffi::EVP_DecryptInit_ex) |
| 154 | } |
| 155 | |
| 156 | fn cipher_init( |
| 157 | &mut self, |
| 158 | type_: Option<&CipherRef>, |
| 159 | key: Option<&[u8]>, |
| 160 | iv: Option<&[u8]>, |
| 161 | f: unsafe extern "C" fn( |
| 162 | *mut ffi::EVP_CIPHER_CTX, |
| 163 | *const ffi::EVP_CIPHER, |
| 164 | *mut ffi::ENGINE, |
| 165 | *const c_uchar, |
| 166 | *const c_uchar, |
| 167 | ) -> c_int, |
| 168 | ) -> Result<(), ErrorStack> { |
| 169 | if let Some(key) = key { |
| 170 | let key_len = type_.map_or_else(|| self.key_length(), |c| c.key_length()); |
| 171 | assert!(key_len <= key.len()); |
| 172 | } |
| 173 | |
| 174 | if let Some(iv) = iv { |
| 175 | let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length()); |
| 176 | assert!(iv_len <= iv.len()); |
| 177 | } |
| 178 | |
| 179 | unsafe { |
| 180 | cvt(f( |
| 181 | self.as_ptr(), |
| 182 | type_.map_or(ptr::null(), |p| p.as_ptr()), |
| 183 | ptr::null_mut(), |
| 184 | key.map_or(ptr::null(), |k| k.as_ptr()), |
| 185 | iv.map_or(ptr::null(), |iv| iv.as_ptr()), |
| 186 | ))?; |
| 187 | } |
| 188 | |
| 189 | Ok(()) |
| 190 | } |
| 191 | |
| 192 | /// Initializes the context to perform envelope encryption. |
| 193 | /// |
| 194 | /// Normally this is called once to set both the cipher and public keys. However, this process may be split up by |
| 195 | /// first providing the cipher with no public keys and then setting the public keys with no cipher. |
| 196 | /// |
| 197 | /// `encrypted_keys` will contain the generated symmetric key encrypted with each corresponding asymmetric private |
| 198 | /// key. The generated IV will be written to `iv`. |
| 199 | /// |
| 200 | /// # Panics |
| 201 | /// |
| 202 | /// Panics if `pub_keys` is not the same size as `encrypted_keys`, the IV buffer is smaller than the cipher's IV |
| 203 | /// size, or if an IV is provided before the cipher. |
| 204 | #[corresponds (EVP_SealInit)] |
| 205 | #[cfg (not(any(boringssl, awslc)))] |
| 206 | pub fn seal_init<T>( |
| 207 | &mut self, |
| 208 | type_: Option<&CipherRef>, |
| 209 | pub_keys: &[PKey<T>], |
| 210 | encrypted_keys: &mut [Vec<u8>], |
| 211 | iv: Option<&mut [u8]>, |
| 212 | ) -> Result<(), ErrorStack> |
| 213 | where |
| 214 | T: HasPublic, |
| 215 | { |
| 216 | assert_eq!(pub_keys.len(), encrypted_keys.len()); |
| 217 | if !pub_keys.is_empty() { |
| 218 | let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length()); |
| 219 | assert!(iv.as_ref().map_or(0, |b| b.len()) >= iv_len); |
| 220 | } |
| 221 | |
| 222 | for (pub_key, buf) in pub_keys.iter().zip(&mut *encrypted_keys) { |
| 223 | buf.resize(pub_key.size(), 0); |
| 224 | } |
| 225 | |
| 226 | let mut keys = encrypted_keys |
| 227 | .iter_mut() |
| 228 | .map(|b| b.as_mut_ptr()) |
| 229 | .collect::<Vec<_>>(); |
| 230 | let mut key_lengths = vec![0; pub_keys.len()]; |
| 231 | let pub_keys_len = i32::try_from(pub_keys.len()).unwrap(); |
| 232 | |
| 233 | unsafe { |
| 234 | cvt(ffi::EVP_SealInit( |
| 235 | self.as_ptr(), |
| 236 | type_.map_or(ptr::null(), |p| p.as_ptr()), |
| 237 | keys.as_mut_ptr(), |
| 238 | key_lengths.as_mut_ptr(), |
| 239 | iv.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
| 240 | pub_keys.as_ptr() as *mut _, |
| 241 | pub_keys_len, |
| 242 | ))?; |
| 243 | } |
| 244 | |
| 245 | for (buf, len) in encrypted_keys.iter_mut().zip(key_lengths) { |
| 246 | buf.truncate(len as usize); |
| 247 | } |
| 248 | |
| 249 | Ok(()) |
| 250 | } |
| 251 | |
| 252 | /// Initializes the context to perform envelope decryption. |
| 253 | /// |
| 254 | /// Normally this is called once with all of the arguments present. However, this process may be split up by first |
| 255 | /// providing the cipher alone and then after providing the rest of the arguments in a second call. |
| 256 | /// |
| 257 | /// # Panics |
| 258 | /// |
| 259 | /// Panics if the IV buffer is smaller than the cipher's required IV size or if the IV is provided before the |
| 260 | /// cipher. |
| 261 | #[corresponds (EVP_OpenInit)] |
| 262 | #[cfg (not(any(boringssl, awslc)))] |
| 263 | pub fn open_init<T>( |
| 264 | &mut self, |
| 265 | type_: Option<&CipherRef>, |
| 266 | encrypted_key: &[u8], |
| 267 | iv: Option<&[u8]>, |
| 268 | priv_key: Option<&PKeyRef<T>>, |
| 269 | ) -> Result<(), ErrorStack> |
| 270 | where |
| 271 | T: HasPrivate, |
| 272 | { |
| 273 | if priv_key.is_some() { |
| 274 | let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length()); |
| 275 | assert!(iv.map_or(0, |b| b.len()) >= iv_len); |
| 276 | } |
| 277 | |
| 278 | let len = c_int::try_from(encrypted_key.len()).unwrap(); |
| 279 | unsafe { |
| 280 | cvt(ffi::EVP_OpenInit( |
| 281 | self.as_ptr(), |
| 282 | type_.map_or(ptr::null(), |p| p.as_ptr()), |
| 283 | encrypted_key.as_ptr(), |
| 284 | len, |
| 285 | iv.map_or(ptr::null(), |b| b.as_ptr()), |
| 286 | priv_key.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), |
| 287 | ))?; |
| 288 | } |
| 289 | |
| 290 | Ok(()) |
| 291 | } |
| 292 | |
| 293 | fn assert_cipher(&self) { |
| 294 | unsafe { |
| 295 | assert!(!EVP_CIPHER_CTX_get0_cipher(self.as_ptr()).is_null()); |
| 296 | } |
| 297 | } |
| 298 | |
| 299 | /// Returns the block size of the context's cipher. |
| 300 | /// |
| 301 | /// Stream ciphers will report a block size of 1. |
| 302 | /// |
| 303 | /// # Panics |
| 304 | /// |
| 305 | /// Panics if the context has not been initialized with a cipher. |
| 306 | #[corresponds (EVP_CIPHER_CTX_block_size)] |
| 307 | pub fn block_size(&self) -> usize { |
| 308 | self.assert_cipher(); |
| 309 | |
| 310 | unsafe { ffi::EVP_CIPHER_CTX_block_size(self.as_ptr()) as usize } |
| 311 | } |
| 312 | |
| 313 | /// Returns the key length of the context's cipher. |
| 314 | /// |
| 315 | /// # Panics |
| 316 | /// |
| 317 | /// Panics if the context has not been initialized with a cipher. |
| 318 | #[corresponds (EVP_CIPHER_CTX_key_length)] |
| 319 | pub fn key_length(&self) -> usize { |
| 320 | self.assert_cipher(); |
| 321 | |
| 322 | unsafe { ffi::EVP_CIPHER_CTX_key_length(self.as_ptr()) as usize } |
| 323 | } |
| 324 | |
| 325 | /// Generates a random key based on the configured cipher. |
| 326 | /// |
| 327 | /// # Panics |
| 328 | /// |
| 329 | /// Panics if the context has not been initialized with a cipher or if the buffer is smaller than the cipher's key |
| 330 | /// length. |
| 331 | #[corresponds (EVP_CIPHER_CTX_rand_key)] |
| 332 | #[cfg (not(any(boringssl, awslc)))] |
| 333 | pub fn rand_key(&self, buf: &mut [u8]) -> Result<(), ErrorStack> { |
| 334 | assert!(buf.len() >= self.key_length()); |
| 335 | |
| 336 | unsafe { |
| 337 | cvt(ffi::EVP_CIPHER_CTX_rand_key( |
| 338 | self.as_ptr(), |
| 339 | buf.as_mut_ptr(), |
| 340 | ))?; |
| 341 | } |
| 342 | |
| 343 | Ok(()) |
| 344 | } |
| 345 | |
| 346 | /// Sets the length of the key expected by the context. |
| 347 | /// |
| 348 | /// Only some ciphers support configurable key lengths. |
| 349 | /// |
| 350 | /// # Panics |
| 351 | /// |
| 352 | /// Panics if the context has not been initialized with a cipher. |
| 353 | #[corresponds (EVP_CIPHER_CTX_set_key_length)] |
| 354 | pub fn set_key_length(&mut self, len: usize) -> Result<(), ErrorStack> { |
| 355 | self.assert_cipher(); |
| 356 | |
| 357 | unsafe { |
| 358 | cvt(ffi::EVP_CIPHER_CTX_set_key_length( |
| 359 | self.as_ptr(), |
| 360 | len.try_into().unwrap(), |
| 361 | ))?; |
| 362 | } |
| 363 | |
| 364 | Ok(()) |
| 365 | } |
| 366 | |
| 367 | /// Returns the length of the IV expected by this context. |
| 368 | /// |
| 369 | /// Returns 0 if the cipher does not use an IV. |
| 370 | /// |
| 371 | /// # Panics |
| 372 | /// |
| 373 | /// Panics if the context has not been initialized with a cipher. |
| 374 | #[corresponds (EVP_CIPHER_CTX_iv_length)] |
| 375 | pub fn iv_length(&self) -> usize { |
| 376 | self.assert_cipher(); |
| 377 | |
| 378 | unsafe { ffi::EVP_CIPHER_CTX_iv_length(self.as_ptr()) as usize } |
| 379 | } |
| 380 | |
| 381 | /// Returns the `num` parameter of the cipher. |
| 382 | /// |
| 383 | /// Built-in ciphers typically use this to track how much of the |
| 384 | /// current underlying block has been "used" already. |
| 385 | /// |
| 386 | /// # Panics |
| 387 | /// |
| 388 | /// Panics if the context has not been initialized with a cipher. |
| 389 | #[corresponds (EVP_CIPHER_CTX_num)] |
| 390 | #[cfg (ossl110)] |
| 391 | pub fn num(&self) -> usize { |
| 392 | self.assert_cipher(); |
| 393 | |
| 394 | unsafe { ffi::EVP_CIPHER_CTX_num(self.as_ptr()) as usize } |
| 395 | } |
| 396 | |
| 397 | /// Sets the length of the IV expected by this context. |
| 398 | /// |
| 399 | /// Only some ciphers support configurable IV lengths. |
| 400 | /// |
| 401 | /// # Panics |
| 402 | /// |
| 403 | /// Panics if the context has not been initialized with a cipher. |
| 404 | #[corresponds (EVP_CIPHER_CTX_ctrl)] |
| 405 | pub fn set_iv_length(&mut self, len: usize) -> Result<(), ErrorStack> { |
| 406 | self.assert_cipher(); |
| 407 | |
| 408 | let len = c_int::try_from(len).unwrap(); |
| 409 | |
| 410 | unsafe { |
| 411 | cvt(ffi::EVP_CIPHER_CTX_ctrl( |
| 412 | self.as_ptr(), |
| 413 | ffi::EVP_CTRL_GCM_SET_IVLEN, |
| 414 | len, |
| 415 | ptr::null_mut(), |
| 416 | ))?; |
| 417 | } |
| 418 | |
| 419 | Ok(()) |
| 420 | } |
| 421 | |
| 422 | /// Returns the length of the authentication tag expected by this context. |
| 423 | /// |
| 424 | /// Returns 0 if the cipher is not authenticated. |
| 425 | /// |
| 426 | /// # Panics |
| 427 | /// |
| 428 | /// Panics if the context has not been initialized with a cipher. |
| 429 | /// |
| 430 | /// Requires OpenSSL 3.0.0 or newer. |
| 431 | #[corresponds (EVP_CIPHER_CTX_get_tag_length)] |
| 432 | #[cfg (ossl300)] |
| 433 | pub fn tag_length(&self) -> usize { |
| 434 | self.assert_cipher(); |
| 435 | |
| 436 | unsafe { ffi::EVP_CIPHER_CTX_get_tag_length(self.as_ptr()) as usize } |
| 437 | } |
| 438 | |
| 439 | /// Retrieves the calculated authentication tag from the context. |
| 440 | /// |
| 441 | /// This should be called after [`Self::cipher_final`], and is only supported by authenticated ciphers. |
| 442 | /// |
| 443 | /// The size of the buffer indicates the size of the tag. While some ciphers support a range of tag sizes, it is |
| 444 | /// recommended to pick the maximum size. |
| 445 | #[corresponds (EVP_CIPHER_CTX_ctrl)] |
| 446 | pub fn tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> { |
| 447 | let len = c_int::try_from(tag.len()).unwrap(); |
| 448 | |
| 449 | unsafe { |
| 450 | cvt(ffi::EVP_CIPHER_CTX_ctrl( |
| 451 | self.as_ptr(), |
| 452 | ffi::EVP_CTRL_GCM_GET_TAG, |
| 453 | len, |
| 454 | tag.as_mut_ptr() as *mut _, |
| 455 | ))?; |
| 456 | } |
| 457 | |
| 458 | Ok(()) |
| 459 | } |
| 460 | |
| 461 | /// Sets the length of the generated authentication tag. |
| 462 | /// |
| 463 | /// This must be called when encrypting with a cipher in CCM mode to use a tag size other than the default. |
| 464 | #[corresponds (EVP_CIPHER_CTX_ctrl)] |
| 465 | pub fn set_tag_length(&mut self, len: usize) -> Result<(), ErrorStack> { |
| 466 | let len = c_int::try_from(len).unwrap(); |
| 467 | |
| 468 | unsafe { |
| 469 | cvt(ffi::EVP_CIPHER_CTX_ctrl( |
| 470 | self.as_ptr(), |
| 471 | ffi::EVP_CTRL_GCM_SET_TAG, |
| 472 | len, |
| 473 | ptr::null_mut(), |
| 474 | ))?; |
| 475 | } |
| 476 | |
| 477 | Ok(()) |
| 478 | } |
| 479 | |
| 480 | /// Sets the authentication tag for verification during decryption. |
| 481 | #[corresponds (EVP_CIPHER_CTX_ctrl)] |
| 482 | pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> { |
| 483 | let len = c_int::try_from(tag.len()).unwrap(); |
| 484 | |
| 485 | unsafe { |
| 486 | cvt(ffi::EVP_CIPHER_CTX_ctrl( |
| 487 | self.as_ptr(), |
| 488 | ffi::EVP_CTRL_GCM_SET_TAG, |
| 489 | len, |
| 490 | tag.as_ptr() as *mut _, |
| 491 | ))?; |
| 492 | } |
| 493 | |
| 494 | Ok(()) |
| 495 | } |
| 496 | |
| 497 | /// Enables or disables padding. |
| 498 | /// |
| 499 | /// If padding is disabled, the plaintext must be an exact multiple of the cipher's block size. |
| 500 | #[corresponds (EVP_CIPHER_CTX_set_padding)] |
| 501 | pub fn set_padding(&mut self, padding: bool) { |
| 502 | unsafe { |
| 503 | ffi::EVP_CIPHER_CTX_set_padding(self.as_ptr(), padding as c_int); |
| 504 | } |
| 505 | } |
| 506 | |
| 507 | /// Sets the total length of plaintext data. |
| 508 | /// |
| 509 | /// This is required for ciphers operating in CCM mode. |
| 510 | #[corresponds (EVP_CipherUpdate)] |
| 511 | pub fn set_data_len(&mut self, len: usize) -> Result<(), ErrorStack> { |
| 512 | let len = c_int::try_from(len).unwrap(); |
| 513 | |
| 514 | unsafe { |
| 515 | cvt(ffi::EVP_CipherUpdate( |
| 516 | self.as_ptr(), |
| 517 | ptr::null_mut(), |
| 518 | &mut 0, |
| 519 | ptr::null(), |
| 520 | len, |
| 521 | ))?; |
| 522 | } |
| 523 | |
| 524 | Ok(()) |
| 525 | } |
| 526 | |
| 527 | /// Set ctx flags. |
| 528 | /// |
| 529 | /// This function is currently used to enable AES key wrap feature supported by OpenSSL 1.0.2 or newer. |
| 530 | #[corresponds (EVP_CIPHER_CTX_set_flags)] |
| 531 | #[cfg (ossl102)] |
| 532 | pub fn set_flags(&mut self, flags: CipherCtxFlags) { |
| 533 | unsafe { |
| 534 | ffi::EVP_CIPHER_CTX_set_flags(self.as_ptr(), flags.bits()); |
| 535 | } |
| 536 | } |
| 537 | |
| 538 | /// Writes data into the context. |
| 539 | /// |
| 540 | /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD). |
| 541 | /// |
| 542 | /// Returns the number of bytes written to `output`. |
| 543 | /// |
| 544 | /// # Panics |
| 545 | /// |
| 546 | /// Panics if `output` doesn't contain enough space for data to be |
| 547 | /// written. |
| 548 | #[corresponds (EVP_CipherUpdate)] |
| 549 | pub fn cipher_update( |
| 550 | &mut self, |
| 551 | input: &[u8], |
| 552 | output: Option<&mut [u8]>, |
| 553 | ) -> Result<usize, ErrorStack> { |
| 554 | if let Some(output) = &output { |
| 555 | let mut block_size = self.block_size(); |
| 556 | if block_size == 1 { |
| 557 | block_size = 0; |
| 558 | } |
| 559 | let min_output_size = input.len() + block_size; |
| 560 | assert!( |
| 561 | output.len() >= min_output_size, |
| 562 | "Output buffer size should be at least {} bytes." , |
| 563 | min_output_size |
| 564 | ); |
| 565 | } |
| 566 | |
| 567 | unsafe { self.cipher_update_unchecked(input, output) } |
| 568 | } |
| 569 | |
| 570 | /// Writes data into the context. |
| 571 | /// |
| 572 | /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD). |
| 573 | /// |
| 574 | /// Returns the number of bytes written to `output`. |
| 575 | /// |
| 576 | /// This function is the same as [`Self::cipher_update`] but with the |
| 577 | /// output size check removed. It can be used when the exact |
| 578 | /// buffer size control is maintained by the caller. |
| 579 | /// |
| 580 | /// # Safety |
| 581 | /// |
| 582 | /// The caller is expected to provide `output` buffer |
| 583 | /// large enough to contain correct number of bytes. For streaming |
| 584 | /// ciphers the output buffer size should be at least as big as |
| 585 | /// the input buffer. For block ciphers the size of the output |
| 586 | /// buffer depends on the state of partially updated blocks. |
| 587 | #[corresponds (EVP_CipherUpdate)] |
| 588 | pub unsafe fn cipher_update_unchecked( |
| 589 | &mut self, |
| 590 | input: &[u8], |
| 591 | output: Option<&mut [u8]>, |
| 592 | ) -> Result<usize, ErrorStack> { |
| 593 | let inlen = c_int::try_from(input.len()).unwrap(); |
| 594 | |
| 595 | let mut outlen = 0; |
| 596 | |
| 597 | cvt(ffi::EVP_CipherUpdate( |
| 598 | self.as_ptr(), |
| 599 | output.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
| 600 | &mut outlen, |
| 601 | input.as_ptr(), |
| 602 | inlen, |
| 603 | ))?; |
| 604 | |
| 605 | Ok(outlen as usize) |
| 606 | } |
| 607 | |
| 608 | /// Like [`Self::cipher_update`] except that it appends output to a [`Vec`]. |
| 609 | pub fn cipher_update_vec( |
| 610 | &mut self, |
| 611 | input: &[u8], |
| 612 | output: &mut Vec<u8>, |
| 613 | ) -> Result<usize, ErrorStack> { |
| 614 | let base = output.len(); |
| 615 | output.resize(base + input.len() + self.block_size(), 0); |
| 616 | let len = self.cipher_update(input, Some(&mut output[base..]))?; |
| 617 | output.truncate(base + len); |
| 618 | |
| 619 | Ok(len) |
| 620 | } |
| 621 | |
| 622 | /// Like [`Self::cipher_update`] except that it writes output into the |
| 623 | /// `data` buffer. The `inlen` parameter specifies the number of bytes in |
| 624 | /// `data` that are considered the input. For streaming ciphers, the size of |
| 625 | /// `data` must be at least the input size. Otherwise, it must be at least |
| 626 | /// an additional block size larger. |
| 627 | /// |
| 628 | /// Note: Use [`Self::cipher_update`] with no output argument to write AAD. |
| 629 | /// |
| 630 | /// # Panics |
| 631 | /// |
| 632 | /// This function panics if the input size cannot be represented as `int` or |
| 633 | /// exceeds the buffer size, or if the output buffer does not contain enough |
| 634 | /// additional space. |
| 635 | #[corresponds (EVP_CipherUpdate)] |
| 636 | pub fn cipher_update_inplace( |
| 637 | &mut self, |
| 638 | data: &mut [u8], |
| 639 | inlen: usize, |
| 640 | ) -> Result<usize, ErrorStack> { |
| 641 | assert!(inlen <= data.len(), "Input size may not exceed buffer size" ); |
| 642 | let block_size = self.block_size(); |
| 643 | if block_size != 1 { |
| 644 | assert!( |
| 645 | data.len() >= inlen + block_size, |
| 646 | "Output buffer size must be at least {} bytes." , |
| 647 | inlen + block_size |
| 648 | ); |
| 649 | } |
| 650 | |
| 651 | let inlen = c_int::try_from(inlen).unwrap(); |
| 652 | let mut outlen = 0; |
| 653 | unsafe { |
| 654 | cvt(ffi::EVP_CipherUpdate( |
| 655 | self.as_ptr(), |
| 656 | data.as_mut_ptr(), |
| 657 | &mut outlen, |
| 658 | data.as_ptr(), |
| 659 | inlen, |
| 660 | )) |
| 661 | }?; |
| 662 | |
| 663 | Ok(outlen as usize) |
| 664 | } |
| 665 | |
| 666 | /// Finalizes the encryption or decryption process. |
| 667 | /// |
| 668 | /// Any remaining data will be written to the output buffer. |
| 669 | /// |
| 670 | /// Returns the number of bytes written to `output`. |
| 671 | /// |
| 672 | /// # Panics |
| 673 | /// |
| 674 | /// Panics if `output` is smaller than the cipher's block size. |
| 675 | #[corresponds (EVP_CipherFinal)] |
| 676 | pub fn cipher_final(&mut self, output: &mut [u8]) -> Result<usize, ErrorStack> { |
| 677 | let block_size = self.block_size(); |
| 678 | if block_size > 1 { |
| 679 | assert!(output.len() >= block_size); |
| 680 | } |
| 681 | |
| 682 | unsafe { self.cipher_final_unchecked(output) } |
| 683 | } |
| 684 | |
| 685 | /// Finalizes the encryption or decryption process. |
| 686 | /// |
| 687 | /// Any remaining data will be written to the output buffer. |
| 688 | /// |
| 689 | /// Returns the number of bytes written to `output`. |
| 690 | /// |
| 691 | /// This function is the same as [`Self::cipher_final`] but with |
| 692 | /// the output buffer size check removed. |
| 693 | /// |
| 694 | /// # Safety |
| 695 | /// |
| 696 | /// The caller is expected to provide `output` buffer |
| 697 | /// large enough to contain correct number of bytes. For streaming |
| 698 | /// ciphers the output buffer can be empty, for block ciphers the |
| 699 | /// output buffer should be at least as big as the block. |
| 700 | #[corresponds (EVP_CipherFinal)] |
| 701 | pub unsafe fn cipher_final_unchecked( |
| 702 | &mut self, |
| 703 | output: &mut [u8], |
| 704 | ) -> Result<usize, ErrorStack> { |
| 705 | let mut outl = 0; |
| 706 | |
| 707 | cvt(ffi::EVP_CipherFinal( |
| 708 | self.as_ptr(), |
| 709 | output.as_mut_ptr(), |
| 710 | &mut outl, |
| 711 | ))?; |
| 712 | |
| 713 | Ok(outl as usize) |
| 714 | } |
| 715 | |
| 716 | /// Like [`Self::cipher_final`] except that it appends output to a [`Vec`]. |
| 717 | pub fn cipher_final_vec(&mut self, output: &mut Vec<u8>) -> Result<usize, ErrorStack> { |
| 718 | let base = output.len(); |
| 719 | output.resize(base + self.block_size(), 0); |
| 720 | let len = self.cipher_final(&mut output[base..])?; |
| 721 | output.truncate(base + len); |
| 722 | |
| 723 | Ok(len) |
| 724 | } |
| 725 | } |
| 726 | |
| 727 | #[cfg (test)] |
| 728 | mod test { |
| 729 | use super::*; |
| 730 | use crate::{cipher::Cipher, rand::rand_bytes}; |
| 731 | #[cfg (not(any(boringssl, awslc)))] |
| 732 | use std::slice; |
| 733 | |
| 734 | #[test ] |
| 735 | #[cfg (not(any(boringssl, awslc)))] |
| 736 | fn seal_open() { |
| 737 | let private_pem = include_bytes!("../test/rsa.pem" ); |
| 738 | let public_pem = include_bytes!("../test/rsa.pem.pub" ); |
| 739 | let private_key = PKey::private_key_from_pem(private_pem).unwrap(); |
| 740 | let public_key = PKey::public_key_from_pem(public_pem).unwrap(); |
| 741 | let cipher = Cipher::aes_256_cbc(); |
| 742 | let secret = b"My secret message" ; |
| 743 | |
| 744 | let mut ctx = CipherCtx::new().unwrap(); |
| 745 | let mut encrypted_key = vec![]; |
| 746 | let mut iv = vec![0; cipher.iv_length()]; |
| 747 | let mut encrypted = vec![]; |
| 748 | ctx.seal_init( |
| 749 | Some(cipher), |
| 750 | &[public_key], |
| 751 | slice::from_mut(&mut encrypted_key), |
| 752 | Some(&mut iv), |
| 753 | ) |
| 754 | .unwrap(); |
| 755 | ctx.cipher_update_vec(secret, &mut encrypted).unwrap(); |
| 756 | ctx.cipher_final_vec(&mut encrypted).unwrap(); |
| 757 | |
| 758 | let mut decrypted = vec![]; |
| 759 | ctx.open_init(Some(cipher), &encrypted_key, Some(&iv), Some(&private_key)) |
| 760 | .unwrap(); |
| 761 | ctx.cipher_update_vec(&encrypted, &mut decrypted).unwrap(); |
| 762 | ctx.cipher_final_vec(&mut decrypted).unwrap(); |
| 763 | |
| 764 | assert_eq!(secret, &decrypted[..]); |
| 765 | } |
| 766 | |
| 767 | fn aes_128_cbc(cipher: &CipherRef) { |
| 768 | // from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf |
| 769 | let key = hex::decode("2b7e151628aed2a6abf7158809cf4f3c" ).unwrap(); |
| 770 | let iv = hex::decode("000102030405060708090a0b0c0d0e0f" ).unwrap(); |
| 771 | let pt = hex::decode("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51" ) |
| 772 | .unwrap(); |
| 773 | let ct = hex::decode("7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b2" ) |
| 774 | .unwrap(); |
| 775 | |
| 776 | let mut ctx = CipherCtx::new().unwrap(); |
| 777 | |
| 778 | ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv)) |
| 779 | .unwrap(); |
| 780 | ctx.set_padding(false); |
| 781 | |
| 782 | let mut buf = vec![]; |
| 783 | ctx.cipher_update_vec(&pt, &mut buf).unwrap(); |
| 784 | ctx.cipher_final_vec(&mut buf).unwrap(); |
| 785 | |
| 786 | assert_eq!(buf, ct); |
| 787 | |
| 788 | ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv)) |
| 789 | .unwrap(); |
| 790 | ctx.set_padding(false); |
| 791 | |
| 792 | let mut buf = vec![]; |
| 793 | ctx.cipher_update_vec(&ct, &mut buf).unwrap(); |
| 794 | ctx.cipher_final_vec(&mut buf).unwrap(); |
| 795 | |
| 796 | assert_eq!(buf, pt); |
| 797 | } |
| 798 | |
| 799 | #[test ] |
| 800 | #[cfg (ossl300)] |
| 801 | fn fetched_aes_128_cbc() { |
| 802 | let cipher = Cipher::fetch(None, "AES-128-CBC" , None).unwrap(); |
| 803 | aes_128_cbc(&cipher); |
| 804 | } |
| 805 | |
| 806 | #[test ] |
| 807 | fn default_aes_128_cbc() { |
| 808 | let cipher = Cipher::aes_128_cbc(); |
| 809 | aes_128_cbc(cipher); |
| 810 | } |
| 811 | |
| 812 | #[cfg (not(boringssl))] |
| 813 | #[test ] |
| 814 | fn default_aes_128_ccm() { |
| 815 | // from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/ccmtestvectors.zip |
| 816 | let cipher = Cipher::aes_128_ccm(); |
| 817 | aes_ccm( |
| 818 | cipher, |
| 819 | "26511fb51fcfa75cb4b44da75a6e5a0e" , |
| 820 | "ea98ec44f5a86715014783172e" , |
| 821 | "4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10" , |
| 822 | "e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810" , |
| 823 | "1bf0ba0ebb20d8edba59f29a9371750c9c714078f73c335d" , |
| 824 | "2f1322ac69b848b001476323aed84c47" , |
| 825 | ); |
| 826 | } |
| 827 | |
| 828 | #[cfg (not(boringssl))] |
| 829 | #[test ] |
| 830 | fn default_aes_192_ccm() { |
| 831 | // from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/ccmtestvectors.zip |
| 832 | let cipher = Cipher::aes_192_ccm(); |
| 833 | aes_ccm( |
| 834 | cipher, |
| 835 | "26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886" , |
| 836 | "ea98ec44f5a86715014783172e" , |
| 837 | "4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10" , |
| 838 | "e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810" , |
| 839 | "30c154c616946eccc2e241d336ad33720953e449a0e6b0f0" , |
| 840 | "dbf8e9464909bdf337e48093c082a10b" , |
| 841 | ); |
| 842 | } |
| 843 | |
| 844 | #[cfg (not(boringssl))] |
| 845 | #[test ] |
| 846 | fn default_aes_256_ccm() { |
| 847 | // from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/mac/ccmtestvectors.zip |
| 848 | let cipher = Cipher::aes_256_ccm(); |
| 849 | aes_ccm( |
| 850 | cipher, |
| 851 | "314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e" , |
| 852 | "3542fbe0f59a6d5f3abf619b7d" , |
| 853 | "c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed" , |
| 854 | "dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8" , |
| 855 | "39c2e8f6edfe663b90963b98eb79e2d4f7f28a5053ae8881" , |
| 856 | "567a6b4426f1667136bed4a5e32a2bc1" , |
| 857 | ); |
| 858 | } |
| 859 | |
| 860 | #[cfg (not(boringssl))] |
| 861 | fn aes_ccm( |
| 862 | cipher: &CipherRef, |
| 863 | key: &'static str, |
| 864 | iv: &'static str, |
| 865 | pt: &'static str, |
| 866 | aad: &'static str, |
| 867 | ct: &'static str, |
| 868 | tag: &'static str, |
| 869 | ) { |
| 870 | let key = hex::decode(key).unwrap(); |
| 871 | let iv = hex::decode(iv).unwrap(); |
| 872 | let pt = hex::decode(pt).unwrap(); |
| 873 | let ct = hex::decode(ct).unwrap(); |
| 874 | let aad = hex::decode(aad).unwrap(); |
| 875 | let tag = hex::decode(tag).unwrap(); |
| 876 | |
| 877 | let mut ctx = CipherCtx::new().unwrap(); |
| 878 | |
| 879 | ctx.encrypt_init(Some(cipher), None, None).unwrap(); |
| 880 | ctx.set_iv_length(iv.len()).unwrap(); |
| 881 | ctx.set_tag_length(tag.len()).unwrap(); |
| 882 | ctx.encrypt_init(None, Some(&key), Some(&iv)).unwrap(); |
| 883 | ctx.set_data_len(pt.len()).unwrap(); |
| 884 | |
| 885 | let mut buf = vec![]; |
| 886 | ctx.cipher_update(&aad, None).unwrap(); |
| 887 | ctx.cipher_update_vec(&pt, &mut buf).unwrap(); |
| 888 | ctx.cipher_final_vec(&mut buf).unwrap(); |
| 889 | assert_eq!(buf, ct); |
| 890 | |
| 891 | let mut out_tag = vec![0u8; tag.len()]; |
| 892 | ctx.tag(&mut out_tag).unwrap(); |
| 893 | assert_eq!(tag, out_tag); |
| 894 | |
| 895 | ctx.decrypt_init(Some(cipher), None, None).unwrap(); |
| 896 | ctx.set_iv_length(iv.len()).unwrap(); |
| 897 | ctx.set_tag(&tag).unwrap(); |
| 898 | ctx.decrypt_init(None, Some(&key), Some(&iv)).unwrap(); |
| 899 | ctx.set_data_len(pt.len()).unwrap(); |
| 900 | |
| 901 | let mut buf = vec![]; |
| 902 | ctx.cipher_update(&aad, None).unwrap(); |
| 903 | ctx.cipher_update_vec(&ct, &mut buf).unwrap(); |
| 904 | // Some older libraries don't support calling EVP_CipherFinal/EVP_DecryptFinal for CCM |
| 905 | // https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Decryption_using_CCM_mode |
| 906 | #[cfg (any(ossl111, awslc, boringssl))] |
| 907 | ctx.cipher_final_vec(&mut buf).unwrap(); |
| 908 | |
| 909 | assert_eq!(buf, pt); |
| 910 | } |
| 911 | |
| 912 | #[cfg (not(any(boringssl, awslc)))] |
| 913 | #[test ] |
| 914 | fn default_aes_128_xts() { |
| 915 | // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/aes/XTSTestVectors.zip |
| 916 | let cipher = Cipher::aes_128_xts(); |
| 917 | aes_xts( |
| 918 | cipher, |
| 919 | "a1b90cba3f06ac353b2c343876081762090923026e91771815f29dab01932f2f" , |
| 920 | "4faef7117cda59c66e4b92013e768ad5" , |
| 921 | "ebabce95b14d3c8d6fb350390790311c" , |
| 922 | "778ae8b43cb98d5a825081d5be471c63" , |
| 923 | ); |
| 924 | } |
| 925 | |
| 926 | #[cfg (not(boringssl))] |
| 927 | #[test ] |
| 928 | fn default_aes_256_xts() { |
| 929 | // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/aes/XTSTestVectors.zip |
| 930 | let cipher = Cipher::aes_256_xts(); |
| 931 | aes_xts(cipher, "1ea661c58d943a0e4801e42f4b0947149e7f9f8e3e68d0c7505210bd311a0e7cd6e13ffdf2418d8d1911c004cda58da3d619b7e2b9141e58318eea392cf41b08" , "adf8d92627464ad2f0428e84a9f87564" , "2eedea52cd8215e1acc647e810bbc3642e87287f8d2e57e36c0a24fbc12a202e" , "cbaad0e2f6cea3f50b37f934d46a9b130b9d54f07e34f36af793e86f73c6d7db" ); |
| 932 | } |
| 933 | |
| 934 | #[cfg (not(boringssl))] |
| 935 | fn aes_xts( |
| 936 | cipher: &CipherRef, |
| 937 | key: &'static str, |
| 938 | i: &'static str, |
| 939 | pt: &'static str, |
| 940 | ct: &'static str, |
| 941 | ) { |
| 942 | let key = hex::decode(key).unwrap(); |
| 943 | let i = hex::decode(i).unwrap(); |
| 944 | let pt = hex::decode(pt).unwrap(); |
| 945 | let ct = hex::decode(ct).unwrap(); |
| 946 | |
| 947 | let mut ctx = CipherCtx::new().unwrap(); |
| 948 | ctx.encrypt_init(Some(cipher), Some(&key), Some(&i)) |
| 949 | .unwrap(); |
| 950 | let mut buf = vec![]; |
| 951 | ctx.cipher_update_vec(&pt, &mut buf).unwrap(); |
| 952 | ctx.cipher_final_vec(&mut buf).unwrap(); |
| 953 | |
| 954 | assert_eq!(ct, buf); |
| 955 | |
| 956 | ctx.decrypt_init(Some(cipher), Some(&key), Some(&i)) |
| 957 | .unwrap(); |
| 958 | let mut buf = vec![]; |
| 959 | ctx.cipher_update_vec(&ct, &mut buf).unwrap(); |
| 960 | ctx.cipher_final_vec(&mut buf).unwrap(); |
| 961 | |
| 962 | assert_eq!(pt, buf); |
| 963 | } |
| 964 | |
| 965 | #[test ] |
| 966 | fn test_stream_ciphers() { |
| 967 | #[cfg (not(boringssl))] |
| 968 | { |
| 969 | test_stream_cipher(Cipher::aes_128_cfb1()); |
| 970 | test_stream_cipher(Cipher::aes_128_cfb8()); |
| 971 | test_stream_cipher(Cipher::aes_128_cfb128()); |
| 972 | test_stream_cipher(Cipher::aes_192_cfb1()); |
| 973 | test_stream_cipher(Cipher::aes_192_cfb8()); |
| 974 | test_stream_cipher(Cipher::aes_192_cfb128()); |
| 975 | test_stream_cipher(Cipher::aes_256_cfb1()); |
| 976 | test_stream_cipher(Cipher::aes_256_cfb8()); |
| 977 | test_stream_cipher(Cipher::aes_256_cfb128()); |
| 978 | } |
| 979 | test_stream_cipher(Cipher::aes_192_ctr()); |
| 980 | test_stream_cipher(Cipher::aes_256_ctr()); |
| 981 | } |
| 982 | |
| 983 | fn test_stream_cipher(cipher: &'static CipherRef) { |
| 984 | let mut key = vec![0; cipher.key_length()]; |
| 985 | rand_bytes(&mut key).unwrap(); |
| 986 | let mut iv = vec![0; cipher.iv_length()]; |
| 987 | rand_bytes(&mut iv).unwrap(); |
| 988 | |
| 989 | let mut ctx = CipherCtx::new().unwrap(); |
| 990 | |
| 991 | ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv)) |
| 992 | .unwrap(); |
| 993 | ctx.set_padding(false); |
| 994 | |
| 995 | assert_eq!( |
| 996 | 1, |
| 997 | cipher.block_size(), |
| 998 | "Need a stream cipher, not a block cipher" |
| 999 | ); |
| 1000 | |
| 1001 | // update cipher with non-full block |
| 1002 | // this is a streaming cipher so the number of output bytes |
| 1003 | // will be the same as the number of input bytes |
| 1004 | let mut output = vec![0; 32]; |
| 1005 | let outlen = ctx |
| 1006 | .cipher_update(&[1; 15], Some(&mut output[0..15])) |
| 1007 | .unwrap(); |
| 1008 | assert_eq!(15, outlen); |
| 1009 | |
| 1010 | // update cipher with missing bytes from the previous block |
| 1011 | // as previously it will output the same number of bytes as |
| 1012 | // the input |
| 1013 | let outlen = ctx |
| 1014 | .cipher_update(&[1; 17], Some(&mut output[15..])) |
| 1015 | .unwrap(); |
| 1016 | assert_eq!(17, outlen); |
| 1017 | |
| 1018 | ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); |
| 1019 | |
| 1020 | // encrypt again, but use in-place encryption this time |
| 1021 | // First reset the IV |
| 1022 | ctx.encrypt_init(None, None, Some(&iv)).unwrap(); |
| 1023 | ctx.set_padding(false); |
| 1024 | let mut data_inplace: [u8; 32] = [1; 32]; |
| 1025 | let outlen = ctx |
| 1026 | .cipher_update_inplace(&mut data_inplace[0..15], 15) |
| 1027 | .unwrap(); |
| 1028 | assert_eq!(15, outlen); |
| 1029 | |
| 1030 | let outlen = ctx |
| 1031 | .cipher_update_inplace(&mut data_inplace[15..32], 17) |
| 1032 | .unwrap(); |
| 1033 | assert_eq!(17, outlen); |
| 1034 | |
| 1035 | ctx.cipher_final(&mut [0u8; 0]).unwrap(); |
| 1036 | |
| 1037 | // Check that the resulting data is encrypted in the same manner |
| 1038 | assert_eq!(data_inplace.as_slice(), output.as_slice()); |
| 1039 | |
| 1040 | // try to decrypt |
| 1041 | ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv)) |
| 1042 | .unwrap(); |
| 1043 | ctx.set_padding(false); |
| 1044 | |
| 1045 | // update cipher with non-full block |
| 1046 | // expect that the output for stream cipher will contain |
| 1047 | // the same number of bytes as the input |
| 1048 | let mut output_decrypted = vec![0; 32]; |
| 1049 | let outlen = ctx |
| 1050 | .cipher_update(&output[0..15], Some(&mut output_decrypted[0..15])) |
| 1051 | .unwrap(); |
| 1052 | assert_eq!(15, outlen); |
| 1053 | |
| 1054 | let outlen = ctx |
| 1055 | .cipher_update(&output[15..], Some(&mut output_decrypted[15..])) |
| 1056 | .unwrap(); |
| 1057 | assert_eq!(17, outlen); |
| 1058 | |
| 1059 | ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); |
| 1060 | // check if the decrypted blocks are the same as input (all ones) |
| 1061 | assert_eq!(output_decrypted, vec![1; 32]); |
| 1062 | |
| 1063 | // decrypt again, but now the output in-place |
| 1064 | ctx.decrypt_init(None, None, Some(&iv)).unwrap(); |
| 1065 | ctx.set_padding(false); |
| 1066 | |
| 1067 | let outlen = ctx.cipher_update_inplace(&mut output[0..15], 15).unwrap(); |
| 1068 | assert_eq!(15, outlen); |
| 1069 | |
| 1070 | let outlen = ctx.cipher_update_inplace(&mut output[15..], 17).unwrap(); |
| 1071 | assert_eq!(17, outlen); |
| 1072 | |
| 1073 | ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); |
| 1074 | assert_eq!(output_decrypted, output); |
| 1075 | } |
| 1076 | |
| 1077 | #[test ] |
| 1078 | #[should_panic (expected = "Output buffer size should be at least 33 bytes." )] |
| 1079 | fn full_block_updates_aes_128() { |
| 1080 | output_buffer_too_small(Cipher::aes_128_cbc()); |
| 1081 | } |
| 1082 | |
| 1083 | #[test ] |
| 1084 | #[should_panic (expected = "Output buffer size should be at least 33 bytes." )] |
| 1085 | fn full_block_updates_aes_256() { |
| 1086 | output_buffer_too_small(Cipher::aes_256_cbc()); |
| 1087 | } |
| 1088 | |
| 1089 | #[test ] |
| 1090 | #[should_panic (expected = "Output buffer size should be at least 17 bytes." )] |
| 1091 | fn full_block_updates_3des() { |
| 1092 | output_buffer_too_small(Cipher::des_ede3_cbc()); |
| 1093 | } |
| 1094 | |
| 1095 | fn output_buffer_too_small(cipher: &'static CipherRef) { |
| 1096 | let mut key = vec![0; cipher.key_length()]; |
| 1097 | rand_bytes(&mut key).unwrap(); |
| 1098 | let mut iv = vec![0; cipher.iv_length()]; |
| 1099 | rand_bytes(&mut iv).unwrap(); |
| 1100 | |
| 1101 | let mut ctx = CipherCtx::new().unwrap(); |
| 1102 | |
| 1103 | ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv)) |
| 1104 | .unwrap(); |
| 1105 | ctx.set_padding(false); |
| 1106 | |
| 1107 | let block_size = cipher.block_size(); |
| 1108 | assert!(block_size > 1, "Need a block cipher, not a stream cipher" ); |
| 1109 | |
| 1110 | ctx.cipher_update(&vec![0; block_size + 1], Some(&mut vec![0; block_size - 1])) |
| 1111 | .unwrap(); |
| 1112 | } |
| 1113 | |
| 1114 | #[cfg (ossl102)] |
| 1115 | fn cipher_wrap_test(cipher: &CipherRef, pt: &str, ct: &str, key: &str, iv: Option<&str>) { |
| 1116 | let pt = hex::decode(pt).unwrap(); |
| 1117 | let key = hex::decode(key).unwrap(); |
| 1118 | let expected = hex::decode(ct).unwrap(); |
| 1119 | let iv = iv.map(|v| hex::decode(v).unwrap()); |
| 1120 | let padding = 8 - pt.len() % 8; |
| 1121 | let mut computed = vec![0; pt.len() + padding + cipher.block_size() * 2]; |
| 1122 | let mut ctx = CipherCtx::new().unwrap(); |
| 1123 | |
| 1124 | ctx.set_flags(CipherCtxFlags::FLAG_WRAP_ALLOW); |
| 1125 | ctx.encrypt_init(Some(cipher), Some(&key), iv.as_deref()) |
| 1126 | .unwrap(); |
| 1127 | |
| 1128 | let count = ctx.cipher_update(&pt, Some(&mut computed)).unwrap(); |
| 1129 | let rest = ctx.cipher_final(&mut computed[count..]).unwrap(); |
| 1130 | computed.truncate(count + rest); |
| 1131 | |
| 1132 | if computed != expected { |
| 1133 | println!("Computed: {}" , hex::encode(&computed)); |
| 1134 | println!("Expected: {}" , hex::encode(&expected)); |
| 1135 | if computed.len() != expected.len() { |
| 1136 | println!( |
| 1137 | "Lengths differ: {} in computed vs {} expected" , |
| 1138 | computed.len(), |
| 1139 | expected.len() |
| 1140 | ); |
| 1141 | } |
| 1142 | panic!("test failure" ); |
| 1143 | } |
| 1144 | } |
| 1145 | |
| 1146 | #[test ] |
| 1147 | #[cfg (ossl102)] |
| 1148 | fn test_aes128_wrap() { |
| 1149 | let pt = "00112233445566778899aabbccddeeff" ; |
| 1150 | let ct = "7940ff694448b5bb5139c959a4896832e55d69aa04daa27e" ; |
| 1151 | let key = "2b7e151628aed2a6abf7158809cf4f3c" ; |
| 1152 | let iv = "0001020304050607" ; |
| 1153 | |
| 1154 | cipher_wrap_test(Cipher::aes_128_wrap(), pt, ct, key, Some(iv)); |
| 1155 | } |
| 1156 | |
| 1157 | #[test ] |
| 1158 | #[cfg (ossl102)] |
| 1159 | fn test_aes128_wrap_default_iv() { |
| 1160 | let pt = "00112233445566778899aabbccddeeff" ; |
| 1161 | let ct = "38f1215f0212526f8a70b51955b9fbdc9fe3041d9832306e" ; |
| 1162 | let key = "2b7e151628aed2a6abf7158809cf4f3c" ; |
| 1163 | |
| 1164 | cipher_wrap_test(Cipher::aes_128_wrap(), pt, ct, key, None); |
| 1165 | } |
| 1166 | |
| 1167 | #[test ] |
| 1168 | #[cfg (ossl110)] |
| 1169 | fn test_aes128_wrap_pad() { |
| 1170 | let pt = "00112233445566778899aabbccddee" ; |
| 1171 | let ct = "f13998f5ab32ef82a1bdbcbe585e1d837385b529572a1e1b" ; |
| 1172 | let key = "2b7e151628aed2a6abf7158809cf4f3c" ; |
| 1173 | let iv = "00010203" ; |
| 1174 | |
| 1175 | cipher_wrap_test(Cipher::aes_128_wrap_pad(), pt, ct, key, Some(iv)); |
| 1176 | } |
| 1177 | |
| 1178 | #[test ] |
| 1179 | #[cfg (ossl110)] |
| 1180 | fn test_aes128_wrap_pad_default_iv() { |
| 1181 | let pt = "00112233445566778899aabbccddee" ; |
| 1182 | let ct = "3a501085fb8cf66f4186b7df851914d471ed823411598add" ; |
| 1183 | let key = "2b7e151628aed2a6abf7158809cf4f3c" ; |
| 1184 | |
| 1185 | cipher_wrap_test(Cipher::aes_128_wrap_pad(), pt, ct, key, None); |
| 1186 | } |
| 1187 | |
| 1188 | #[test ] |
| 1189 | #[cfg (ossl102)] |
| 1190 | fn test_aes192_wrap() { |
| 1191 | let pt = "9f6dee187d35302116aecbfd059657efd9f7589c4b5e7f5b" ; |
| 1192 | let ct = "83b89142dfeeb4871e078bfb81134d33e23fedc19b03a1cf689973d3831b6813" ; |
| 1193 | let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" ; |
| 1194 | let iv = "0001020304050607" ; |
| 1195 | |
| 1196 | cipher_wrap_test(Cipher::aes_192_wrap(), pt, ct, key, Some(iv)); |
| 1197 | } |
| 1198 | |
| 1199 | #[test ] |
| 1200 | #[cfg (ossl102)] |
| 1201 | fn test_aes192_wrap_default_iv() { |
| 1202 | let pt = "9f6dee187d35302116aecbfd059657efd9f7589c4b5e7f5b" ; |
| 1203 | let ct = "c02c2cf11505d3e4851030d5534cbf5a1d7eca7ba8839adbf239756daf1b43e6" ; |
| 1204 | let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" ; |
| 1205 | |
| 1206 | cipher_wrap_test(Cipher::aes_192_wrap(), pt, ct, key, None); |
| 1207 | } |
| 1208 | |
| 1209 | #[test ] |
| 1210 | #[cfg (ossl110)] |
| 1211 | fn test_aes192_wrap_pad() { |
| 1212 | let pt = "00112233445566778899aabbccddee" ; |
| 1213 | let ct = "b4f6bb167ef7caf061a74da82b36ad038ca057ab51e98d3a" ; |
| 1214 | let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" ; |
| 1215 | let iv = "00010203" ; |
| 1216 | |
| 1217 | cipher_wrap_test(Cipher::aes_192_wrap_pad(), pt, ct, key, Some(iv)); |
| 1218 | } |
| 1219 | |
| 1220 | #[test ] |
| 1221 | #[cfg (ossl110)] |
| 1222 | fn test_aes192_wrap_pad_default_iv() { |
| 1223 | let pt = "00112233445566778899aabbccddee" ; |
| 1224 | let ct = "b2c37a28cc602753a7c944a4c2555a2df9c98b2eded5312e" ; |
| 1225 | let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b" ; |
| 1226 | |
| 1227 | cipher_wrap_test(Cipher::aes_192_wrap_pad(), pt, ct, key, None); |
| 1228 | } |
| 1229 | |
| 1230 | #[test ] |
| 1231 | #[cfg (ossl102)] |
| 1232 | fn test_aes256_wrap() { |
| 1233 | let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51" ; |
| 1234 | let ct = "cc05da2a7f56f7dd0c144231f90bce58648fa20a8278f5a6b7d13bba6aa57a33229d4333866b7fd6" ; |
| 1235 | let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" ; |
| 1236 | let iv = "0001020304050607" ; |
| 1237 | |
| 1238 | cipher_wrap_test(Cipher::aes_256_wrap(), pt, ct, key, Some(iv)); |
| 1239 | } |
| 1240 | |
| 1241 | #[test ] |
| 1242 | #[cfg (ossl102)] |
| 1243 | fn test_aes256_wrap_default_iv() { |
| 1244 | let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51" ; |
| 1245 | let ct = "0b24f068b50e52bc6987868411c36e1b03900866ed12af81eb87cef70a8d1911731c1d7abf789d88" ; |
| 1246 | let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" ; |
| 1247 | |
| 1248 | cipher_wrap_test(Cipher::aes_256_wrap(), pt, ct, key, None); |
| 1249 | } |
| 1250 | |
| 1251 | #[test ] |
| 1252 | #[cfg (ossl110)] |
| 1253 | fn test_aes256_wrap_pad() { |
| 1254 | let pt = "00112233445566778899aabbccddee" ; |
| 1255 | let ct = "91594e044ccc06130d60e6c84a996aa4f96a9faff8c5f6e7" ; |
| 1256 | let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" ; |
| 1257 | let iv = "00010203" ; |
| 1258 | |
| 1259 | cipher_wrap_test(Cipher::aes_256_wrap_pad(), pt, ct, key, Some(iv)); |
| 1260 | } |
| 1261 | |
| 1262 | #[test ] |
| 1263 | #[cfg (ossl110)] |
| 1264 | fn test_aes256_wrap_pad_default_iv() { |
| 1265 | let pt = "00112233445566778899aabbccddee" ; |
| 1266 | let ct = "dc3c166a854afd68aea624a4272693554bf2e4fcbae602cd" ; |
| 1267 | let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4" ; |
| 1268 | |
| 1269 | cipher_wrap_test(Cipher::aes_256_wrap_pad(), pt, ct, key, None); |
| 1270 | } |
| 1271 | } |
| 1272 | |