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 }