Skip to main content

ssh_cipher/block_cipher/
decryptor.rs

1//! Stateful decryptor object.
2
3use super::{BlockMode, State, sealed::BlockCipher};
4use crate::{Cipher, Error, Result};
5use ::cipher::{
6    Block, BlockModeDecClosure, BlockModeDecrypt,
7    common::{BlockSizeUser, InnerUser},
8};
9use core::fmt::{self, Debug};
10
11/// Stateful decryptor object for unauthenticated symmetric ciphers used in the SSH packet
12/// encryption protocol.
13///
14/// Note we need encryption support for decryption in order to support AES-CTR, where encryption
15/// and decryption are the same operation.
16pub struct Decryptor<C: BlockCipher> {
17    /// Inner block cipher.
18    cipher: C,
19
20    /// State of the block cipher's mode of operation.
21    state: State<C::BlockSize>,
22}
23
24impl<C: BlockCipher> Decryptor<C> {
25    /// Create a new decryptor object with the given [`Cipher`], `key`, and `iv` (i.e.
26    /// initialization vector).
27    ///
28    /// # Errors
29    /// - Returns [`Error::Crypto`] if the given `cipher` cannot be used with `Decryptor`.
30    /// - Returns [`Error::Length`] if `key` or `iv` are the wrong length for the given `cipher`.
31    /// - Returns [`Error::UnsupportedCipher`] if support for the given `cipher` is not enabled
32    ///   in the crate features.
33    pub fn new(cipher: Cipher, key: &[u8], iv: &[u8]) -> Result<Self> {
34        if !C::is_supported(cipher) {
35            return Err(Error::UnsupportedCipher(cipher));
36        }
37
38        let mode = cipher.block_mode().ok_or(Error::Crypto)?;
39        let cipher = C::new_from_slice(key)?;
40        let state = State::new_from_slice(mode, iv)?;
41        Ok(Self { cipher, state })
42    }
43
44    /// Call the provided function with an ephemeral [`Decryptor`] state which will be reset upon
45    /// completion, returning the result of the function.
46    pub fn peek<T, F>(&mut self, mut f: F) -> T
47    where
48        F: FnMut(&mut Self) -> T,
49    {
50        let state = self.state.clone();
51        let ret = f(self);
52        self.state = state;
53        ret
54    }
55}
56
57impl<C: BlockCipher> BlockModeDecrypt for Decryptor<C> {
58    fn decrypt_with_backend(&mut self, _f: impl BlockModeDecClosure<BlockSize = Self::BlockSize>) {
59        unimplemented!("CTR mode support is incompatible with BlockModeDecrypt")
60    }
61
62    fn decrypt_block(&mut self, block: &mut Block<Self>) {
63        match self.state.mode() {
64            BlockMode::Cbc => {
65                let pad = self.state.clone();
66                self.state.as_mut().copy_from_slice(block);
67                self.cipher.decrypt_block(block);
68                pad.xor_into(block);
69            }
70            BlockMode::Ctr => {
71                let mut pad = self.state.clone();
72                self.cipher.encrypt_block(pad.as_mut());
73                pad.xor_into(block);
74                self.state.increment_counter();
75            }
76        }
77    }
78
79    fn decrypt_blocks(&mut self, blocks: &mut [Block<Self>]) {
80        // TODO(tarcieri): parallel decryption support
81        for block in blocks {
82            self.decrypt_block(block);
83        }
84    }
85}
86impl<C: BlockCipher> BlockSizeUser for Decryptor<C> {
87    type BlockSize = C::BlockSize;
88}
89
90impl<C: BlockCipher> Debug for Decryptor<C> {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        f.debug_struct("Decryptor").finish_non_exhaustive()
93    }
94}
95
96impl<C: BlockCipher> InnerUser for Decryptor<C> {
97    type Inner = C;
98}