| 1 | use crate::{ParBlocks, ParBlocksSizeUser, StreamCipherError}; |
| 2 | use crypto_common::{ |
| 3 | generic_array::{ArrayLength, GenericArray}, |
| 4 | typenum::Unsigned, |
| 5 | Block, BlockSizeUser, |
| 6 | }; |
| 7 | use inout::{InOut, InOutBuf}; |
| 8 | |
| 9 | /// Trait implemented by stream cipher backends. |
| 10 | pub trait StreamBackend: ParBlocksSizeUser { |
| 11 | /// Generate keystream block. |
| 12 | fn gen_ks_block(&mut self, block: &mut Block<Self>); |
| 13 | |
| 14 | /// Generate keystream blocks in parallel. |
| 15 | #[inline (always)] |
| 16 | fn gen_par_ks_blocks(&mut self, blocks: &mut ParBlocks<Self>) { |
| 17 | for block: &mut GenericArray::BlockSize> in blocks { |
| 18 | self.gen_ks_block(block); |
| 19 | } |
| 20 | } |
| 21 | |
| 22 | /// Generate keystream blocks. Length of the buffer MUST be smaller |
| 23 | /// than `Self::ParBlocksSize`. |
| 24 | #[inline (always)] |
| 25 | fn gen_tail_blocks(&mut self, blocks: &mut [Block<Self>]) { |
| 26 | assert!(blocks.len() < Self::ParBlocksSize::USIZE); |
| 27 | for block: &mut GenericArray::BlockSize> in blocks { |
| 28 | self.gen_ks_block(block); |
| 29 | } |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | /// Trait for [`StreamBackend`] users. |
| 34 | /// |
| 35 | /// This trait is used to define rank-2 closures. |
| 36 | pub trait StreamClosure: BlockSizeUser { |
| 37 | /// Execute closure with the provided stream cipher backend. |
| 38 | fn call<B: StreamBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B); |
| 39 | } |
| 40 | |
| 41 | /// Block-level synchronous stream ciphers. |
| 42 | pub trait StreamCipherCore: BlockSizeUser + Sized { |
| 43 | /// Return number of remaining blocks before cipher wraps around. |
| 44 | /// |
| 45 | /// Returns `None` if number of remaining blocks can not be computed |
| 46 | /// (e.g. in ciphers based on the sponge construction) or it's too big |
| 47 | /// to fit into `usize`. |
| 48 | fn remaining_blocks(&self) -> Option<usize>; |
| 49 | |
| 50 | /// Process data using backend provided to the rank-2 closure. |
| 51 | fn process_with_backend(&mut self, f: impl StreamClosure<BlockSize = Self::BlockSize>); |
| 52 | |
| 53 | /// Write keystream block. |
| 54 | /// |
| 55 | /// WARNING: this method does not check number of remaining blocks! |
| 56 | #[inline ] |
| 57 | fn write_keystream_block(&mut self, block: &mut Block<Self>) { |
| 58 | self.process_with_backend(WriteBlockCtx { block }); |
| 59 | } |
| 60 | |
| 61 | /// Write keystream blocks. |
| 62 | /// |
| 63 | /// WARNING: this method does not check number of remaining blocks! |
| 64 | #[inline ] |
| 65 | fn write_keystream_blocks(&mut self, blocks: &mut [Block<Self>]) { |
| 66 | self.process_with_backend(WriteBlocksCtx { blocks }); |
| 67 | } |
| 68 | |
| 69 | /// Apply keystream block. |
| 70 | /// |
| 71 | /// WARNING: this method does not check number of remaining blocks! |
| 72 | #[inline ] |
| 73 | fn apply_keystream_block_inout(&mut self, block: InOut<'_, '_, Block<Self>>) { |
| 74 | self.process_with_backend(ApplyBlockCtx { block }); |
| 75 | } |
| 76 | |
| 77 | /// Apply keystream blocks. |
| 78 | /// |
| 79 | /// WARNING: this method does not check number of remaining blocks! |
| 80 | #[inline ] |
| 81 | fn apply_keystream_blocks(&mut self, blocks: &mut [Block<Self>]) { |
| 82 | self.process_with_backend(ApplyBlocksCtx { |
| 83 | blocks: blocks.into(), |
| 84 | }); |
| 85 | } |
| 86 | |
| 87 | /// Apply keystream blocks. |
| 88 | /// |
| 89 | /// WARNING: this method does not check number of remaining blocks! |
| 90 | #[inline ] |
| 91 | fn apply_keystream_blocks_inout(&mut self, blocks: InOutBuf<'_, '_, Block<Self>>) { |
| 92 | self.process_with_backend(ApplyBlocksCtx { blocks }); |
| 93 | } |
| 94 | |
| 95 | /// Try to apply keystream to data not divided into blocks. |
| 96 | /// |
| 97 | /// Consumes cipher since it may consume final keystream block only |
| 98 | /// partially. |
| 99 | /// |
| 100 | /// Returns an error if number of remaining blocks is not sufficient |
| 101 | /// for processing the input data. |
| 102 | #[inline ] |
| 103 | fn try_apply_keystream_partial( |
| 104 | mut self, |
| 105 | mut buf: InOutBuf<'_, '_, u8>, |
| 106 | ) -> Result<(), StreamCipherError> { |
| 107 | if let Some(rem) = self.remaining_blocks() { |
| 108 | let blocks = if buf.len() % Self::BlockSize::USIZE == 0 { |
| 109 | buf.len() % Self::BlockSize::USIZE |
| 110 | } else { |
| 111 | buf.len() % Self::BlockSize::USIZE + 1 |
| 112 | }; |
| 113 | if blocks > rem { |
| 114 | return Err(StreamCipherError); |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | if buf.len() > Self::BlockSize::USIZE { |
| 119 | let (blocks, tail) = buf.into_chunks(); |
| 120 | self.apply_keystream_blocks_inout(blocks); |
| 121 | buf = tail; |
| 122 | } |
| 123 | let n = buf.len(); |
| 124 | if n == 0 { |
| 125 | return Ok(()); |
| 126 | } |
| 127 | let mut block = Block::<Self>::default(); |
| 128 | block[..n].copy_from_slice(buf.get_in()); |
| 129 | let t = InOutBuf::from_mut(&mut block); |
| 130 | self.apply_keystream_blocks_inout(t); |
| 131 | buf.get_out().copy_from_slice(&block[..n]); |
| 132 | Ok(()) |
| 133 | } |
| 134 | |
| 135 | /// Try to apply keystream to data not divided into blocks. |
| 136 | /// |
| 137 | /// Consumes cipher since it may consume final keystream block only |
| 138 | /// partially. |
| 139 | /// |
| 140 | /// # Panics |
| 141 | /// If number of remaining blocks is not sufficient for processing the |
| 142 | /// input data. |
| 143 | #[inline ] |
| 144 | fn apply_keystream_partial(self, buf: InOutBuf<'_, '_, u8>) { |
| 145 | self.try_apply_keystream_partial(buf).unwrap() |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | // note: unfortunately, currently we can not write blanket impls of |
| 150 | // `BlockEncryptMut` and `BlockDecryptMut` for `T: StreamCipherCore` |
| 151 | // since it requires mutually exclusive traits, see: |
| 152 | // https://github.com/rust-lang/rfcs/issues/1053 |
| 153 | |
| 154 | /// Counter type usable with [`StreamCipherCore`]. |
| 155 | /// |
| 156 | /// This trait is implemented for `i32`, `u32`, `u64`, `u128`, and `usize`. |
| 157 | /// It's not intended to be implemented in third-party crates, but doing so |
| 158 | /// is not forbidden. |
| 159 | pub trait Counter: |
| 160 | TryFrom<i32> |
| 161 | + TryFrom<u32> |
| 162 | + TryFrom<u64> |
| 163 | + TryFrom<u128> |
| 164 | + TryFrom<usize> |
| 165 | + TryInto<i32> |
| 166 | + TryInto<u32> |
| 167 | + TryInto<u64> |
| 168 | + TryInto<u128> |
| 169 | + TryInto<usize> |
| 170 | { |
| 171 | } |
| 172 | |
| 173 | /// Block-level seeking trait for stream ciphers. |
| 174 | pub trait StreamCipherSeekCore: StreamCipherCore { |
| 175 | /// Counter type used inside stream cipher. |
| 176 | type Counter: Counter; |
| 177 | |
| 178 | /// Get current block position. |
| 179 | fn get_block_pos(&self) -> Self::Counter; |
| 180 | |
| 181 | /// Set block position. |
| 182 | fn set_block_pos(&mut self, pos: Self::Counter); |
| 183 | } |
| 184 | |
| 185 | macro_rules! impl_counter { |
| 186 | {$($t:ty )*} => { |
| 187 | $( impl Counter for $t { } )* |
| 188 | }; |
| 189 | } |
| 190 | |
| 191 | impl_counter! { u32 u64 u128 } |
| 192 | |
| 193 | /// Partition buffer into 2 parts: buffer of arrays and tail. |
| 194 | /// |
| 195 | /// In case if `N` is less or equal to 1, buffer of arrays has length |
| 196 | /// of zero and tail is equal to `self`. |
| 197 | #[inline ] |
| 198 | fn into_chunks<T, N: ArrayLength<T>>(buf: &mut [T]) -> (&mut [GenericArray<T, N>], &mut [T]) { |
| 199 | use core::slice; |
| 200 | if N::USIZE <= 1 { |
| 201 | return (&mut [], buf); |
| 202 | } |
| 203 | let chunks_len: usize = buf.len() / N::USIZE; |
| 204 | let tail_pos: usize = N::USIZE * chunks_len; |
| 205 | let tail_len: usize = buf.len() - tail_pos; |
| 206 | unsafe { |
| 207 | let ptr: *mut T = buf.as_mut_ptr(); |
| 208 | let chunks: &mut [GenericArray] = slice::from_raw_parts_mut(data:ptr as *mut GenericArray<T, N>, chunks_len); |
| 209 | let tail: &mut [T] = slice::from_raw_parts_mut(data:ptr.add(count:tail_pos), tail_len); |
| 210 | (chunks, tail) |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | struct WriteBlockCtx<'a, BS: ArrayLength<u8>> { |
| 215 | block: &'a mut Block<Self>, |
| 216 | } |
| 217 | impl<'a, BS: ArrayLength<u8>> BlockSizeUser for WriteBlockCtx<'a, BS> { |
| 218 | type BlockSize = BS; |
| 219 | } |
| 220 | impl<'a, BS: ArrayLength<u8>> StreamClosure for WriteBlockCtx<'a, BS> { |
| 221 | #[inline (always)] |
| 222 | fn call<B: StreamBackend<BlockSize = BS>>(self, backend: &mut B) { |
| 223 | backend.gen_ks_block(self.block); |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | struct WriteBlocksCtx<'a, BS: ArrayLength<u8>> { |
| 228 | blocks: &'a mut [Block<Self>], |
| 229 | } |
| 230 | impl<'a, BS: ArrayLength<u8>> BlockSizeUser for WriteBlocksCtx<'a, BS> { |
| 231 | type BlockSize = BS; |
| 232 | } |
| 233 | impl<'a, BS: ArrayLength<u8>> StreamClosure for WriteBlocksCtx<'a, BS> { |
| 234 | #[inline (always)] |
| 235 | fn call<B: StreamBackend<BlockSize = BS>>(self, backend: &mut B) { |
| 236 | if B::ParBlocksSize::USIZE > 1 { |
| 237 | let (chunks: &mut [GenericArray, …>], tail: &mut [GenericArray]) = into_chunks::<_, B::ParBlocksSize>(self.blocks); |
| 238 | for chunk: &mut GenericArray, …> in chunks { |
| 239 | backend.gen_par_ks_blocks(chunk); |
| 240 | } |
| 241 | backend.gen_tail_blocks(tail); |
| 242 | } else { |
| 243 | for block: &'a mut GenericArray in self.blocks { |
| 244 | backend.gen_ks_block(block); |
| 245 | } |
| 246 | } |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | struct ApplyBlockCtx<'inp, 'out, BS: ArrayLength<u8>> { |
| 251 | block: InOut<'inp, 'out, Block<Self>>, |
| 252 | } |
| 253 | |
| 254 | impl<'inp, 'out, BS: ArrayLength<u8>> BlockSizeUser for ApplyBlockCtx<'inp, 'out, BS> { |
| 255 | type BlockSize = BS; |
| 256 | } |
| 257 | |
| 258 | impl<'inp, 'out, BS: ArrayLength<u8>> StreamClosure for ApplyBlockCtx<'inp, 'out, BS> { |
| 259 | #[inline (always)] |
| 260 | fn call<B: StreamBackend<BlockSize = BS>>(mut self, backend: &mut B) { |
| 261 | let mut t: GenericArray = Default::default(); |
| 262 | backend.gen_ks_block(&mut t); |
| 263 | self.block.xor_in2out(&t); |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | struct ApplyBlocksCtx<'inp, 'out, BS: ArrayLength<u8>> { |
| 268 | blocks: InOutBuf<'inp, 'out, Block<Self>>, |
| 269 | } |
| 270 | |
| 271 | impl<'inp, 'out, BS: ArrayLength<u8>> BlockSizeUser for ApplyBlocksCtx<'inp, 'out, BS> { |
| 272 | type BlockSize = BS; |
| 273 | } |
| 274 | |
| 275 | impl<'inp, 'out, BS: ArrayLength<u8>> StreamClosure for ApplyBlocksCtx<'inp, 'out, BS> { |
| 276 | #[inline (always)] |
| 277 | #[allow (clippy::needless_range_loop)] |
| 278 | fn call<B: StreamBackend<BlockSize = BS>>(self, backend: &mut B) { |
| 279 | if B::ParBlocksSize::USIZE > 1 { |
| 280 | let (chunks, mut tail) = self.blocks.into_chunks::<B::ParBlocksSize>(); |
| 281 | for mut chunk in chunks { |
| 282 | let mut tmp = Default::default(); |
| 283 | backend.gen_par_ks_blocks(&mut tmp); |
| 284 | chunk.xor_in2out(&tmp); |
| 285 | } |
| 286 | let n = tail.len(); |
| 287 | let mut buf = GenericArray::<_, B::ParBlocksSize>::default(); |
| 288 | let ks = &mut buf[..n]; |
| 289 | backend.gen_tail_blocks(ks); |
| 290 | for i in 0..n { |
| 291 | tail.get(i).xor_in2out(&ks[i]); |
| 292 | } |
| 293 | } else { |
| 294 | for mut block in self.blocks { |
| 295 | let mut t = Default::default(); |
| 296 | backend.gen_ks_block(&mut t); |
| 297 | block.xor_in2out(&t); |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | } |
| 302 | |