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