cipher/
stream.rs

1//! Traits which define functionality of stream ciphers.
2//!
3//! See [RustCrypto/stream-ciphers](https://github.com/RustCrypto/stream-ciphers)
4//! for ciphers implementation.
5
6use crate::errors::{LoopError, OverflowError};
7use core::convert::{TryFrom, TryInto};
8
9/// Synchronous stream cipher core trait.
10pub trait StreamCipher {
11    /// Apply keystream to the data.
12    ///
13    /// It will XOR generated keystream with the data, which can be both
14    /// encryption and decryption.
15    ///
16    /// # Panics
17    /// If end of the keystream will be reached with the given data length,
18    /// method will panic without modifying the provided `data`.
19    #[inline]
20    fn apply_keystream(&mut self, data: &mut [u8]) {
21        self.try_apply_keystream(data).unwrap();
22    }
23
24    /// Apply keystream to the data, but return an error if end of a keystream
25    /// will be reached.
26    ///
27    /// If end of the keystream will be achieved with the given data length,
28    /// method will return `Err(LoopError)` without modifying provided `data`.
29    fn try_apply_keystream(&mut self, data: &mut [u8]) -> Result<(), LoopError>;
30}
31
32/// Trait for seekable stream ciphers.
33///
34/// Methods of this trait are generic over the [`SeekNum`] trait, which is
35/// implemented for primitive numeric types, i.e.: `i/u8`, `i/u16`, `i/u32`,
36/// `i/u64`, `i/u128`, and `i/usize`.
37pub trait StreamCipherSeek {
38    /// Try to get current keystream position
39    ///
40    /// Returns [`LoopError`] if position can not be represented by type `T`
41    fn try_current_pos<T: SeekNum>(&self) -> Result<T, OverflowError>;
42
43    /// Try to seek to the given position
44    ///
45    /// Returns [`LoopError`] if provided position value is bigger than
46    /// keystream length.
47    fn try_seek<T: SeekNum>(&mut self, pos: T) -> Result<(), LoopError>;
48
49    /// Get current keystream position
50    ///
51    /// # Panics
52    /// If position can not be represented by type `T`
53    fn current_pos<T: SeekNum>(&self) -> T {
54        self.try_current_pos().unwrap()
55    }
56
57    /// Seek to the given position
58    ///
59    /// # Panics
60    /// If provided position value is bigger than keystream leangth
61    fn seek<T: SeekNum>(&mut self, pos: T) {
62        self.try_seek(pos).unwrap()
63    }
64}
65
66/// Asynchronous stream cipher core trait.
67pub trait AsyncStreamCipher {
68    /// Encrypt data in place.
69    fn encrypt(&mut self, data: &mut [u8]);
70
71    /// Decrypt data in place.
72    fn decrypt(&mut self, data: &mut [u8]);
73}
74
75impl<C: StreamCipher> StreamCipher for &mut C {
76    #[inline]
77    fn apply_keystream(&mut self, data: &mut [u8]) {
78        C::apply_keystream(self, data);
79    }
80
81    #[inline]
82    fn try_apply_keystream(&mut self, data: &mut [u8]) -> Result<(), LoopError> {
83        C::try_apply_keystream(self, data)
84    }
85}
86
87/// Trait implemented for numeric types which can be used with the
88/// [`StreamCipherSeek`] trait.
89///
90/// This trait is implemented for primitive numeric types, i.e. `i/u8`,
91/// `u16`, `u32`, `u64`, `u128`, `usize`, and `i32`. It is not intended
92/// to be implemented in third-party crates.
93#[rustfmt::skip]
94pub trait SeekNum:
95    Sized
96    + TryInto<u8> + TryFrom<u8> + TryInto<i8> + TryFrom<i8>
97    + TryInto<u16> + TryFrom<u16> + TryInto<i16> + TryFrom<i16>
98    + TryInto<u32> + TryFrom<u32> + TryInto<i32> + TryFrom<i32>
99    + TryInto<u64> + TryFrom<u64> + TryInto<i64> + TryFrom<i64>
100    + TryInto<u128> + TryFrom<u128> + TryInto<i128> + TryFrom<i128>
101    + TryInto<usize> + TryFrom<usize> + TryInto<isize> + TryFrom<isize>
102{
103    /// Try to get position for block number `block`, byte position inside
104    /// block `byte`, and block size `bs`.
105    fn from_block_byte<T: SeekNum>(block: T, byte: u8, bs: u8) -> Result<Self, OverflowError>;
106
107    /// Try to get block number and bytes position for given block size `bs`.
108    fn to_block_byte<T: SeekNum>(self, bs: u8) -> Result<(T, u8), OverflowError>;
109}
110
111macro_rules! impl_seek_num {
112    {$($t:ty )*} => {
113        $(
114            impl SeekNum for $t {
115                fn from_block_byte<T: TryInto<Self>>(block: T, byte: u8, bs: u8) -> Result<Self, OverflowError> {
116                    debug_assert!(byte < bs);
117                    let block = block.try_into().map_err(|_| OverflowError)?;
118                    let pos = block.checked_mul(bs as Self).ok_or(OverflowError)? + (byte as Self);
119                    Ok(pos)
120                }
121
122                fn to_block_byte<T: TryFrom<Self>>(self, bs: u8) -> Result<(T, u8), OverflowError> {
123                    let bs = bs as Self;
124                    let byte = self % bs;
125                    let block = T::try_from(self/bs).map_err(|_| OverflowError)?;
126                    Ok((block, byte as u8))
127                }
128            }
129        )*
130    };
131}
132
133impl_seek_num! { u8 u16 u32 u64 u128 usize i32 }