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    fn fips(&self) -> bool {
39        false
40    }
41}
42
43/// Factory trait for building `MessageEncrypter` and `MessageDecrypter` for a TLS1.2 cipher suite.
44pub trait Tls12AeadAlgorithm: Send + Sync + 'static {
45    /// Build a `MessageEncrypter` for the given key/iv and extra key block (which can be used for
46    /// improving explicit nonce size security, if needed).
47    ///
48    /// The length of `key` is set by [`KeyBlockShape::enc_key_len`].
49    ///
50    /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`].
51    ///
52    /// The length of `extra` is set by [`KeyBlockShape::explicit_nonce_len`].
53    fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box<dyn MessageEncrypter>;
54
55    /// Build a `MessageDecrypter` for the given key/iv.
56    ///
57    /// The length of `key` is set by [`KeyBlockShape::enc_key_len`].
58    ///
59    /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`].
60    fn decrypter(&self, key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter>;
61
62    /// Return a `KeyBlockShape` that defines how large the `key_block` is and how it
63    /// is split up prior to calling `encrypter()`, `decrypter()` and/or `extract_keys()`.
64    fn key_block_shape(&self) -> KeyBlockShape;
65
66    /// Convert the key material from `key`/`iv`, into a `ConnectionTrafficSecrets` item.
67    ///
68    /// The length of `key` is set by [`KeyBlockShape::enc_key_len`].
69    ///
70    /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`].
71    ///
72    /// The length of `extra` is set by [`KeyBlockShape::explicit_nonce_len`].
73    ///
74    /// May return [`UnsupportedOperationError`] if the AEAD algorithm is not a supported
75    /// variant of `ConnectionTrafficSecrets`.
76    fn extract_keys(
77        &self,
78        key: AeadKey,
79        iv: &[u8],
80        explicit: &[u8],
81    ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError>;
82
83    /// Return `true` if this is backed by a FIPS-approved implementation.
84    fn fips(&self) -> bool {
85        false
86    }
87}
88
89/// An error indicating that the AEAD algorithm does not support the requested operation.
90#[allow(clippy::exhaustive_structs)]
91#[derive(Debug, Eq, PartialEq, Clone, Copy)]
92pub struct UnsupportedOperationError;
93
94impl From<UnsupportedOperationError> for Error {
95    fn from(value: UnsupportedOperationError) -> Self {
96        Self::General(value.to_string())
97    }
98}
99
100impl fmt::Display for UnsupportedOperationError {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        write!(f, "operation not supported")
103    }
104}
105
106#[cfg(feature = "std")]
107impl std::error::Error for UnsupportedOperationError {}
108
109/// How a TLS1.2 `key_block` is partitioned.
110///
111/// Note: ciphersuites with non-zero `mac_key_length` are  not currently supported.
112#[allow(clippy::exhaustive_structs)]
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    pub fn new(value: [u8; NONCE_LEN]) -> Self {
183        Self(value)
184    }
185
186    /// Create a new `Iv` from a byte slice, of precisely `NONCE_LEN` bytes.
187    pub fn copy(value: &[u8]) -> Self {
188        debug_assert_eq!(value.len(), NONCE_LEN);
189        let mut iv = Self::new(Default::default());
190        iv.0.copy_from_slice(value);
191        iv
192    }
193}
194
195impl From<[u8; NONCE_LEN]> for Iv {
196    fn from(bytes: [u8; NONCE_LEN]) -> Self {
197        Self(bytes)
198    }
199}
200
201impl AsRef<[u8]> for Iv {
202    fn as_ref(&self) -> &[u8] {
203        self.0.as_ref()
204    }
205}
206
207/// A nonce.  This is unique for all messages on a connection.
208#[allow(clippy::exhaustive_structs)]
209pub struct Nonce(pub [u8; NONCE_LEN]);
210
211impl Nonce {
212    /// Combine an `Iv` and sequence number to produce a unique nonce.
213    ///
214    /// This is `iv ^ seq` where `seq` is encoded as a 96-bit big-endian integer.
215    #[inline]
216    pub fn new(iv: &Iv, seq: u64) -> Self {
217        Self::new_inner(None, iv, seq)
218    }
219
220    /// Creates a unique nonce based on the multipath `path_id`, the `iv` and packet number `pn`.
221    ///
222    /// The nonce is computed as the XOR between the `iv` and the 96-bit big-endian integer formed
223    /// by concatenating `path_id` (or 0) and `pn`.
224    pub fn quic(path_id: Option<u32>, iv: &Iv, pn: u64) -> Self {
225        Self::new_inner(path_id, iv, pn)
226    }
227
228    /// Creates a unique nonce based on the `iv` and sequence number `seq`.
229    #[inline]
230    fn new_inner(path_id: Option<u32>, iv: &Iv, seq: u64) -> Self {
231        let mut seq_bytes = [0u8; NONCE_LEN];
232        codec::put_u64(seq, &mut seq_bytes[4..]);
233        if let Some(path_id) = path_id {
234            seq_bytes[0..4].copy_from_slice(&path_id.to_be_bytes());
235        }
236
237        seq_bytes
238            .iter_mut()
239            .zip(iv.0.iter())
240            .for_each(|(s, iv)| {
241                *s ^= *iv;
242            });
243
244        Self(seq_bytes)
245    }
246}
247
248/// Size of TLS nonces (incorrectly termed "IV" in standard) for all supported ciphersuites
249/// (AES-GCM, Chacha20Poly1305)
250pub const NONCE_LEN: usize = 12;
251
252/// Returns a TLS1.3 `additional_data` encoding.
253///
254/// See RFC8446 s5.2 for the `additional_data` definition.
255#[inline]
256pub fn make_tls13_aad(payload_len: usize) -> [u8; 5] {
257    let version = ProtocolVersion::TLSv1_2.to_array();
258    [
259        ContentType::ApplicationData.into(),
260        // Note: this is `legacy_record_version`, i.e. TLS1.2 even for TLS1.3.
261        version[0],
262        version[1],
263        (payload_len >> 8) as u8,
264        (payload_len & 0xff) as u8,
265    ]
266}
267
268/// Returns a TLS1.2 `additional_data` encoding.
269///
270/// See RFC5246 s6.2.3.3 for the `additional_data` definition.
271#[inline]
272pub fn make_tls12_aad(
273    seq: u64,
274    typ: ContentType,
275    vers: ProtocolVersion,
276    len: usize,
277) -> [u8; TLS12_AAD_SIZE] {
278    let mut out = [0; TLS12_AAD_SIZE];
279    codec::put_u64(seq, &mut out[0..]);
280    out[8] = typ.into();
281    codec::put_u16(vers.into(), &mut out[9..]);
282    codec::put_u16(len as u16, &mut out[11..]);
283    out
284}
285
286const TLS12_AAD_SIZE: usize = 8 + 1 + 2 + 2;
287
288/// A key for an AEAD algorithm.
289///
290/// This is a value type for a byte string up to `AeadKey::MAX_LEN` bytes in length.
291pub struct AeadKey {
292    buf: [u8; Self::MAX_LEN],
293    used: usize,
294}
295
296impl AeadKey {
297    pub(crate) fn new(buf: &[u8]) -> Self {
298        debug_assert!(buf.len() <= Self::MAX_LEN);
299        let mut key = Self::from([0u8; Self::MAX_LEN]);
300        key.buf[..buf.len()].copy_from_slice(buf);
301        key.used = buf.len();
302        key
303    }
304
305    pub(crate) fn with_length(self, len: usize) -> Self {
306        assert!(len <= self.used);
307        Self {
308            buf: self.buf,
309            used: len,
310        }
311    }
312
313    /// Largest possible AEAD key in the ciphersuites we support.
314    pub(crate) const MAX_LEN: usize = 32;
315}
316
317impl Drop for AeadKey {
318    fn drop(&mut self) {
319        self.buf.zeroize();
320    }
321}
322
323impl AsRef<[u8]> for AeadKey {
324    fn as_ref(&self) -> &[u8] {
325        &self.buf[..self.used]
326    }
327}
328
329impl From<[u8; Self::MAX_LEN]> for AeadKey {
330    fn from(bytes: [u8; Self::MAX_LEN]) -> Self {
331        Self {
332            buf: bytes,
333            used: Self::MAX_LEN,
334        }
335    }
336}
337
338/// A `MessageEncrypter` which doesn't work.
339struct InvalidMessageEncrypter {}
340
341impl MessageEncrypter for InvalidMessageEncrypter {
342    fn encrypt(
343        &mut self,
344        _m: OutboundPlainMessage<'_>,
345        _seq: u64,
346    ) -> Result<OutboundOpaqueMessage, Error> {
347        Err(Error::EncryptError)
348    }
349
350    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
351        payload_len
352    }
353}
354
355/// A `MessageDecrypter` which doesn't work.
356struct InvalidMessageDecrypter {}
357
358impl MessageDecrypter for InvalidMessageDecrypter {
359    fn decrypt<'a>(
360        &mut self,
361        _m: InboundOpaqueMessage<'a>,
362        _seq: u64,
363    ) -> Result<InboundPlainMessage<'a>, Error> {
364        Err(Error::DecryptError)
365    }
366}
367#[cfg(test)]
368mod tests {
369    use super::*;
370
371    /// Using test values provided in the spec in
372    /// <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-15.html#section-2.4>
373    #[test]
374    fn multipath_nonce() {
375        const PATH_ID: u32 = 3;
376        const PN: u64 = 54321;
377        const IV: [u8; 16] = 0x6b26114b9cba2b63a9e8dd4fu128.to_be_bytes();
378        const EXPECTED_NONCE: [u8; 16] = 0x6b2611489cba2b63a9e8097eu128.to_be_bytes();
379        let nonce = Nonce::quic(Some(PATH_ID), &Iv::copy(&IV[4..]), PN).0;
380        assert_eq!(EXPECTED_NONCE[4..], nonce);
381    }
382}