portable_rustls/crypto/
cipher.rs

1use alloc::boxed::Box;
2use alloc::string::ToString;
3use core::fmt;
4
5use zeroize::Zeroize;
6
7use crate::enums::{ContentType, ProtocolVersion};
8use crate::error::Error;
9use crate::msgs::codec;
10pub use crate::msgs::message::{
11    BorrowedPayload, InboundOpaqueMessage, InboundPlainMessage, OutboundChunks,
12    OutboundOpaqueMessage, OutboundPlainMessage, PlainMessage, PrefixedPayload,
13};
14use crate::suites::ConnectionTrafficSecrets;
15
16/// Factory trait for building `MessageEncrypter` and `MessageDecrypter` for a TLS1.3 cipher suite.
17pub trait Tls13AeadAlgorithm: Send + Sync {
18    /// Build a `MessageEncrypter` for the given key/iv.
19    fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter>;
20
21    /// Build a `MessageDecrypter` for the given key/iv.
22    fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter>;
23
24    /// The length of key in bytes required by `encrypter()` and `decrypter()`.
25    fn key_len(&self) -> usize;
26
27    /// Convert the key material from `key`/`iv`, into a `ConnectionTrafficSecrets` item.
28    ///
29    /// May return [`UnsupportedOperationError`] if the AEAD algorithm is not a supported
30    /// variant of `ConnectionTrafficSecrets`.
31    fn extract_keys(
32        &self,
33        key: AeadKey,
34        iv: Iv,
35    ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError>;
36
37    /// Return `true` if this is backed by a FIPS-approved implementation.
38    #[cfg(unstable_api_not_supported)] // [FIPS REMOVED FROM THIS FORK]
39    fn fips(&self) -> bool {
40        false
41    }
42}
43
44/// Factory trait for building `MessageEncrypter` and `MessageDecrypter` for a TLS1.2 cipher suite.
45pub trait Tls12AeadAlgorithm: Send + Sync + 'static {
46    /// Build a `MessageEncrypter` for the given key/iv and extra key block (which can be used for
47    /// improving explicit nonce size security, if needed).
48    ///
49    /// The length of `key` is set by [`KeyBlockShape::enc_key_len`].
50    ///
51    /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`].
52    ///
53    /// The length of `extra` is set by [`KeyBlockShape::explicit_nonce_len`].
54    fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box<dyn MessageEncrypter>;
55
56    /// Build a `MessageDecrypter` for the given key/iv.
57    ///
58    /// The length of `key` is set by [`KeyBlockShape::enc_key_len`].
59    ///
60    /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`].
61    fn decrypter(&self, key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter>;
62
63    /// Return a `KeyBlockShape` that defines how large the `key_block` is and how it
64    /// is split up prior to calling `encrypter()`, `decrypter()` and/or `extract_keys()`.
65    fn key_block_shape(&self) -> KeyBlockShape;
66
67    /// Convert the key material from `key`/`iv`, into a `ConnectionTrafficSecrets` item.
68    ///
69    /// The length of `key` is set by [`KeyBlockShape::enc_key_len`].
70    ///
71    /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`].
72    ///
73    /// The length of `extra` is set by [`KeyBlockShape::explicit_nonce_len`].
74    ///
75    /// May return [`UnsupportedOperationError`] if the AEAD algorithm is not a supported
76    /// variant of `ConnectionTrafficSecrets`.
77    fn extract_keys(
78        &self,
79        key: AeadKey,
80        iv: &[u8],
81        explicit: &[u8],
82    ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError>;
83
84    /// Return `true` if this is backed by a FIPS-approved implementation.
85    #[cfg(unstable_api_not_supported)] // [FIPS REMOVED FROM THIS FORK]
86    fn fips(&self) -> bool {
87        false
88    }
89}
90
91/// An error indicating that the AEAD algorithm does not support the requested operation.
92#[derive(Debug, Eq, PartialEq, Clone, Copy)]
93pub struct UnsupportedOperationError;
94
95impl From<UnsupportedOperationError> for Error {
96    fn from(value: UnsupportedOperationError) -> Self {
97        Self::General(value.to_string())
98    }
99}
100
101impl fmt::Display for UnsupportedOperationError {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        write!(f, "operation not supported")
104    }
105}
106
107#[cfg(feature = "std")]
108impl std::error::Error for UnsupportedOperationError {}
109
110/// How a TLS1.2 `key_block` is partitioned.
111///
112/// Note: ciphersuites with non-zero `mac_key_length` are  not currently supported.
113pub struct KeyBlockShape {
114    /// How long keys are.
115    ///
116    /// `enc_key_length` terminology is from the standard ([RFC5246 A.6]).
117    ///
118    /// [RFC5246 A.6]: <https://www.rfc-editor.org/rfc/rfc5246#appendix-A.6>
119    pub enc_key_len: usize,
120
121    /// How long the fixed part of the 'IV' is.
122    ///
123    /// `fixed_iv_length` terminology is from the standard ([RFC5246 A.6]).
124    ///
125    /// This isn't usually an IV, but we continue the
126    /// terminology misuse to match the standard.
127    ///
128    /// [RFC5246 A.6]: <https://www.rfc-editor.org/rfc/rfc5246#appendix-A.6>
129    pub fixed_iv_len: usize,
130
131    /// This is a non-standard extension which extends the
132    /// key block to provide an initial explicit nonce offset,
133    /// in a deterministic and safe way.  GCM needs this,
134    /// chacha20poly1305 works this way by design.
135    pub explicit_nonce_len: usize,
136}
137
138/// Objects with this trait can decrypt TLS messages.
139pub trait MessageDecrypter: Send + Sync {
140    /// Decrypt the given TLS message `msg`, using the sequence number
141    /// `seq` which can be used to derive a unique [`Nonce`].
142    fn decrypt<'a>(
143        &mut self,
144        msg: InboundOpaqueMessage<'a>,
145        seq: u64,
146    ) -> Result<InboundPlainMessage<'a>, Error>;
147}
148
149/// Objects with this trait can encrypt TLS messages.
150pub trait MessageEncrypter: Send + Sync {
151    /// Encrypt the given TLS message `msg`, using the sequence number
152    /// `seq` which can be used to derive a unique [`Nonce`].
153    fn encrypt(
154        &mut self,
155        msg: OutboundPlainMessage<'_>,
156        seq: u64,
157    ) -> Result<OutboundOpaqueMessage, Error>;
158
159    /// Return the length of the ciphertext that results from encrypting plaintext of
160    /// length `payload_len`
161    fn encrypted_payload_len(&self, payload_len: usize) -> usize;
162}
163
164impl dyn MessageEncrypter {
165    pub(crate) fn invalid() -> Box<dyn MessageEncrypter> {
166        Box::new(InvalidMessageEncrypter {})
167    }
168}
169
170impl dyn MessageDecrypter {
171    pub(crate) fn invalid() -> Box<dyn MessageDecrypter> {
172        Box::new(InvalidMessageDecrypter {})
173    }
174}
175
176/// A write or read IV.
177#[derive(Default)]
178pub struct Iv([u8; NONCE_LEN]);
179
180impl Iv {
181    /// Create a new `Iv` from a byte array, of precisely `NONCE_LEN` bytes.
182    #[cfg(feature = "tls12")]
183    pub fn new(value: [u8; NONCE_LEN]) -> Self {
184        Self(value)
185    }
186
187    /// Create a new `Iv` from a byte slice, of precisely `NONCE_LEN` bytes.
188    #[cfg(feature = "tls12")]
189    pub fn copy(value: &[u8]) -> Self {
190        debug_assert_eq!(value.len(), NONCE_LEN);
191        let mut iv = Self::new(Default::default());
192        iv.0.copy_from_slice(value);
193        iv
194    }
195}
196
197impl From<[u8; NONCE_LEN]> for Iv {
198    fn from(bytes: [u8; NONCE_LEN]) -> Self {
199        Self(bytes)
200    }
201}
202
203impl AsRef<[u8]> for Iv {
204    fn as_ref(&self) -> &[u8] {
205        self.0.as_ref()
206    }
207}
208
209/// A nonce.  This is unique for all messages on a connection.
210pub struct Nonce(pub [u8; NONCE_LEN]);
211
212impl Nonce {
213    /// Combine an `Iv` and sequence number to produce a unique nonce.
214    ///
215    /// This is `iv ^ seq` where `seq` is encoded as a 96-bit big-endian integer.
216    #[inline]
217    pub fn new(iv: &Iv, seq: u64) -> Self {
218        let mut nonce = Self([0u8; NONCE_LEN]);
219        codec::put_u64(seq, &mut nonce.0[4..]);
220
221        nonce
222            .0
223            .iter_mut()
224            .zip(iv.0.iter())
225            .for_each(|(nonce, iv)| {
226                *nonce ^= *iv;
227            });
228
229        nonce
230    }
231}
232
233/// Size of TLS nonces (incorrectly termed "IV" in standard) for all supported ciphersuites
234/// (AES-GCM, Chacha20Poly1305)
235pub const NONCE_LEN: usize = 12;
236
237/// Returns a TLS1.3 `additional_data` encoding.
238///
239/// See RFC8446 s5.2 for the `additional_data` definition.
240#[inline]
241pub fn make_tls13_aad(payload_len: usize) -> [u8; 5] {
242    let version = ProtocolVersion::TLSv1_2.to_array();
243    [
244        ContentType::ApplicationData.into(),
245        // Note: this is `legacy_record_version`, i.e. TLS1.2 even for TLS1.3.
246        version[0],
247        version[1],
248        (payload_len >> 8) as u8,
249        (payload_len & 0xff) as u8,
250    ]
251}
252
253/// Returns a TLS1.2 `additional_data` encoding.
254///
255/// See RFC5246 s6.2.3.3 for the `additional_data` definition.
256#[inline]
257pub fn make_tls12_aad(
258    seq: u64,
259    typ: ContentType,
260    vers: ProtocolVersion,
261    len: usize,
262) -> [u8; TLS12_AAD_SIZE] {
263    let mut out = [0; TLS12_AAD_SIZE];
264    codec::put_u64(seq, &mut out[0..]);
265    out[8] = typ.into();
266    codec::put_u16(vers.into(), &mut out[9..]);
267    codec::put_u16(len as u16, &mut out[11..]);
268    out
269}
270
271const TLS12_AAD_SIZE: usize = 8 + 1 + 2 + 2;
272
273/// A key for an AEAD algorithm.
274///
275/// This is a value type for a byte string up to `AeadKey::MAX_LEN` bytes in length.
276pub struct AeadKey {
277    buf: [u8; Self::MAX_LEN],
278    used: usize,
279}
280
281impl AeadKey {
282    #[cfg(feature = "tls12")]
283    pub(crate) fn new(buf: &[u8]) -> Self {
284        debug_assert!(buf.len() <= Self::MAX_LEN);
285        let mut key = Self::from([0u8; Self::MAX_LEN]);
286        key.buf[..buf.len()].copy_from_slice(buf);
287        key.used = buf.len();
288        key
289    }
290
291    pub(crate) fn with_length(self, len: usize) -> Self {
292        assert!(len <= self.used);
293        Self {
294            buf: self.buf,
295            used: len,
296        }
297    }
298
299    /// Largest possible AEAD key in the ciphersuites we support.
300    pub(crate) const MAX_LEN: usize = 32;
301}
302
303impl Drop for AeadKey {
304    fn drop(&mut self) {
305        self.buf.zeroize();
306    }
307}
308
309impl AsRef<[u8]> for AeadKey {
310    fn as_ref(&self) -> &[u8] {
311        &self.buf[..self.used]
312    }
313}
314
315impl From<[u8; Self::MAX_LEN]> for AeadKey {
316    fn from(bytes: [u8; Self::MAX_LEN]) -> Self {
317        Self {
318            buf: bytes,
319            used: Self::MAX_LEN,
320        }
321    }
322}
323
324/// A `MessageEncrypter` which doesn't work.
325struct InvalidMessageEncrypter {}
326
327impl MessageEncrypter for InvalidMessageEncrypter {
328    fn encrypt(
329        &mut self,
330        _m: OutboundPlainMessage<'_>,
331        _seq: u64,
332    ) -> Result<OutboundOpaqueMessage, Error> {
333        Err(Error::EncryptError)
334    }
335
336    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
337        payload_len
338    }
339}
340
341/// A `MessageDecrypter` which doesn't work.
342struct InvalidMessageDecrypter {}
343
344impl MessageDecrypter for InvalidMessageDecrypter {
345    fn decrypt<'a>(
346        &mut self,
347        _m: InboundOpaqueMessage<'a>,
348        _seq: u64,
349    ) -> Result<InboundPlainMessage<'a>, Error> {
350        Err(Error::DecryptError)
351    }
352}