summaryrefslogtreecommitdiff
path: root/crates/tor-llcrypto/src/cipher.rs
blob: d04109c79e587f2cb10ccbb97177619c3fc13ac9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! Ciphers used to implement the Tor protocols.
//!
//! Fortunately, Tor has managed not to proliferate ciphers.  It only
//! uses AES, and (so far) only uses AES in counter mode.

/// Re-exports implementations of counter-mode AES.
///
/// These ciphers implement the `cipher::StreamCipher` trait, so use
/// the [`cipher`](https://docs.rs/cipher) crate to access them.
#[cfg_attr(docsrs, doc(cfg(true)))]
#[cfg(not(feature = "with-openssl"))]
pub mod aes {
    // These implement StreamCipher.
    /// AES128 in counter mode as used by Tor.
    pub type Aes128Ctr = ctr::Ctr128BE<aes::Aes128>;

    /// AES256 in counter mode as used by Tor.  
    pub type Aes256Ctr = ctr::Ctr128BE<aes::Aes256>;
}

/// Compatibility layer between OpenSSL and `cipher::StreamCipher`.
///
/// These ciphers implement the `cipher::StreamCipher` trait, so use
/// the [`cipher`](https://docs.rs/cipher) crate to access them.
#[cfg_attr(docsrs, doc(cfg(true)))]
#[cfg(feature = "with-openssl")]
pub mod aes {
    use cipher::common::array::Array;
    use cipher::common::{InnerUser, KeyInit, KeySizeUser};
    use cipher::inout::InOutBuf;
    use cipher::{InnerIvInit, IvSizeUser, StreamCipher, StreamCipherError};
    use openssl::symm::{Cipher, Crypter, Mode};
    use zeroize::{Zeroize, ZeroizeOnDrop};

    /// AES 128 in counter mode as used by Tor.
    pub struct Aes128Ctr(
        /// Underlying openssl crypto context.
        Crypter,
    );

    /// AES 128 key
    #[derive(Zeroize, ZeroizeOnDrop)]
    pub struct Aes128Key([u8; 16]);

    impl KeySizeUser for Aes128Key {
        type KeySize = typenum::consts::U16;
    }

    impl KeyInit for Aes128Key {
        fn new(key: &Array<u8, Self::KeySize>) -> Self {
            Aes128Key((*key).into())
        }
    }

    impl InnerUser for Aes128Ctr {
        type Inner = Aes128Key;
    }

    impl IvSizeUser for Aes128Ctr {
        type IvSize = typenum::consts::U16;
    }

    impl StreamCipher for Aes128Ctr {
        fn check_remaining(&self, _data_len: usize) -> Result<(), StreamCipherError> {
            // NOTE: this is not a sefe pattern in general, but since the underlying counter
            // is 128 bits, we don't need to worry about overflowing it.
            Ok(())
        }

        fn unchecked_apply_keystream_inout(&mut self, mut buf: InOutBuf<'_, '_, u8>) {
            // TODO(nickm): It would be lovely if we could get rid of this copy somehow.
            let in_buf = zeroize::Zeroizing::new(buf.get_in().to_vec());
            self.0
                .update(&in_buf, buf.get_out())
                .expect("OpenSSL AES encryption failed.");
        }

        fn unchecked_write_keystream(&mut self, buf: &mut [u8]) {
            // TODO(nickm): It would be lovely if we could get rid of this vec somehow.
            let z = vec![0; buf.len()];
            self.0
                .update(&z, buf)
                .expect("OpenSSL AES encryption failed.");
        }
    }

    impl InnerIvInit for Aes128Ctr {
        fn inner_iv_init(inner: Self::Inner, iv: &Array<u8, Self::IvSize>) -> Self {
            let crypter = Crypter::new(Cipher::aes_128_ctr(), Mode::Encrypt, &inner.0, Some(iv))
                .expect("openssl error while initializing Aes128Ctr");
            Aes128Ctr(crypter)
        }
    }

    /// AES 256 in counter mode as used by Tor.
    pub struct Aes256Ctr(Crypter);

    /// AES 256 key
    #[derive(Zeroize, ZeroizeOnDrop)]
    pub struct Aes256Key([u8; 32]);

    impl KeySizeUser for Aes256Key {
        type KeySize = typenum::consts::U32;
    }

    impl KeyInit for Aes256Key {
        fn new(key: &Array<u8, Self::KeySize>) -> Self {
            Aes256Key((*key).into())
        }
    }

    impl InnerUser for Aes256Ctr {
        type Inner = Aes256Key;
    }

    impl IvSizeUser for Aes256Ctr {
        type IvSize = typenum::consts::U16;
    }

    impl StreamCipher for Aes256Ctr {
        fn check_remaining(&self, _data_len: usize) -> Result<(), StreamCipherError> {
            // NOTE: this is not a sefe pattern in general, but since the underlying counter
            // is 128 bits, we don't need to worry about overflowing it.
            Ok(())
        }

        fn unchecked_apply_keystream_inout(&mut self, mut buf: InOutBuf<'_, '_, u8>) {
            // TODO(nickm): It would be lovely if we could get rid of this copy somehow.
            let in_buf = zeroize::Zeroizing::new(buf.get_in().to_vec());
            self.0
                .update(&in_buf, buf.get_out())
                .expect("OpenSSL AES encryption failed.");
        }

        fn unchecked_write_keystream(&mut self, buf: &mut [u8]) {
            // TODO(nickm): It would be lovely if we could get rid of this vec somehow.
            let z = vec![0; buf.len()];
            self.0
                .update(&z, buf)
                .expect("OpenSSL AES encryption failed.");
        }
    }

    impl InnerIvInit for Aes256Ctr {
        fn inner_iv_init(inner: Self::Inner, iv: &Array<u8, Self::IvSize>) -> Self {
            let crypter = Crypter::new(Cipher::aes_256_ctr(), Mode::Encrypt, &inner.0, Some(iv))
                .expect("openssl error while initializing Aes256Ctr");
            Aes256Ctr(crypter)
        }
    }
}