Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cipher/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ hex-literal = "1"
alloc = []
block-padding = ["inout/block-padding"]
stream-wrapper = ["block-buffer"]
# Enable random key and IV generation methods
getrandom = ["common/getrandom"]
rand_core = ["common/rand_core"]
dev = ["blobby"]
zeroize = ["dep:zeroize", "common/zeroize", "block-buffer?/zeroize"]

[lints]
workspace = true

[package.metadata.docs.rs]
all-features = true
22 changes: 16 additions & 6 deletions cipher/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub trait BlockCipherEncrypt: BlockSizeUser + Sized {

/// Encrypt blocks buffer-to-buffer.
///
/// # Errors
/// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
/// have different lengths.
#[inline]
Expand Down Expand Up @@ -123,6 +124,7 @@ pub trait BlockCipherDecrypt: BlockSizeUser {

/// Decrypt blocks buffer-to-buffer.
///
/// # Errors
/// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
/// have different lengths.
#[inline]
Expand Down Expand Up @@ -192,6 +194,7 @@ pub trait BlockModeEncrypt: BlockSizeUser + Sized {

/// Encrypt blocks buffer-to-buffer.
///
/// # Errors
/// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
/// have different lengths.
#[inline]
Expand All @@ -206,6 +209,7 @@ pub trait BlockModeEncrypt: BlockSizeUser + Sized {

/// Pad input and encrypt. Returns resulting ciphertext slice.
///
/// # Errors
/// Returns [`PadError`] if length of output buffer is not sufficient.
#[cfg(feature = "block-padding")]
#[inline]
Expand All @@ -223,6 +227,7 @@ pub trait BlockModeEncrypt: BlockSizeUser + Sized {

/// Pad input and encrypt in-place. Returns resulting ciphertext slice.
///
/// # Errors
/// Returns [`PadError`] if length of output buffer is not sufficient.
#[cfg(feature = "block-padding")]
#[inline]
Expand All @@ -233,6 +238,7 @@ pub trait BlockModeEncrypt: BlockSizeUser + Sized {

/// Pad input and encrypt buffer-to-buffer. Returns resulting ciphertext slice.
///
/// # Errors
/// Returns [`PadError`] if length of output buffer is not sufficient.
#[cfg(feature = "block-padding")]
#[inline]
Expand Down Expand Up @@ -262,12 +268,11 @@ pub trait BlockModeEncrypt: BlockSizeUser + Sized {

let pad_type_id = TypeId::of::<P>();
let buf_blocks_len = if pad_type_id == TypeId::of::<NoPadding>() {
if msg_len % bs != 0 {
panic!(
"NoPadding is used with a {msg_len}‑byte message,
which is not a multiple of the {bs}‑byte cipher block size"
);
}
assert!(
msg_len % bs == 0,
"NoPadding is used with a {msg_len}‑byte message,
which is not a multiple of the {bs}‑byte cipher block size"
);
msg_len / bs
} else if pad_type_id == TypeId::of::<ZeroPadding>() {
msg_len.div_ceil(bs)
Expand Down Expand Up @@ -329,6 +334,7 @@ pub trait BlockModeDecrypt: BlockSizeUser + Sized {

/// Decrypt blocks buffer-to-buffer.
///
/// # Errors
/// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks`
/// have different lengths.
#[inline]
Expand All @@ -343,6 +349,7 @@ pub trait BlockModeDecrypt: BlockSizeUser + Sized {

/// Decrypt input and unpad it. Returns resulting plaintext slice.
///
/// # Errors
/// Returns [`block_padding::Error`] if padding is malformed or if input length is
/// not multiple of `Self::BlockSize`.
#[cfg(feature = "block-padding")]
Expand All @@ -361,6 +368,7 @@ pub trait BlockModeDecrypt: BlockSizeUser + Sized {

/// Decrypt input and unpad it in-place. Returns resulting plaintext slice.
///
/// # Errors
/// Returns [`block_padding::Error`] if padding is malformed or if input length is
/// not multiple of `Self::BlockSize`.
#[cfg(feature = "block-padding")]
Expand All @@ -372,6 +380,7 @@ pub trait BlockModeDecrypt: BlockSizeUser + Sized {
/// Decrypt input and unpad it buffer-to-buffer. Returns resulting
/// plaintext slice.
///
/// # Errors
/// Returns [`block_padding::Error`] if padding is malformed or if input length is
/// not multiple of `Self::BlockSize`.
#[cfg(feature = "block-padding")]
Expand All @@ -393,6 +402,7 @@ pub trait BlockModeDecrypt: BlockSizeUser + Sized {
/// Decrypt input and unpad it in a newly allocated Vec. Returns resulting
/// plaintext `Vec`.
///
/// # Errors
/// Returns [`block_padding::Error`] if padding is malformed or if input length is
/// not multiple of `Self::BlockSize`.
#[cfg(all(feature = "block-padding", feature = "alloc"))]
Expand Down
4 changes: 4 additions & 0 deletions cipher/src/dev/block_cipher.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Development-related functionality for block ciphers

#![allow(clippy::missing_errors_doc)]

use crate::{Block, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};

/// Block cipher test vector
Expand All @@ -24,6 +26,7 @@ fn encrypt_test_inner<C: BlockCipherEncrypt>(
return Err("single block encryption failure");
}

#[allow(clippy::cast_possible_truncation)]
let mut blocks1: [Block<C>; 101] = core::array::from_fn(|i| {
let mut block = pt.clone();
block[0] ^= i as u8;
Expand Down Expand Up @@ -54,6 +57,7 @@ fn decrypt_test_inner<C: BlockCipherDecrypt>(
return Err("single block decryption failure");
}

#[allow(clippy::cast_possible_truncation)]
let mut blocks1: [Block<C>; 101] = core::array::from_fn(|i| {
let mut block = ct.clone();
block[0] ^= i as u8;
Expand Down
2 changes: 2 additions & 0 deletions cipher/src/dev/block_mode.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Development-related functionality for block modes

#![allow(clippy::missing_errors_doc)]

use crate::{BlockModeDecrypt, BlockModeEncrypt, KeyIvInit, inout::InOutBuf};

const MAX_MSG_LEN: usize = 1 << 12;
Expand Down
3 changes: 3 additions & 0 deletions cipher/src/dev/stream.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
//! Development-related functionality for stream ciphers

#![allow(clippy::missing_errors_doc)]

use crate::{KeyIvInit, StreamCipher};

/// Stream cipher test vector
Expand Down
6 changes: 0 additions & 6 deletions cipher/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
)]
#![warn(
missing_docs,
rust_2018_idioms,
unused_lifetimes,
missing_debug_implementations
)]
#![forbid(unsafe_code)]

#[cfg(feature = "alloc")]
Expand Down
65 changes: 52 additions & 13 deletions cipher/src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ pub trait AsyncStreamCipher: Sized {
}

/// Encrypt data from buffer to buffer.
///
/// # Errors
/// Returns [`NotEqualError`] if provided `in_buf` and `out_buf` have different lengths.
fn encrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), NotEqualError>
where
Self: BlockModeEncrypt,
Expand All @@ -78,6 +81,9 @@ pub trait AsyncStreamCipher: Sized {
}

/// Decrypt data from buffer to buffer.
///
/// # Errors
/// Returns [`NotEqualError`] if provided `in_buf` and `out_buf` have different lengths.
fn decrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), NotEqualError>
where
Self: BlockModeDecrypt,
Expand Down Expand Up @@ -110,42 +116,58 @@ pub trait AsyncStreamCipher: Sized {
/// and the seeking methods defined in the [`StreamCipherSeek`] trait.
pub trait StreamCipher {
/// Check that the cipher can generate a keystream with a length of `data_len` bytes.
///
/// # Errors
/// Returns [`StreamCipherError`] in the event it cannot.
fn check_remaining(&self, data_len: usize) -> Result<(), StreamCipherError>;

/// Apply keystream to `inout` without checking for keystream repetition.
///
/// # WARNING
/// <div><class = "warning">
/// <b>WARNING<b>
///
/// This method should be used with extreme caution! Triggering keystream repetition can expose
/// the stream cipher to chosen plaintext attacks.
/// </div>
fn unchecked_apply_keystream_inout(&mut self, buf: InOutBuf<'_, '_, u8>);

/// Apply keystream to `buf` without checking for keystream repetition.
///
/// # WARNING
/// <div><class = "warning">
/// <b>WARNING<b>
///
/// This method should be used with extreme caution! Triggering keystream repetition can expose
/// the stream cipher to chosen plaintext attacks.
/// </div>
fn unchecked_write_keystream(&mut self, buf: &mut [u8]);

/// Apply keystream to data behind `buf` without checking for keystream repetition.
///
/// # WARNING
/// <div><class = "warning">
/// <b>WARNING<b>
///
/// This method should be used with extreme caution! Triggering keystream repetition can expose
/// the stream cipher to chosen plaintext attacks.
/// </div>
#[inline]
fn unchecked_apply_keystream(&mut self, buf: &mut [u8]) {
self.unchecked_apply_keystream_inout(buf.into())
self.unchecked_apply_keystream_inout(buf.into());
}

/// Apply keystream to data buffer-to-buffer without checking for keystream repetition.
///
/// It will XOR generated keystream with data from the `input` buffer
/// and will write result to the `output` buffer.
///
/// # Errors
/// Returns [`NotEqualError`] if the `input` and `output` buffers have different lengths.
///
/// # WARNING
/// <div><class = "warning">
/// <b>WARNING<b>
///
/// This method should be used with extreme caution! Triggering keystream repetition can expose
/// the stream cipher to chosen plaintext attacks.
/// </div>
#[inline]
fn unchecked_apply_keystream_b2b(
&mut self,
Expand All @@ -159,6 +181,7 @@ pub trait StreamCipher {

/// Apply keystream to `inout` data.
///
/// # Errors
/// If the end of the keystream is reached with the given buffer length,
/// the method will return [`StreamCipherError`] without modifying `buf`.
fn try_apply_keystream_inout(
Expand All @@ -172,6 +195,7 @@ pub trait StreamCipher {

/// Apply keystream to data behind `buf`.
///
/// # Errors
/// If the end of the keystream is reached with the given buffer length,
/// the method will return [`StreamCipherError`] without modifying `buf`.
#[inline]
Expand All @@ -184,6 +208,7 @@ pub trait StreamCipher {
/// It will XOR generated keystream with data from the `input` buffer
/// and will write result to the `output` buffer.
///
/// # Errors
/// Returns [`StreamCipherError`] without modifying the buffers if the `input` and `output`
/// buffers have different lengths, or if the end of the keystream is reached with
/// the given data length.
Expand All @@ -200,6 +225,7 @@ pub trait StreamCipher {

/// Write keystream to `buf`.
///
/// # Errors
/// If the end of the keystream is reached with the given buffer length,
/// the method will return [`StreamCipherError`] without modifying `buf`.
#[inline]
Expand All @@ -218,7 +244,8 @@ pub trait StreamCipher {
/// If the end of the keystream is reached with the given buffer length.
#[inline]
fn apply_keystream_inout(&mut self, buf: InOutBuf<'_, '_, u8>) {
self.try_apply_keystream_inout(buf).unwrap();
self.try_apply_keystream_inout(buf)
.expect("end of keystream reached");
}

/// Apply keystream to data in-place.
Expand All @@ -230,7 +257,8 @@ pub trait StreamCipher {
/// If the end of the keystream is reached with the given buffer length.
#[inline]
fn apply_keystream(&mut self, buf: &mut [u8]) {
self.try_apply_keystream(buf).unwrap();
self.try_apply_keystream(buf)
.expect("end of keystream reached");
}

/// Apply keystream to data buffer-to-buffer.
Expand All @@ -246,7 +274,7 @@ pub trait StreamCipher {
let Ok(buf) = InOutBuf::new(input, output) else {
panic!("Lengths of input and output buffers are not equal to each other!");
};
self.apply_keystream_inout(buf)
self.apply_keystream_inout(buf);
}

/// Write keystream to `buf`.
Expand All @@ -255,7 +283,8 @@ pub trait StreamCipher {
/// If the end of the keystream is reached with the given buffer length.
#[inline]
fn write_keystream(&mut self, buf: &mut [u8]) {
self.try_write_keystream(buf).unwrap();
self.try_write_keystream(buf)
.expect("end of keystream reached");
}
}

Expand All @@ -266,11 +295,13 @@ pub trait StreamCipher {
pub trait StreamCipherSeek {
/// Try to get current keystream position in bytes.
///
/// # Errors
/// Returns [`OverflowError`] if the position value can not be represented by type `T`.
fn try_current_pos<T: SeekNum>(&self) -> Result<T, OverflowError>;

/// Try to seek to the provided position in bytes.
///
/// # Errors
/// Returns [`StreamCipherError`] if the position value is bigger than keystream length.
fn try_seek<T: SeekNum>(&mut self, pos: T) -> Result<(), StreamCipherError>;

Expand All @@ -279,15 +310,17 @@ pub trait StreamCipherSeek {
/// # Panics
/// If the position value can not be represented by type `T`.
fn current_pos<T: SeekNum>(&self) -> T {
self.try_current_pos().unwrap()
self.try_current_pos()
.expect("position cannot be represented by `T`")
}

/// Seek to the provided keystream position in bytes.
///
/// # Panics
/// If the position value is bigger than keystream length.
fn seek<T: SeekNum>(&mut self, pos: T) {
self.try_seek(pos).unwrap()
self.try_seek(pos)
.expect("position value bigger than keystream length");
}
}

Expand All @@ -299,12 +332,12 @@ impl<C: StreamCipher> StreamCipher for &mut C {

#[inline]
fn unchecked_apply_keystream_inout(&mut self, buf: InOutBuf<'_, '_, u8>) {
C::unchecked_apply_keystream_inout(self, buf)
C::unchecked_apply_keystream_inout(self, buf);
}

#[inline]
fn unchecked_write_keystream(&mut self, buf: &mut [u8]) {
C::unchecked_write_keystream(self, buf)
C::unchecked_write_keystream(self, buf);
}
}

Expand All @@ -316,13 +349,19 @@ impl<C: StreamCipher> StreamCipher for &mut C {
pub trait SeekNum: Sized {
/// Try to get position for block number `block`, byte position inside
/// block `byte`, and block size `bs`.
///
/// # Errors
/// Returns [`OverflowError`] in the event of a counter overflow.
fn from_block_byte<T: StreamCipherCounter>(
block: T,
byte: u8,
bs: u8,
) -> Result<Self, OverflowError>;

/// Try to get block number and bytes position for given block size `bs`.
///
/// # Errors
/// Returns [`OverflowError`] in the event of a counter overflow.
fn into_block_byte<T: StreamCipherCounter>(self, bs: u8) -> Result<(T, u8), OverflowError>;
}

Expand Down
Loading