Coverage Report

Created: 2026-10-28 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-0.23.46/src/crypto/cipher.rs
Line
Count
Source
1
use alloc::boxed::Box;
2
use alloc::string::ToString;
3
use core::fmt;
4
5
use zeroize::Zeroize;
6
7
use crate::enums::{ContentType, ProtocolVersion};
8
use crate::error::Error;
9
use crate::msgs::codec;
10
pub use crate::msgs::message::{
11
    BorrowedPayload, InboundOpaqueMessage, InboundPlainMessage, OutboundChunks,
12
    OutboundOpaqueMessage, OutboundPlainMessage, PlainMessage, PrefixedPayload,
13
};
14
use crate::suites::ConnectionTrafficSecrets;
15
16
/// Factory trait for building `MessageEncrypter` and `MessageDecrypter` for a TLS1.3 cipher suite.
17
pub 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
0
    fn fips(&self) -> bool {
39
0
        false
40
0
    }
Unexecuted instantiation: <_ as rustls::crypto::cipher::Tls13AeadAlgorithm>::fips
Unexecuted instantiation: <_ as rustls::crypto::cipher::Tls13AeadAlgorithm>::fips
Unexecuted instantiation: <_ as rustls::crypto::cipher::Tls13AeadAlgorithm>::fips
41
}
42
43
/// Factory trait for building `MessageEncrypter` and `MessageDecrypter` for a TLS1.2 cipher suite.
44
pub 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
0
    fn fips(&self) -> bool {
85
0
        false
86
0
    }
Unexecuted instantiation: <_ as rustls::crypto::cipher::Tls12AeadAlgorithm>::fips
Unexecuted instantiation: <_ as rustls::crypto::cipher::Tls12AeadAlgorithm>::fips
Unexecuted instantiation: <_ as rustls::crypto::cipher::Tls12AeadAlgorithm>::fips
87
}
88
89
/// An error indicating that the AEAD algorithm does not support the requested operation.
90
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
91
pub struct UnsupportedOperationError;
92
93
impl From<UnsupportedOperationError> for Error {
94
0
    fn from(value: UnsupportedOperationError) -> Self {
95
0
        Self::General(value.to_string())
96
0
    }
Unexecuted instantiation: <rustls::error::Error as core::convert::From<rustls::crypto::cipher::UnsupportedOperationError>>::from
Unexecuted instantiation: <rustls::error::Error as core::convert::From<rustls::crypto::cipher::UnsupportedOperationError>>::from
Unexecuted instantiation: <rustls::error::Error as core::convert::From<rustls::crypto::cipher::UnsupportedOperationError>>::from
97
}
98
99
impl fmt::Display for UnsupportedOperationError {
100
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101
0
        write!(f, "operation not supported")
102
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::UnsupportedOperationError as core::fmt::Display>::fmt
Unexecuted instantiation: <rustls::crypto::cipher::UnsupportedOperationError as core::fmt::Display>::fmt
Unexecuted instantiation: <rustls::crypto::cipher::UnsupportedOperationError as core::fmt::Display>::fmt
103
}
104
105
#[cfg(feature = "std")]
106
impl std::error::Error for UnsupportedOperationError {}
107
108
/// How a TLS1.2 `key_block` is partitioned.
109
///
110
/// Note: ciphersuites with non-zero `mac_key_length` are  not currently supported.
111
pub struct KeyBlockShape {
112
    /// How long keys are.
113
    ///
114
    /// `enc_key_length` terminology is from the standard ([RFC5246 A.6]).
115
    ///
116
    /// [RFC5246 A.6]: <https://www.rfc-editor.org/rfc/rfc5246#appendix-A.6>
117
    pub enc_key_len: usize,
118
119
    /// How long the fixed part of the 'IV' is.
120
    ///
121
    /// `fixed_iv_length` terminology is from the standard ([RFC5246 A.6]).
122
    ///
123
    /// This isn't usually an IV, but we continue the
124
    /// terminology misuse to match the standard.
125
    ///
126
    /// [RFC5246 A.6]: <https://www.rfc-editor.org/rfc/rfc5246#appendix-A.6>
127
    pub fixed_iv_len: usize,
128
129
    /// This is a non-standard extension which extends the
130
    /// key block to provide an initial explicit nonce offset,
131
    /// in a deterministic and safe way.  GCM needs this,
132
    /// chacha20poly1305 works this way by design.
133
    pub explicit_nonce_len: usize,
134
}
135
136
/// Objects with this trait can decrypt TLS messages.
137
pub trait MessageDecrypter: Send + Sync {
138
    /// Decrypt the given TLS message `msg`, using the sequence number
139
    /// `seq` which can be used to derive a unique [`Nonce`].
140
    fn decrypt<'a>(
141
        &mut self,
142
        msg: InboundOpaqueMessage<'a>,
143
        seq: u64,
144
    ) -> Result<InboundPlainMessage<'a>, Error>;
145
}
146
147
/// Objects with this trait can encrypt TLS messages.
148
pub trait MessageEncrypter: Send + Sync {
149
    /// Encrypt the given TLS message `msg`, using the sequence number
150
    /// `seq` which can be used to derive a unique [`Nonce`].
151
    fn encrypt(
152
        &mut self,
153
        msg: OutboundPlainMessage<'_>,
154
        seq: u64,
155
    ) -> Result<OutboundOpaqueMessage, Error>;
156
157
    /// Return the length of the ciphertext that results from encrypting plaintext of
158
    /// length `payload_len`
159
    fn encrypted_payload_len(&self, payload_len: usize) -> usize;
160
}
161
162
impl dyn MessageEncrypter {
163
0
    pub(crate) fn invalid() -> Box<dyn MessageEncrypter> {
164
0
        Box::new(InvalidMessageEncrypter {})
165
0
    }
Unexecuted instantiation: <dyn rustls::crypto::cipher::MessageEncrypter>::invalid
Unexecuted instantiation: <dyn rustls::crypto::cipher::MessageEncrypter>::invalid
Unexecuted instantiation: <dyn rustls::crypto::cipher::MessageEncrypter>::invalid
166
}
167
168
impl dyn MessageDecrypter {
169
0
    pub(crate) fn invalid() -> Box<dyn MessageDecrypter> {
170
0
        Box::new(InvalidMessageDecrypter {})
171
0
    }
Unexecuted instantiation: <dyn rustls::crypto::cipher::MessageDecrypter>::invalid
Unexecuted instantiation: <dyn rustls::crypto::cipher::MessageDecrypter>::invalid
Unexecuted instantiation: <dyn rustls::crypto::cipher::MessageDecrypter>::invalid
172
}
173
174
/// A write or read IV.
175
#[derive(Default)]
176
pub struct Iv([u8; NONCE_LEN]);
177
178
impl Iv {
179
    /// Create a new `Iv` from a byte array, of precisely `NONCE_LEN` bytes.
180
    #[cfg(feature = "tls12")]
181
    pub fn new(value: [u8; NONCE_LEN]) -> Self {
182
        Self(value)
183
    }
184
185
    /// Create a new `Iv` from a byte slice, of precisely `NONCE_LEN` bytes.
186
    #[cfg(feature = "tls12")]
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
195
impl From<[u8; NONCE_LEN]> for Iv {
196
0
    fn from(bytes: [u8; NONCE_LEN]) -> Self {
197
0
        Self(bytes)
198
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::Iv as core::convert::From<[u8; 12]>>::from
Unexecuted instantiation: <rustls::crypto::cipher::Iv as core::convert::From<[u8; 12]>>::from
Unexecuted instantiation: <rustls::crypto::cipher::Iv as core::convert::From<[u8; 12]>>::from
199
}
200
201
impl AsRef<[u8]> for Iv {
202
0
    fn as_ref(&self) -> &[u8] {
203
0
        self.0.as_ref()
204
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::Iv as core::convert::AsRef<[u8]>>::as_ref
Unexecuted instantiation: <rustls::crypto::cipher::Iv as core::convert::AsRef<[u8]>>::as_ref
Unexecuted instantiation: <rustls::crypto::cipher::Iv as core::convert::AsRef<[u8]>>::as_ref
205
}
206
207
/// A nonce.  This is unique for all messages on a connection.
208
pub struct Nonce(pub [u8; NONCE_LEN]);
209
210
impl Nonce {
211
    /// Combine an `Iv` and sequence number to produce a unique nonce.
212
    ///
213
    /// This is `iv ^ seq` where `seq` is encoded as a 96-bit big-endian integer.
214
    #[inline]
215
0
    pub fn new(iv: &Iv, seq: u64) -> Self {
216
0
        let mut seq_bytes = [0u8; NONCE_LEN];
217
0
        codec::put_u64(seq, &mut seq_bytes[4..]);
218
0
        Self::new_from_seq(iv, seq_bytes)
219
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::new
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::new
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::new
220
221
    /// Creates a unique nonce based on the `iv`, the packet number `pn` and multipath `path_id`.
222
    ///
223
    /// The nonce is computed as the XOR between the `iv` and the 96-bit big-ending integer formed
224
    /// by concatenating `path_id` and `pn`.
225
0
    pub fn for_path(path_id: u32, iv: &Iv, pn: u64) -> Self {
226
0
        let mut seq_bytes = [0u8; NONCE_LEN];
227
0
        seq_bytes[0..4].copy_from_slice(&path_id.to_be_bytes());
228
0
        codec::put_u64(pn, &mut seq_bytes[4..]);
229
0
        Self::new_from_seq(iv, seq_bytes)
230
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::for_path
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::for_path
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::for_path
231
232
    /// Creates a unique nonce based on the `iv` and sequence number `seq`.
233
    #[inline]
234
0
    fn new_from_seq(iv: &Iv, mut seq: [u8; NONCE_LEN]) -> Self {
235
0
        seq.iter_mut()
236
0
            .zip(iv.0.iter())
237
0
            .for_each(|(s, iv)| {
238
0
                *s ^= *iv;
239
0
            });
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::new_from_seq::{closure#0}
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::new_from_seq::{closure#0}
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::new_from_seq::{closure#0}
240
241
0
        Self(seq)
242
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::new_from_seq
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::new_from_seq
Unexecuted instantiation: <rustls::crypto::cipher::Nonce>::new_from_seq
243
}
244
245
/// Size of TLS nonces (incorrectly termed "IV" in standard) for all supported ciphersuites
246
/// (AES-GCM, Chacha20Poly1305)
247
pub const NONCE_LEN: usize = 12;
248
249
/// Returns a TLS1.3 `additional_data` encoding.
250
///
251
/// See RFC8446 s5.2 for the `additional_data` definition.
252
#[inline]
253
0
pub fn make_tls13_aad(payload_len: usize) -> [u8; 5] {
254
0
    let version = ProtocolVersion::TLSv1_2.to_array();
255
0
    [
256
0
        ContentType::ApplicationData.into(),
257
0
        // Note: this is `legacy_record_version`, i.e. TLS1.2 even for TLS1.3.
258
0
        version[0],
259
0
        version[1],
260
0
        (payload_len >> 8) as u8,
261
0
        (payload_len & 0xff) as u8,
262
0
    ]
263
0
}
Unexecuted instantiation: rustls::crypto::cipher::make_tls13_aad
Unexecuted instantiation: rustls::crypto::cipher::make_tls13_aad
Unexecuted instantiation: rustls::crypto::cipher::make_tls13_aad
264
265
/// Returns a TLS1.2 `additional_data` encoding.
266
///
267
/// See RFC5246 s6.2.3.3 for the `additional_data` definition.
268
#[inline]
269
0
pub fn make_tls12_aad(
270
0
    seq: u64,
271
0
    typ: ContentType,
272
0
    vers: ProtocolVersion,
273
0
    len: usize,
274
0
) -> [u8; TLS12_AAD_SIZE] {
275
0
    let mut out = [0; TLS12_AAD_SIZE];
276
0
    codec::put_u64(seq, &mut out[0..]);
277
0
    out[8] = typ.into();
278
0
    codec::put_u16(vers.into(), &mut out[9..]);
279
0
    codec::put_u16(len as u16, &mut out[11..]);
280
0
    out
281
0
}
Unexecuted instantiation: rustls::crypto::cipher::make_tls12_aad
Unexecuted instantiation: rustls::crypto::cipher::make_tls12_aad
Unexecuted instantiation: rustls::crypto::cipher::make_tls12_aad
282
283
const TLS12_AAD_SIZE: usize = 8 + 1 + 2 + 2;
284
285
/// A key for an AEAD algorithm.
286
///
287
/// This is a value type for a byte string up to `AeadKey::MAX_LEN` bytes in length.
288
pub struct AeadKey {
289
    buf: [u8; Self::MAX_LEN],
290
    used: usize,
291
}
292
293
impl AeadKey {
294
    #[cfg(feature = "tls12")]
295
    pub(crate) fn new(buf: &[u8]) -> Self {
296
        debug_assert!(buf.len() <= Self::MAX_LEN);
297
        let mut key = Self::from([0u8; Self::MAX_LEN]);
298
        key.buf[..buf.len()].copy_from_slice(buf);
299
        key.used = buf.len();
300
        key
301
    }
302
303
0
    pub(crate) fn with_length(self, len: usize) -> Self {
304
0
        assert!(len <= self.used);
305
0
        Self {
306
0
            buf: self.buf,
307
0
            used: len,
308
0
        }
309
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey>::with_length
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey>::with_length
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey>::with_length
310
311
    /// Largest possible AEAD key in the ciphersuites we support.
312
    pub(crate) const MAX_LEN: usize = 32;
313
}
314
315
impl Drop for AeadKey {
316
0
    fn drop(&mut self) {
317
0
        self.buf.zeroize();
318
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey as core::ops::drop::Drop>::drop
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey as core::ops::drop::Drop>::drop
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey as core::ops::drop::Drop>::drop
319
}
320
321
impl AsRef<[u8]> for AeadKey {
322
0
    fn as_ref(&self) -> &[u8] {
323
0
        &self.buf[..self.used]
324
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey as core::convert::AsRef<[u8]>>::as_ref
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey as core::convert::AsRef<[u8]>>::as_ref
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey as core::convert::AsRef<[u8]>>::as_ref
325
}
326
327
impl From<[u8; Self::MAX_LEN]> for AeadKey {
328
0
    fn from(bytes: [u8; Self::MAX_LEN]) -> Self {
329
0
        Self {
330
0
            buf: bytes,
331
0
            used: Self::MAX_LEN,
332
0
        }
333
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey as core::convert::From<[u8; 32]>>::from
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey as core::convert::From<[u8; 32]>>::from
Unexecuted instantiation: <rustls::crypto::cipher::AeadKey as core::convert::From<[u8; 32]>>::from
334
}
335
336
/// A `MessageEncrypter` which doesn't work.
337
struct InvalidMessageEncrypter {}
338
339
impl MessageEncrypter for InvalidMessageEncrypter {
340
0
    fn encrypt(
341
0
        &mut self,
342
0
        _m: OutboundPlainMessage<'_>,
343
0
        _seq: u64,
344
0
    ) -> Result<OutboundOpaqueMessage, Error> {
345
0
        Err(Error::EncryptError)
346
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::InvalidMessageEncrypter as rustls::crypto::cipher::MessageEncrypter>::encrypt
Unexecuted instantiation: <rustls::crypto::cipher::InvalidMessageEncrypter as rustls::crypto::cipher::MessageEncrypter>::encrypt
Unexecuted instantiation: <rustls::crypto::cipher::InvalidMessageEncrypter as rustls::crypto::cipher::MessageEncrypter>::encrypt
347
348
0
    fn encrypted_payload_len(&self, payload_len: usize) -> usize {
349
0
        payload_len
350
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::InvalidMessageEncrypter as rustls::crypto::cipher::MessageEncrypter>::encrypted_payload_len
Unexecuted instantiation: <rustls::crypto::cipher::InvalidMessageEncrypter as rustls::crypto::cipher::MessageEncrypter>::encrypted_payload_len
Unexecuted instantiation: <rustls::crypto::cipher::InvalidMessageEncrypter as rustls::crypto::cipher::MessageEncrypter>::encrypted_payload_len
351
}
352
353
/// A `MessageDecrypter` which doesn't work.
354
struct InvalidMessageDecrypter {}
355
356
impl MessageDecrypter for InvalidMessageDecrypter {
357
0
    fn decrypt<'a>(
358
0
        &mut self,
359
0
        _m: InboundOpaqueMessage<'a>,
360
0
        _seq: u64,
361
0
    ) -> Result<InboundPlainMessage<'a>, Error> {
362
0
        Err(Error::DecryptError)
363
0
    }
Unexecuted instantiation: <rustls::crypto::cipher::InvalidMessageDecrypter as rustls::crypto::cipher::MessageDecrypter>::decrypt
Unexecuted instantiation: <rustls::crypto::cipher::InvalidMessageDecrypter as rustls::crypto::cipher::MessageDecrypter>::decrypt
Unexecuted instantiation: <rustls::crypto::cipher::InvalidMessageDecrypter as rustls::crypto::cipher::MessageDecrypter>::decrypt
364
}