1 //! PublicKey-Encrypted Session Key packets. 2 //! 3 //! The session key is needed to decrypt the actual ciphertext. See 4 //! [Section 5.1 of RFC 4880] for details. 5 //! 6 //! [Section 5.1 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.1 7 8 #[cfg(any(test, feature = "quickcheck"))] 9 use quickcheck::{Arbitrary, Gen}; 10 11 use crate::Error; 12 use crate::packet::key; 13 use crate::packet::Key; 14 use crate::KeyID; 15 use crate::crypto::Decryptor; 16 use crate::crypto::mpi::Ciphertext; 17 use crate::Packet; 18 use crate::PublicKeyAlgorithm; 19 use crate::Result; 20 use crate::SymmetricAlgorithm; 21 use crate::crypto::SessionKey; 22 use crate::packet; 23 24 /// Holds an asymmetrically encrypted session key. 25 /// 26 /// The session key is needed to decrypt the actual ciphertext. See 27 /// [Section 5.1 of RFC 4880] for details. 28 /// 29 /// [Section 5.1 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.1 30 // IMPORTANT: If you add fields to this struct, you need to explicitly 31 // IMPORTANT: implement PartialEq, Eq, and Hash. 32 #[derive(Clone, Debug, PartialEq, Eq, Hash)] 33 pub struct PKESK3 { 34 /// CTB header fields. 35 pub(crate) common: packet::Common, 36 /// Key ID of the key this is encrypted to. 37 recipient: KeyID, 38 /// Public key algorithm used to encrypt the session key. 39 pk_algo: PublicKeyAlgorithm, 40 /// The encrypted session key. 41 esk: Ciphertext, 42 } 43 44 impl PKESK3 { 45 /// Creates a new PKESK3 packet. new(recipient: KeyID, pk_algo: PublicKeyAlgorithm, encrypted_session_key: Ciphertext) -> Result<PKESK3>46 pub fn new(recipient: KeyID, pk_algo: PublicKeyAlgorithm, 47 encrypted_session_key: Ciphertext) 48 -> Result<PKESK3> { 49 Ok(PKESK3 { 50 common: Default::default(), 51 recipient, 52 pk_algo, 53 esk: encrypted_session_key, 54 }) 55 } 56 57 /// Creates a new PKESK3 packet for the given recipent. 58 /// 59 /// The given symmetric algorithm must match the algorithm that is 60 /// used to encrypt the payload. for_recipient<P, R>(algo: SymmetricAlgorithm, session_key: &SessionKey, recipient: &Key<P, R>) -> Result<PKESK3> where P: key::KeyParts, R: key::KeyRole,61 pub fn for_recipient<P, R>(algo: SymmetricAlgorithm, 62 session_key: &SessionKey, 63 recipient: &Key<P, R>) 64 -> Result<PKESK3> 65 where P: key::KeyParts, 66 R: key::KeyRole, 67 { 68 // We need to prefix the cipher specifier to the session key, 69 // and a two-octet checksum. 70 let mut psk = Vec::with_capacity(1 + session_key.len() + 2); 71 psk.push(algo.into()); 72 psk.extend_from_slice(session_key); 73 74 // Compute the sum modulo 65536, i.e. as u16. 75 let checksum = session_key 76 .iter() 77 .cloned() 78 .map(u16::from) 79 .fold(0u16, u16::wrapping_add); 80 81 psk.extend_from_slice(&checksum.to_be_bytes()); 82 83 let psk: SessionKey = psk.into(); 84 let esk = recipient.encrypt(&psk)?; 85 Ok(PKESK3{ 86 common: Default::default(), 87 recipient: recipient.keyid(), 88 pk_algo: recipient.pk_algo(), 89 esk, 90 }) 91 } 92 93 /// Gets the recipient. recipient(&self) -> &KeyID94 pub fn recipient(&self) -> &KeyID { 95 &self.recipient 96 } 97 98 /// Sets the recipient. set_recipient(&mut self, recipient: KeyID) -> KeyID99 pub fn set_recipient(&mut self, recipient: KeyID) -> KeyID { 100 ::std::mem::replace(&mut self.recipient, recipient) 101 } 102 103 /// Gets the public key algorithm. pk_algo(&self) -> PublicKeyAlgorithm104 pub fn pk_algo(&self) -> PublicKeyAlgorithm { 105 self.pk_algo 106 } 107 108 /// Sets the public key algorithm. set_pk_algo(&mut self, algo: PublicKeyAlgorithm) -> PublicKeyAlgorithm109 pub fn set_pk_algo(&mut self, algo: PublicKeyAlgorithm) -> PublicKeyAlgorithm { 110 ::std::mem::replace(&mut self.pk_algo, algo) 111 } 112 113 /// Gets the encrypted session key. esk(&self) -> &Ciphertext114 pub fn esk(&self) -> &Ciphertext { 115 &self.esk 116 } 117 118 /// Sets the encrypted session key. set_esk(&mut self, esk: Ciphertext) -> Ciphertext119 pub fn set_esk(&mut self, esk: Ciphertext) -> Ciphertext { 120 ::std::mem::replace(&mut self.esk, esk) 121 } 122 123 /// Decrypts the encrypted session key. 124 /// 125 /// If the symmetric algorithm used to encrypt the message is 126 /// known in advance, it should be given as argument. This allows 127 /// us to reduce the side-channel leakage of the decryption 128 /// operation for RSA. 129 /// 130 /// Returns the session key and symmetric algorithm used to 131 /// encrypt the following payload. 132 /// 133 /// Returns `None` on errors. This prevents leaking information 134 /// to an attacker, which could lead to compromise of secret key 135 /// material with certain algorithms (RSA). See [Section 14 of 136 /// RFC 4880]. 137 /// 138 /// [Section 14 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-14 decrypt(&self, decryptor: &mut dyn Decryptor, sym_algo_hint: Option<SymmetricAlgorithm>) -> Option<(SymmetricAlgorithm, SessionKey)>139 pub fn decrypt(&self, decryptor: &mut dyn Decryptor, 140 sym_algo_hint: Option<SymmetricAlgorithm>) 141 -> Option<(SymmetricAlgorithm, SessionKey)> 142 { 143 self.decrypt_insecure(decryptor, sym_algo_hint).ok() 144 } 145 decrypt_insecure(&self, decryptor: &mut dyn Decryptor, sym_algo_hint: Option<SymmetricAlgorithm>) -> Result<(SymmetricAlgorithm, SessionKey)>146 fn decrypt_insecure(&self, decryptor: &mut dyn Decryptor, 147 sym_algo_hint: Option<SymmetricAlgorithm>) 148 -> Result<(SymmetricAlgorithm, SessionKey)> 149 { 150 let plaintext_len = if let Some(s) = sym_algo_hint { 151 Some(1 /* cipher octet */ + s.key_size()? + 2 /* chksum */) 152 } else { 153 None 154 }; 155 let plain = decryptor.decrypt(&self.esk, plaintext_len)?; 156 let key_rgn = 1..(plain.len() - 2); 157 let sym_algo: SymmetricAlgorithm = plain[0].into(); 158 let mut key: SessionKey = vec![0u8; sym_algo.key_size()?].into(); 159 160 if key_rgn.len() != sym_algo.key_size()? { 161 return Err(Error::MalformedPacket( 162 format!("session key has the wrong size")).into()); 163 } 164 165 key.copy_from_slice(&plain[key_rgn]); 166 167 let our_checksum 168 = key.iter().map(|&x| x as usize).sum::<usize>() & 0xffff; 169 let their_checksum = (plain[plain.len() - 2] as usize) << 8 170 | (plain[plain.len() - 1] as usize); 171 172 if their_checksum == our_checksum { 173 Ok((sym_algo, key)) 174 } else { 175 Err(Error::MalformedPacket(format!("key checksum wrong")) 176 .into()) 177 } 178 } 179 } 180 181 impl From<PKESK3> for super::PKESK { from(p: PKESK3) -> Self182 fn from(p: PKESK3) -> Self { 183 super::PKESK::V3(p) 184 } 185 } 186 187 impl From<PKESK3> for Packet { from(p: PKESK3) -> Self188 fn from(p: PKESK3) -> Self { 189 Packet::PKESK(p.into()) 190 } 191 } 192 193 #[cfg(any(test, feature = "quickcheck"))] 194 impl Arbitrary for super::PKESK { arbitrary<G: Gen>(g: &mut G) -> Self195 fn arbitrary<G: Gen>(g: &mut G) -> Self { 196 PKESK3::arbitrary(g).into() 197 } 198 } 199 200 #[cfg(any(test, feature = "quickcheck"))] 201 impl Arbitrary for PKESK3 { arbitrary<G: Gen>(g: &mut G) -> Self202 fn arbitrary<G: Gen>(g: &mut G) -> Self { 203 let (ciphertext, pk_algo) = loop { 204 let ciphertext = Ciphertext::arbitrary(g); 205 if let Some(pk_algo) = ciphertext.pk_algo() { 206 break (ciphertext, pk_algo); 207 } 208 }; 209 210 PKESK3::new(KeyID::arbitrary(g), pk_algo, ciphertext).unwrap() 211 } 212 } 213 214 #[cfg(test)] 215 mod tests { 216 use super::*; 217 use crate::Cert; 218 use crate::PacketPile; 219 use crate::Packet; 220 use crate::parse::Parse; 221 use crate::serialize::MarshalInto; 222 223 quickcheck! { 224 fn roundtrip(p: PKESK3) -> bool { 225 let q = PKESK3::from_bytes(&p.to_vec().unwrap()).unwrap(); 226 assert_eq!(p, q); 227 true 228 } 229 } 230 231 #[test] decrypt_rsa()232 fn decrypt_rsa() { 233 let cert = Cert::from_bytes( 234 crate::tests::key("testy-private.pgp")).unwrap(); 235 let pile = PacketPile::from_bytes( 236 crate::tests::message("encrypted-to-testy.gpg")).unwrap(); 237 let mut keypair = 238 cert.subkeys().next().unwrap() 239 .key().clone().parts_into_secret().unwrap().into_keypair().unwrap(); 240 241 let pkg = pile.descendants().skip(0).next().clone(); 242 243 if let Some(Packet::PKESK(ref pkesk)) = pkg { 244 let plain = pkesk.decrypt(&mut keypair, None).unwrap(); 245 let plain_ = 246 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256)) 247 .unwrap(); 248 assert_eq!(plain, plain_); 249 250 eprintln!("plain: {:?}", plain); 251 } else { 252 panic!("message is not a PKESK packet"); 253 } 254 } 255 256 #[test] decrypt_ecdh_cv25519()257 fn decrypt_ecdh_cv25519() { 258 let cert = Cert::from_bytes( 259 crate::tests::key("testy-new-private.pgp")).unwrap(); 260 let pile = PacketPile::from_bytes( 261 crate::tests::message("encrypted-to-testy-new.pgp")).unwrap(); 262 let mut keypair = 263 cert.subkeys().next().unwrap() 264 .key().clone().parts_into_secret().unwrap().into_keypair().unwrap(); 265 266 let pkg = pile.descendants().skip(0).next().clone(); 267 268 if let Some(Packet::PKESK(ref pkesk)) = pkg { 269 let plain = pkesk.decrypt(&mut keypair, None).unwrap(); 270 let plain_ = 271 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256)) 272 .unwrap(); 273 assert_eq!(plain, plain_); 274 275 eprintln!("plain: {:?}", plain); 276 } else { 277 panic!("message is not a PKESK packet"); 278 } 279 } 280 281 #[test] decrypt_ecdh_nistp256()282 fn decrypt_ecdh_nistp256() { 283 let cert = Cert::from_bytes( 284 crate::tests::key("testy-nistp256-private.pgp")).unwrap(); 285 let pile = PacketPile::from_bytes( 286 crate::tests::message("encrypted-to-testy-nistp256.pgp")).unwrap(); 287 let mut keypair = 288 cert.subkeys().next().unwrap() 289 .key().clone().parts_into_secret().unwrap().into_keypair().unwrap(); 290 291 let pkg = pile.descendants().skip(0).next().clone(); 292 293 if let Some(Packet::PKESK(ref pkesk)) = pkg { 294 let plain = pkesk.decrypt(&mut keypair, None).unwrap(); 295 let plain_ = 296 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256)) 297 .unwrap(); 298 assert_eq!(plain, plain_); 299 300 eprintln!("plain: {:?}", plain); 301 } else { 302 panic!("message is not a PKESK packet"); 303 } 304 } 305 306 #[test] decrypt_ecdh_nistp384()307 fn decrypt_ecdh_nistp384() { 308 let cert = Cert::from_bytes( 309 crate::tests::key("testy-nistp384-private.pgp")).unwrap(); 310 let pile = PacketPile::from_bytes( 311 crate::tests::message("encrypted-to-testy-nistp384.pgp")).unwrap(); 312 let mut keypair = 313 cert.subkeys().next().unwrap() 314 .key().clone().parts_into_secret().unwrap().into_keypair().unwrap(); 315 316 let pkg = pile.descendants().skip(0).next().clone(); 317 318 if let Some(Packet::PKESK(ref pkesk)) = pkg { 319 let plain = pkesk.decrypt(&mut keypair, None).unwrap(); 320 let plain_ = 321 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256)) 322 .unwrap(); 323 assert_eq!(plain, plain_); 324 325 eprintln!("plain: {:?}", plain); 326 } else { 327 panic!("message is not a PKESK packet"); 328 } 329 } 330 331 #[test] decrypt_ecdh_nistp521()332 fn decrypt_ecdh_nistp521() { 333 let cert = Cert::from_bytes( 334 crate::tests::key("testy-nistp521-private.pgp")).unwrap(); 335 let pile = PacketPile::from_bytes( 336 crate::tests::message("encrypted-to-testy-nistp521.pgp")).unwrap(); 337 let mut keypair = 338 cert.subkeys().next().unwrap() 339 .key().clone().parts_into_secret().unwrap().into_keypair().unwrap(); 340 341 let pkg = pile.descendants().skip(0).next().clone(); 342 343 if let Some(Packet::PKESK(ref pkesk)) = pkg { 344 let plain = pkesk.decrypt(&mut keypair, None).unwrap(); 345 let plain_ = 346 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256)) 347 .unwrap(); 348 assert_eq!(plain, plain_); 349 350 eprintln!("plain: {:?}", plain); 351 } else { 352 panic!("message is not a PKESK packet"); 353 } 354 } 355 356 357 #[test] decrypt_with_short_cv25519_secret_key()358 fn decrypt_with_short_cv25519_secret_key() { 359 use super::PKESK3; 360 use crate::crypto::SessionKey; 361 use crate::{HashAlgorithm, SymmetricAlgorithm}; 362 use crate::packet::key::{Key4, UnspecifiedRole}; 363 364 // 20 byte sec key 365 let mut secret_key = [ 366 0x0,0x0, 367 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 368 0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2, 369 0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x0 370 ]; 371 // Ensure that the key is at least somewhat valid, according to the 372 // generation procedure specified in "Responsibilities of the user": 373 // https://cr.yp.to/ecdh/curve25519-20060209.pdf#page=5 374 // Only perform the bit-twiddling on the last byte. This is done so that 375 // we can still have somewhat defined multiplication while still testing 376 // the "short" key logic. 377 // secret_key[0] &= 0xf8; 378 secret_key[31] &= 0x7f; 379 secret_key[31] |= 0x40; 380 381 let key: Key<_, UnspecifiedRole> = Key4::import_secret_cv25519( 382 &secret_key, 383 HashAlgorithm::SHA256, 384 SymmetricAlgorithm::AES256, 385 None, 386 ).unwrap().into(); 387 388 let sess_key = SessionKey::new(32); 389 let pkesk = PKESK3::for_recipient(SymmetricAlgorithm::AES256, &sess_key, 390 &key).unwrap(); 391 let mut keypair = key.into_keypair().unwrap(); 392 pkesk.decrypt(&mut keypair, None).unwrap(); 393 } 394 } 395