Skip to main content

rw_builder/
stream_cipher.rs

1use std::{
2    io::{Read, Write},
3    marker::PhantomData,
4};
5
6use crate::Result;
7#[cfg(feature = "aes_ctr")]
8use aes::{Aes128, Aes256};
9#[cfg(feature = "chacha20")]
10use chacha20::ChaCha20;
11use cipher::{KeyIvInit, StreamCipher};
12#[cfg(feature = "aes_ctr")]
13use ctr::Ctr128BE;
14#[cfg(feature = "salsa20")]
15use salsa20::Salsa20;
16
17use crate::RwBuilder;
18
19/// Type returned by the `chacha20` and `salsa20` functions on the `RwBuilder`
20/// trait. It is itself an `RwBuilder` so can be chained further.
21#[derive(Debug)]
22#[must_use]
23pub struct Builder<B, C, K, N>
24where
25    B: RwBuilder,
26    C: StreamCipher,
27{
28    /// The inner builder it wraps
29    wrapped: B,
30    /// The key used for encryption and decryption
31    key: K,
32    /// The nonce used for encryption and decryption
33    nonce: N,
34    /// We need `Builder` to be generic over the `StreamCipher`
35    _marker: PhantomData<C>,
36}
37
38impl<B, C, K, N> Builder<B, C, K, N>
39where
40    B: RwBuilder,
41    C: StreamCipher,
42{
43    /// Create a new cipher builder from a key and a nonce
44    pub const fn new(builder: B, key: K, nonce: N) -> Self {
45        Self { wrapped: builder, key, nonce, _marker: PhantomData }
46    }
47}
48
49/// The key type for the chacha20 cipher
50#[cfg(feature = "chacha20")]
51pub type ChaCha20Key = chacha20::Key;
52
53/// The nonce type for the chacha20 cipher (12 bytes for IETF variant)
54#[cfg(feature = "chacha20")]
55pub type ChaCha20Nonce = [u8; 12];
56
57/// The type returned by the `chacha20` function in the `RwBuilder` trait
58#[cfg(feature = "chacha20")]
59pub type ChaCha20Builder<B> = Builder<B, ChaCha20, ChaCha20Key, ChaCha20Nonce>;
60
61/// The key type for the salsa20 cipher
62#[cfg(feature = "salsa20")]
63pub type Salsa20Key = salsa20::Key;
64
65/// The nonce type for the salsa20 cipher
66#[cfg(feature = "salsa20")]
67pub type Salsa20Nonce = salsa20::Nonce;
68
69/// The type returned by the `salsa20` function in the `RwBuilder` trait
70#[cfg(feature = "salsa20")]
71pub type Salsa20Builder<B> = Builder<B, Salsa20, Salsa20Key, Salsa20Nonce>;
72
73/// Internal type for AES-128-CTR cipher
74#[cfg(feature = "aes_ctr")]
75pub type Aes128Ctr = Ctr128BE<Aes128>;
76/// Internal type for AES-256-CTR cipher
77#[cfg(feature = "aes_ctr")]
78pub type Aes256Ctr = Ctr128BE<Aes256>;
79
80/// The key type for the AES-128-CTR cipher
81#[cfg(feature = "aes_ctr")]
82pub type Aes128Key = [u8; 16];
83/// The key type for the AES-256-CTR cipher
84#[cfg(feature = "aes_ctr")]
85pub type Aes256Key = [u8; 32];
86/// The nonce type for AES-CTR cipher
87#[cfg(feature = "aes_ctr")]
88pub type AesNonce = [u8; 16];
89
90/// The type returned by the `aes128_ctr` function in the `RwBuilder` trait
91#[cfg(feature = "aes_ctr")]
92pub type Aes128CtrBuilder<B> = Builder<B, Aes128Ctr, Aes128Key, AesNonce>;
93/// The type returned by the `aes256_ctr` function in the `RwBuilder` trait
94#[cfg(feature = "aes_ctr")]
95pub type Aes256CtrBuilder<B> = Builder<B, Aes256Ctr, Aes256Key, AesNonce>;
96
97/// Recipe for how to create a cipher
98trait CipherFactory<C> {
99    /// Create the cipher from the key and the nonce stored in self
100    fn create_cipher(&self) -> C;
101}
102
103#[cfg(feature = "chacha20")]
104impl<B> CipherFactory<ChaCha20> for Builder<B, ChaCha20, ChaCha20Key, ChaCha20Nonce>
105where
106    B: RwBuilder,
107{
108    fn create_cipher(&self) -> ChaCha20 {
109        ChaCha20::new(&self.key, (&self.nonce).into())
110    }
111}
112
113#[cfg(feature = "salsa20")]
114impl<B> CipherFactory<Salsa20> for Builder<B, Salsa20, Salsa20Key, Salsa20Nonce>
115where
116    B: RwBuilder,
117{
118    fn create_cipher(&self) -> Salsa20 {
119        Salsa20::new(&self.key, &self.nonce)
120    }
121}
122
123#[cfg(feature = "aes_ctr")]
124impl<B> CipherFactory<Aes128Ctr> for Builder<B, Aes128Ctr, Aes128Key, AesNonce>
125where
126    B: RwBuilder,
127{
128    fn create_cipher(&self) -> Aes128Ctr {
129        Aes128Ctr::new((&self.key).into(), (&self.nonce).into())
130    }
131}
132
133#[cfg(feature = "aes_ctr")]
134impl<B> CipherFactory<Aes256Ctr> for Builder<B, Aes256Ctr, Aes256Key, AesNonce>
135where
136    B: RwBuilder,
137{
138    fn create_cipher(&self) -> Aes256Ctr {
139        Aes256Ctr::new((&self.key).into(), (&self.nonce).into())
140    }
141}
142
143impl<B, C, K, N> RwBuilder for Builder<B, C, K, N>
144where
145    B: RwBuilder,
146    C: StreamCipher,
147    Self: CipherFactory<C>,
148{
149    type Reader = Reader<B::Reader, C>;
150    type Writer = Writer<B::Writer, C>;
151
152    fn reader(&self) -> Result<Self::Reader> {
153        let reader = self.wrapped.reader()?;
154        let cipher = self.create_cipher();
155        Ok(Reader { cipher, reader })
156    }
157
158    fn writer(&self) -> Result<Self::Writer> {
159        let writer = self.wrapped.writer()?;
160        let cipher = self.create_cipher();
161        Ok(Writer { cipher, writer })
162    }
163}
164
165/// Generic Reader type for multiple ciphers
166#[derive(Debug)]
167pub struct Reader<R, C>
168where
169    R: Read,
170    C: StreamCipher,
171{
172    /// The cipher to use for reading
173    cipher: C,
174    /// The wrapped reader
175    reader: R,
176}
177
178impl<R, C> Read for Reader<R, C>
179where
180    R: Read,
181    C: StreamCipher,
182{
183    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
184        let bytes_read = self.reader.read(buf)?;
185        self.cipher.try_apply_keystream(buf).map_err(std::io::Error::other)?;
186        Ok(bytes_read)
187    }
188}
189
190/// Generic Writer type for multiple ciphers
191#[derive(Debug)]
192pub struct Writer<W, C>
193where
194    W: Write,
195    C: StreamCipher,
196{
197    /// The cipher to use for writing
198    cipher: C,
199    /// The wrapped writer
200    writer: W,
201}
202
203impl<W, C> Write for Writer<W, C>
204where
205    W: Write,
206    C: StreamCipher,
207{
208    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
209        let mut buffer = buf.to_owned();
210        self.cipher.try_apply_keystream(buffer.as_mut_slice()).map_err(std::io::Error::other)?;
211        self.writer.write(buffer.as_slice())
212    }
213
214    fn flush(&mut self) -> std::io::Result<()> {
215        self.writer.flush()
216    }
217}