1use crate::cipher::{make_nonce, Iv, MessageDecrypter, MessageEncrypter};
2use crate::enums::ContentType;
3use crate::enums::ProtocolVersion;
4use crate::error::Error;
5use crate::msgs::base::Payload;
6use crate::msgs::codec;
7use crate::msgs::fragmenter::MAX_FRAGMENT_LEN;
8use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage};
9
10use ring::aead;
11
12const TLS12_AAD_SIZE: usize = 8 + 1 + 2 + 2;
13
14fn make_tls12_aad(
15 seq: u64,
16 typ: ContentType,
17 vers: ProtocolVersion,
18 len: usize,
19) -> aead::Aad<[u8; TLS12_AAD_SIZE]> {
20 let mut out = [0; TLS12_AAD_SIZE];
21 codec::put_u64(seq, &mut out[0..]);
22 out[8] = typ.get_u8();
23 codec::put_u16(vers.get_u16(), &mut out[9..]);
24 codec::put_u16(len as u16, &mut out[11..]);
25 aead::Aad::from(out)
26}
27
28pub(crate) struct AesGcm;
29
30impl Tls12AeadAlgorithm for AesGcm {
31 fn decrypter(&self, dec_key: aead::LessSafeKey, dec_iv: &[u8]) -> Box<dyn MessageDecrypter> {
32 let mut ret = GcmMessageDecrypter {
33 dec_key,
34 dec_salt: [0u8; 4],
35 };
36
37 debug_assert_eq!(dec_iv.len(), 4);
38 ret.dec_salt.copy_from_slice(dec_iv);
39 Box::new(ret)
40 }
41
42 fn encrypter(
43 &self,
44 enc_key: aead::LessSafeKey,
45 write_iv: &[u8],
46 explicit: &[u8],
47 ) -> Box<dyn MessageEncrypter> {
48 debug_assert_eq!(write_iv.len(), 4);
49 debug_assert_eq!(explicit.len(), 8);
50
51 let mut iv = Iv(Default::default());
59 iv.0[..4].copy_from_slice(write_iv);
60 iv.0[4..].copy_from_slice(explicit);
61
62 Box::new(GcmMessageEncrypter { enc_key, iv })
63 }
64}
65
66pub(crate) struct ChaCha20Poly1305;
67
68impl Tls12AeadAlgorithm for ChaCha20Poly1305 {
69 fn decrypter(&self, dec_key: aead::LessSafeKey, iv: &[u8]) -> Box<dyn MessageDecrypter> {
70 Box::new(ChaCha20Poly1305MessageDecrypter {
71 dec_key,
72 dec_offset: Iv::copy(iv),
73 })
74 }
75
76 fn encrypter(
77 &self,
78 enc_key: aead::LessSafeKey,
79 enc_iv: &[u8],
80 _: &[u8],
81 ) -> Box<dyn MessageEncrypter> {
82 Box::new(ChaCha20Poly1305MessageEncrypter {
83 enc_key,
84 enc_offset: Iv::copy(enc_iv),
85 })
86 }
87}
88
89pub(crate) trait Tls12AeadAlgorithm: Send + Sync + 'static {
90 fn decrypter(&self, key: aead::LessSafeKey, iv: &[u8]) -> Box<dyn MessageDecrypter>;
91 fn encrypter(
92 &self,
93 key: aead::LessSafeKey,
94 iv: &[u8],
95 extra: &[u8],
96 ) -> Box<dyn MessageEncrypter>;
97}
98
99struct GcmMessageEncrypter {
101 enc_key: aead::LessSafeKey,
102 iv: Iv,
103}
104
105struct GcmMessageDecrypter {
107 dec_key: aead::LessSafeKey,
108 dec_salt: [u8; 4],
109}
110
111const GCM_EXPLICIT_NONCE_LEN: usize = 8;
112const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16;
113
114impl MessageDecrypter for GcmMessageDecrypter {
115 fn decrypt(&self, mut msg: OpaqueMessage, seq: u64) -> Result<PlainMessage, Error> {
116 let payload = &mut msg.payload.0;
117 if payload.len() < GCM_OVERHEAD {
118 return Err(Error::DecryptError);
119 }
120
121 let nonce = {
122 let mut nonce = [0u8; 12];
123 nonce[..4].copy_from_slice(&self.dec_salt);
124 nonce[4..].copy_from_slice(&payload[..8]);
125 aead::Nonce::assume_unique_for_key(nonce)
126 };
127
128 let aad = make_tls12_aad(seq, msg.typ, msg.version, payload.len() - GCM_OVERHEAD);
129
130 let plain_len = self
131 .dec_key
132 .open_within(nonce, aad, payload, GCM_EXPLICIT_NONCE_LEN..)
133 .map_err(|_| Error::DecryptError)?
134 .len();
135
136 if plain_len > MAX_FRAGMENT_LEN {
137 return Err(Error::PeerSentOversizedRecord);
138 }
139
140 payload.truncate(plain_len);
141 Ok(msg.into_plain_message())
142 }
143}
144
145impl MessageEncrypter for GcmMessageEncrypter {
146 fn encrypt(&self, msg: BorrowedPlainMessage, seq: u64) -> Result<OpaqueMessage, Error> {
147 let nonce = make_nonce(&self.iv, seq);
148 let aad = make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len());
149
150 let total_len = msg.payload.len() + self.enc_key.algorithm().tag_len();
151 let mut payload = Vec::with_capacity(GCM_EXPLICIT_NONCE_LEN + total_len);
152 payload.extend_from_slice(&nonce.as_ref()[4..]);
153 payload.extend_from_slice(msg.payload);
154
155 self.enc_key
156 .seal_in_place_separate_tag(nonce, aad, &mut payload[GCM_EXPLICIT_NONCE_LEN..])
157 .map(|tag| payload.extend(tag.as_ref()))
158 .map_err(|_| Error::EncryptError)?;
159
160 Ok(OpaqueMessage {
161 typ: msg.typ,
162 version: msg.version,
163 payload: Payload::new(payload),
164 })
165 }
166}
167
168struct ChaCha20Poly1305MessageEncrypter {
172 enc_key: aead::LessSafeKey,
173 enc_offset: Iv,
174}
175
176struct ChaCha20Poly1305MessageDecrypter {
180 dec_key: aead::LessSafeKey,
181 dec_offset: Iv,
182}
183
184const CHACHAPOLY1305_OVERHEAD: usize = 16;
185
186impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter {
187 fn decrypt(&self, mut msg: OpaqueMessage, seq: u64) -> Result<PlainMessage, Error> {
188 let payload = &mut msg.payload.0;
189
190 if payload.len() < CHACHAPOLY1305_OVERHEAD {
191 return Err(Error::DecryptError);
192 }
193
194 let nonce = make_nonce(&self.dec_offset, seq);
195 let aad = make_tls12_aad(
196 seq,
197 msg.typ,
198 msg.version,
199 payload.len() - CHACHAPOLY1305_OVERHEAD,
200 );
201
202 let plain_len = self
203 .dec_key
204 .open_in_place(nonce, aad, payload)
205 .map_err(|_| Error::DecryptError)?
206 .len();
207
208 if plain_len > MAX_FRAGMENT_LEN {
209 return Err(Error::PeerSentOversizedRecord);
210 }
211
212 payload.truncate(plain_len);
213 Ok(msg.into_plain_message())
214 }
215}
216
217impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter {
218 fn encrypt(&self, msg: BorrowedPlainMessage, seq: u64) -> Result<OpaqueMessage, Error> {
219 let nonce = make_nonce(&self.enc_offset, seq);
220 let aad = make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len());
221
222 let total_len = msg.payload.len() + self.enc_key.algorithm().tag_len();
223 let mut buf = Vec::with_capacity(total_len);
224 buf.extend_from_slice(msg.payload);
225
226 self.enc_key
227 .seal_in_place_append_tag(nonce, aad, &mut buf)
228 .map_err(|_| Error::EncryptError)?;
229
230 Ok(OpaqueMessage {
231 typ: msg.typ,
232 version: msg.version,
233 payload: Payload::new(buf),
234 })
235 }
236}