Skip to content

Commit f0ff8a7

Browse files
authored
Merge pull request #1762 from wiktor-k/fix-broken-relaxation
Fix broken relaxation
2 parents 64ba480 + 45e5dce commit f0ff8a7

File tree

1 file changed

+37
-152
lines changed

1 file changed

+37
-152
lines changed

openssl/src/cipher_ctx.rs

Lines changed: 37 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -379,49 +379,6 @@ impl CipherCtxRef {
379379
unsafe { ffi::EVP_CIPHER_CTX_num(self.as_ptr()) as usize }
380380
}
381381

382-
/// Returns number of bytes cached in partial block update.
383-
#[cfg(ossl110)]
384-
fn used_block_size(&self) -> usize {
385-
self.num()
386-
}
387-
388-
/// Returns maximum number of bytes that could be cached.
389-
#[cfg(not(ossl110))]
390-
fn used_block_size(&self) -> usize {
391-
self.block_size()
392-
}
393-
394-
/// Calculate the minimal size of the output buffer given the
395-
/// input buffer size.
396-
///
397-
/// For streaming ciphers the minimal output size is the same as
398-
/// the input size. For block ciphers the minimal output size
399-
/// additionally depends on the partial blocks that might have
400-
/// been written in previous calls to [`Self::cipher_update`].
401-
///
402-
/// This function takes into account the number of partially
403-
/// written blocks for block ciphers for supported targets
404-
/// (OpenSSL >= 1.1). For unsupported targets the number of
405-
/// partially written bytes is assumed to contain one full block
406-
/// (pessimistic case).
407-
///
408-
/// # Panics
409-
///
410-
/// Panics if the context has not been initialized with a cipher.
411-
pub fn minimal_output_size(&self, inlen: usize) -> usize {
412-
let block_size = self.block_size();
413-
if block_size > 1 {
414-
// block cipher
415-
let num = self.used_block_size();
416-
let total_size = inlen + num;
417-
let num_blocks = total_size / block_size;
418-
num_blocks * block_size
419-
} else {
420-
// streaming cipher
421-
inlen
422-
}
423-
}
424-
425382
/// Sets the length of the IV expected by this context.
426383
///
427384
/// Only some ciphers support configurable IV lengths.
@@ -569,7 +526,11 @@ impl CipherCtxRef {
569526
output: Option<&mut [u8]>,
570527
) -> Result<usize, ErrorStack> {
571528
if let Some(output) = &output {
572-
let min_output_size = self.minimal_output_size(input.len());
529+
let mut block_size = self.block_size();
530+
if block_size == 1 {
531+
block_size = 0;
532+
}
533+
let min_output_size = input.len() + block_size;
573534
assert!(
574535
output.len() >= min_output_size,
575536
"Output buffer size should be at least {} bytes.",
@@ -588,16 +549,13 @@ impl CipherCtxRef {
588549
///
589550
/// This function is the same as [`Self::cipher_update`] but with the
590551
/// output size check removed. It can be used when the exact
591-
/// buffer size control is maintained by the caller and the
592-
/// underlying cryptographic library doesn't expose exact block
593-
/// cache data (e.g. OpenSSL < 1.1, BoringSSL, LibreSSL).
552+
/// buffer size control is maintained by the caller.
594553
///
595554
/// SAFETY: The caller is expected to provide `output` buffer
596555
/// large enough to contain correct number of bytes. For streaming
597556
/// ciphers the output buffer size should be at least as big as
598557
/// the input buffer. For block ciphers the size of the output
599-
/// buffer depends on the state of partially updated blocks (see
600-
/// [`Self::minimal_output_size`]).
558+
/// buffer depends on the state of partially updated blocks.
601559
#[corresponds(EVP_CipherUpdate)]
602560
pub unsafe fn cipher_update_unchecked(
603561
&mut self,
@@ -649,14 +607,34 @@ impl CipherCtxRef {
649607
assert!(output.len() >= block_size);
650608
}
651609

610+
unsafe { self.cipher_final_unchecked(output) }
611+
}
612+
613+
/// Finalizes the encryption or decryption process.
614+
///
615+
/// Any remaining data will be written to the output buffer.
616+
///
617+
/// Returns the number of bytes written to `output`.
618+
///
619+
/// This function is the same as [`Self::cipher_final`] but with
620+
/// the output buffer size check removed.
621+
///
622+
/// SAFETY: The caller is expected to provide `output` buffer
623+
/// large enough to contain correct number of bytes. For streaming
624+
/// ciphers the output buffer can be empty, for block ciphers the
625+
/// output buffer should be at least as big as the block.
626+
#[corresponds(EVP_CipherFinal)]
627+
pub unsafe fn cipher_final_unchecked(
628+
&mut self,
629+
output: &mut [u8],
630+
) -> Result<usize, ErrorStack> {
652631
let mut outl = 0;
653-
unsafe {
654-
cvt(ffi::EVP_CipherFinal(
655-
self.as_ptr(),
656-
output.as_mut_ptr(),
657-
&mut outl,
658-
))?;
659-
}
632+
633+
cvt(ffi::EVP_CipherFinal(
634+
self.as_ptr(),
635+
output.as_mut_ptr(),
636+
&mut outl,
637+
))?;
660638

661639
Ok(outl as usize)
662640
}
@@ -757,75 +735,6 @@ mod test {
757735
aes_128_cbc(cipher);
758736
}
759737

760-
#[test]
761-
#[cfg(ossl110)]
762-
fn partial_block_updates() {
763-
test_block_cipher_for_partial_block_updates(Cipher::aes_128_cbc());
764-
test_block_cipher_for_partial_block_updates(Cipher::aes_256_cbc());
765-
test_block_cipher_for_partial_block_updates(Cipher::des_ede3_cbc());
766-
}
767-
768-
#[cfg(ossl110)]
769-
fn test_block_cipher_for_partial_block_updates(cipher: &'static CipherRef) {
770-
let mut key = vec![0; cipher.key_length()];
771-
rand_bytes(&mut key).unwrap();
772-
let mut iv = vec![0; cipher.iv_length()];
773-
rand_bytes(&mut iv).unwrap();
774-
775-
let mut ctx = CipherCtx::new().unwrap();
776-
777-
ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv))
778-
.unwrap();
779-
ctx.set_padding(false);
780-
781-
let block_size = cipher.block_size();
782-
assert!(block_size > 1, "Need a block cipher, not a stream cipher");
783-
784-
// update cipher with non-full block
785-
// expect no output until a block is complete
786-
let outlen = ctx
787-
.cipher_update(&vec![0; block_size - 1], Some(&mut [0; 0]))
788-
.unwrap();
789-
assert_eq!(0, outlen);
790-
791-
// update cipher with missing bytes from the previous block
792-
// and one additional block, output should contain two blocks
793-
let mut two_blocks = vec![0; block_size * 2];
794-
let outlen = ctx
795-
.cipher_update(&vec![0; block_size + 1], Some(&mut two_blocks))
796-
.unwrap();
797-
assert_eq!(block_size * 2, outlen);
798-
799-
ctx.cipher_final_vec(&mut vec![0; 0]).unwrap();
800-
801-
// try to decrypt
802-
ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv))
803-
.unwrap();
804-
ctx.set_padding(false);
805-
806-
// update cipher with non-full block
807-
// expect no output until a block is complete
808-
let outlen = ctx
809-
.cipher_update(&two_blocks[0..block_size - 1], Some(&mut [0; 0]))
810-
.unwrap();
811-
assert_eq!(0, outlen);
812-
813-
// update cipher with missing bytes from the previous block
814-
// and one additional block, output should contain two blocks
815-
let mut two_blocks_decrypted = vec![0; block_size * 2];
816-
let outlen = ctx
817-
.cipher_update(
818-
&two_blocks[block_size - 1..],
819-
Some(&mut two_blocks_decrypted),
820-
)
821-
.unwrap();
822-
assert_eq!(block_size * 2, outlen);
823-
824-
ctx.cipher_final_vec(&mut vec![0; 0]).unwrap();
825-
// check if the decrypted blocks are the same as input (all zeros)
826-
assert_eq!(two_blocks_decrypted, vec![0; block_size * 2]);
827-
}
828-
829738
#[test]
830739
fn test_stream_ciphers() {
831740
test_stream_cipher(Cipher::aes_192_ctr());
@@ -894,43 +803,19 @@ mod test {
894803
}
895804

896805
#[test]
897-
#[should_panic(expected = "Output buffer size should be at least 16 bytes.")]
898-
#[cfg(ossl110)]
899-
fn full_block_updates_aes_128() {
900-
output_buffer_too_small(Cipher::aes_128_cbc());
901-
}
902-
903-
#[test]
904-
#[should_panic(expected = "Output buffer size should be at least 16 bytes.")]
905-
#[cfg(ossl110)]
906-
fn full_block_updates_aes_256() {
907-
output_buffer_too_small(Cipher::aes_256_cbc());
908-
}
909-
910-
#[test]
911-
#[should_panic(expected = "Output buffer size should be at least 8 bytes.")]
912-
#[cfg(ossl110)]
913-
fn full_block_updates_3des() {
914-
output_buffer_too_small(Cipher::des_ede3_cbc());
915-
}
916-
917-
#[test]
918-
#[should_panic(expected = "Output buffer size should be at least 32 bytes.")]
919-
#[cfg(not(ossl110))]
806+
#[should_panic(expected = "Output buffer size should be at least 33 bytes.")]
920807
fn full_block_updates_aes_128() {
921808
output_buffer_too_small(Cipher::aes_128_cbc());
922809
}
923810

924811
#[test]
925-
#[should_panic(expected = "Output buffer size should be at least 32 bytes.")]
926-
#[cfg(not(ossl110))]
812+
#[should_panic(expected = "Output buffer size should be at least 33 bytes.")]
927813
fn full_block_updates_aes_256() {
928814
output_buffer_too_small(Cipher::aes_256_cbc());
929815
}
930816

931817
#[test]
932-
#[should_panic(expected = "Output buffer size should be at least 16 bytes.")]
933-
#[cfg(not(ossl110))]
818+
#[should_panic(expected = "Output buffer size should be at least 17 bytes.")]
934819
fn full_block_updates_3des() {
935820
output_buffer_too_small(Cipher::des_ede3_cbc());
936821
}

0 commit comments

Comments
 (0)