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