ssh_packet/packet/
cipher.rs

1use super::{Mac, PACKET_MIN_SIZE};
2
3#[cfg(doc)]
4use super::Packet;
5
6const MIN_PAD_SIZE: usize = 4;
7const MIN_ALIGN: usize = 8;
8
9/// A trait with common methods and associated types involved
10/// in the manipulation of [`OpeningCipher`] and [`SealingCipher`].
11pub trait CipherCore {
12    /// The associated error type returned by the `open` method.
13    type Err: From<binrw::Error> + From<std::io::Error>;
14
15    /// The _Message Authentication Code_ associated to the cipher.
16    type Mac: Mac;
17
18    /// Gets a reference to the _Message Authentication Code_ for this [`CipherCore`].
19    fn mac(&self) -> &Self::Mac;
20
21    /// The size of a [`CipherCore`]'s block.
22    fn block_size(&self) -> usize;
23
24    /// Calculate the necessary padding size for the provided payload `size`.
25    fn padding(&self, payload: usize) -> u8 {
26        let align = self.block_size().max(MIN_ALIGN);
27
28        let size = if self.mac().etm() {
29            std::mem::size_of::<u8>() + payload
30        } else {
31            std::mem::size_of::<u32>() + std::mem::size_of::<u8>() + payload
32        };
33        let padding = align - size % align;
34
35        let padding = if padding < MIN_PAD_SIZE {
36            padding + align
37        } else {
38            padding
39        };
40
41        if size + padding < self.block_size().max(PACKET_MIN_SIZE) {
42            (padding + align) as u8
43        } else {
44            padding as u8
45        }
46    }
47}
48
49/// A cipher able to `open` a [`Packet`] and retrieve it's payload.
50pub trait OpeningCipher: CipherCore {
51    /// Decrypt the received `buf` using the [`OpeningCipher`].
52    fn decrypt<B: AsMut<[u8]>>(&mut self, buf: B) -> Result<(), Self::Err>;
53
54    /// Compare the received `buf` against the received _Message Authentication Code_.
55    fn open<B: AsRef<[u8]>>(&mut self, buf: B, mac: Vec<u8>, seq: u32) -> Result<(), Self::Err>;
56
57    /// Decompress the received `buf` using the [`OpeningCipher`].
58    fn decompress(&mut self, buf: Vec<u8>) -> Result<Vec<u8>, Self::Err>;
59}
60
61/// A cipher able to `seal` a payload to create a [`Packet`].
62pub trait SealingCipher: CipherCore {
63    /// Decompress the `buf` using the [`SealingCipher`].
64    fn compress<B: AsRef<[u8]>>(&mut self, buf: B) -> Result<Vec<u8>, Self::Err>;
65
66    /// Pad the `buf` to match [`SealingCipher`]'s block size with random data,
67    /// by increasing it by `padding` bytes and prefixing the `buf` it with it's len.
68    fn pad(&mut self, buf: Vec<u8>, padding: u8) -> Result<Vec<u8>, Self::Err>;
69
70    /// Encrypt the `buf` using using the [`SealingCipher`].
71    fn encrypt<B: AsMut<[u8]>>(&mut self, buf: B) -> Result<(), Self::Err>;
72
73    /// Generate a seal from the HMAC algorithm to produce a _Message Authentication Code_.
74    fn seal<B: AsRef<[u8]>>(&mut self, buf: B, seq: u32) -> Result<Vec<u8>, Self::Err>;
75}