Skip to main content

tor_llcrypto/
cipher.rs

1//! Ciphers used to implement the Tor protocols.
2//!
3//! Fortunately, Tor has managed not to proliferate ciphers.  It only
4//! uses AES, and (so far) only uses AES in counter mode.
5
6/// Re-exports implementations of counter-mode AES.
7///
8/// These ciphers implement the `cipher::StreamCipher` trait, so use
9/// the [`cipher`](https://docs.rs/cipher) crate to access them.
10#[cfg_attr(docsrs, doc(cfg(true)))]
11#[cfg(not(feature = "with-openssl"))]
12pub mod aes {
13    // These implement StreamCipher.
14    /// AES128 in counter mode as used by Tor.
15    pub type Aes128Ctr = ctr::Ctr128BE<aes::Aes128>;
16
17    /// AES256 in counter mode as used by Tor.  
18    pub type Aes256Ctr = ctr::Ctr128BE<aes::Aes256>;
19}
20
21/// Compatibility layer between OpenSSL and `cipher::StreamCipher`.
22///
23/// These ciphers implement the `cipher::StreamCipher` trait, so use
24/// the [`cipher`](https://docs.rs/cipher) crate to access them.
25#[cfg_attr(docsrs, doc(cfg(true)))]
26#[cfg(feature = "with-openssl")]
27pub mod aes {
28    use cipher::common::array::Array;
29    use cipher::common::{InnerUser, KeyInit, KeySizeUser};
30    use cipher::inout::InOutBuf;
31    use cipher::{InnerIvInit, IvSizeUser, StreamCipher, StreamCipherError};
32    use openssl::symm::{Cipher, Crypter, Mode};
33    use zeroize::{Zeroize, ZeroizeOnDrop};
34
35    /// AES 128 in counter mode as used by Tor.
36    pub struct Aes128Ctr(
37        /// Underlying openssl crypto context.
38        Crypter,
39    );
40
41    /// AES 128 key
42    #[derive(Zeroize, ZeroizeOnDrop)]
43    pub struct Aes128Key([u8; 16]);
44
45    impl KeySizeUser for Aes128Key {
46        type KeySize = typenum::consts::U16;
47    }
48
49    impl KeyInit for Aes128Key {
50        fn new(key: &Array<u8, Self::KeySize>) -> Self {
51            Aes128Key((*key).into())
52        }
53    }
54
55    impl InnerUser for Aes128Ctr {
56        type Inner = Aes128Key;
57    }
58
59    impl IvSizeUser for Aes128Ctr {
60        type IvSize = typenum::consts::U16;
61    }
62
63    impl StreamCipher for Aes128Ctr {
64        fn check_remaining(&self, _data_len: usize) -> Result<(), StreamCipherError> {
65            // NOTE: this is not a sefe pattern in general, but since the underlying counter
66            // is 128 bits, we don't need to worry about overflowing it.
67            Ok(())
68        }
69
70        fn unchecked_apply_keystream_inout(&mut self, mut buf: InOutBuf<'_, '_, u8>) {
71            // TODO(nickm): It would be lovely if we could get rid of this copy somehow.
72            let in_buf = zeroize::Zeroizing::new(buf.get_in().to_vec());
73            self.0
74                .update(&in_buf, buf.get_out())
75                .expect("OpenSSL AES encryption failed.");
76        }
77
78        fn unchecked_write_keystream(&mut self, buf: &mut [u8]) {
79            // TODO(nickm): It would be lovely if we could get rid of this vec somehow.
80            let z = vec![0; buf.len()];
81            self.0
82                .update(&z, buf)
83                .expect("OpenSSL AES encryption failed.");
84        }
85    }
86
87    impl InnerIvInit for Aes128Ctr {
88        fn inner_iv_init(inner: Self::Inner, iv: &Array<u8, Self::IvSize>) -> Self {
89            let crypter = Crypter::new(Cipher::aes_128_ctr(), Mode::Encrypt, &inner.0, Some(iv))
90                .expect("openssl error while initializing Aes128Ctr");
91            Aes128Ctr(crypter)
92        }
93    }
94
95    /// AES 256 in counter mode as used by Tor.
96    pub struct Aes256Ctr(Crypter);
97
98    /// AES 256 key
99    #[derive(Zeroize, ZeroizeOnDrop)]
100    pub struct Aes256Key([u8; 32]);
101
102    impl KeySizeUser for Aes256Key {
103        type KeySize = typenum::consts::U32;
104    }
105
106    impl KeyInit for Aes256Key {
107        fn new(key: &Array<u8, Self::KeySize>) -> Self {
108            Aes256Key((*key).into())
109        }
110    }
111
112    impl InnerUser for Aes256Ctr {
113        type Inner = Aes256Key;
114    }
115
116    impl IvSizeUser for Aes256Ctr {
117        type IvSize = typenum::consts::U16;
118    }
119
120    impl StreamCipher for Aes256Ctr {
121        fn check_remaining(&self, _data_len: usize) -> Result<(), StreamCipherError> {
122            // NOTE: this is not a sefe pattern in general, but since the underlying counter
123            // is 128 bits, we don't need to worry about overflowing it.
124            Ok(())
125        }
126
127        fn unchecked_apply_keystream_inout(&mut self, mut buf: InOutBuf<'_, '_, u8>) {
128            // TODO(nickm): It would be lovely if we could get rid of this copy somehow.
129            let in_buf = zeroize::Zeroizing::new(buf.get_in().to_vec());
130            self.0
131                .update(&in_buf, buf.get_out())
132                .expect("OpenSSL AES encryption failed.");
133        }
134
135        fn unchecked_write_keystream(&mut self, buf: &mut [u8]) {
136            // TODO(nickm): It would be lovely if we could get rid of this vec somehow.
137            let z = vec![0; buf.len()];
138            self.0
139                .update(&z, buf)
140                .expect("OpenSSL AES encryption failed.");
141        }
142    }
143
144    impl InnerIvInit for Aes256Ctr {
145        fn inner_iv_init(inner: Self::Inner, iv: &Array<u8, Self::IvSize>) -> Self {
146            let crypter = Crypter::new(Cipher::aes_256_ctr(), Mode::Encrypt, &inner.0, Some(iv))
147                .expect("openssl error while initializing Aes256Ctr");
148            Aes256Ctr(crypter)
149        }
150    }
151}