sequoia_openpgp/packet/pkesk/
v3.rs1#[cfg(test)]
9use quickcheck::{Arbitrary, Gen};
10
11use crate::packet::key;
12use crate::packet::Key;
13use crate::KeyID;
14use crate::crypto::Decryptor;
15use crate::crypto::mpi::Ciphertext;
16use crate::Packet;
17use crate::PublicKeyAlgorithm;
18use crate::Result;
19use crate::SymmetricAlgorithm;
20use crate::crypto::SessionKey;
21use crate::packet;
22
23#[derive(Clone, Debug, PartialEq, Eq, Hash)]
32pub struct PKESK3 {
33 pub(crate) common: packet::Common,
35 recipient: Option<KeyID>,
37 pk_algo: PublicKeyAlgorithm,
39 esk: Ciphertext,
41}
42
43assert_send_and_sync!(PKESK3);
44
45impl PKESK3 {
46 pub fn new(recipient: Option<KeyID>,
48 pk_algo: PublicKeyAlgorithm,
49 encrypted_session_key: Ciphertext)
50 -> Result<PKESK3> {
51 let recipient =
53 if recipient.as_ref().map(KeyID::is_wildcard).unwrap_or(true) {
54 None
55 } else {
56 recipient
57 };
58
59 Ok(PKESK3 {
60 common: Default::default(),
61 recipient,
62 pk_algo,
63 esk: encrypted_session_key,
64 })
65 }
66
67 pub fn for_recipient<P, R>(algo: SymmetricAlgorithm,
72 session_key: &SessionKey,
73 recipient: &Key<P, R>)
74 -> Result<PKESK3>
75 where P: key::KeyParts,
76 R: key::KeyRole,
77 {
78 Ok(PKESK3{
79 common: Default::default(),
80 recipient: Some(recipient.keyid()),
81 pk_algo: recipient.pk_algo(),
82 esk: packet::PKESK::encrypt_common(
83 Some(algo), session_key,
84 recipient.parts_as_unspecified().role_as_unspecified())?,
85 })
86 }
87
88 pub fn recipient(&self) -> Option<&KeyID> {
90 self.recipient.as_ref()
91 }
92
93 pub fn set_recipient(&mut self, recipient: Option<KeyID>) -> Option<KeyID> {
95 ::std::mem::replace(&mut self.recipient, recipient)
96 }
97
98 pub fn pk_algo(&self) -> PublicKeyAlgorithm {
100 self.pk_algo
101 }
102
103 pub fn set_pk_algo(&mut self, algo: PublicKeyAlgorithm) -> PublicKeyAlgorithm {
105 ::std::mem::replace(&mut self.pk_algo, algo)
106 }
107
108 pub fn esk(&self) -> &Ciphertext {
110 &self.esk
111 }
112
113 pub fn set_esk(&mut self, esk: Ciphertext) -> Ciphertext {
115 ::std::mem::replace(&mut self.esk, esk)
116 }
117
118 pub fn decrypt(&self, decryptor: &mut dyn Decryptor,
135 sym_algo_hint: Option<SymmetricAlgorithm>)
136 -> Option<(SymmetricAlgorithm, SessionKey)>
137 {
138 self.decrypt_insecure(decryptor, sym_algo_hint).ok()
139 }
140
141 fn decrypt_insecure(&self, decryptor: &mut dyn Decryptor,
142 sym_algo_hint: Option<SymmetricAlgorithm>)
143 -> Result<(SymmetricAlgorithm, SessionKey)>
144 {
145 packet::PKESK::decrypt_common(&self.esk, decryptor, sym_algo_hint, true)
146 .map(|(sym_algo, sk)| (sym_algo.expect("known for v3 PKESK"), sk))
147 }
148}
149
150impl From<PKESK3> for crate::packet::PKESK {
151 fn from(p: PKESK3) -> Self {
152 crate::packet::PKESK::V3(p)
153 }
154}
155
156impl From<PKESK3> for Packet {
157 fn from(p: PKESK3) -> Self {
158 Packet::PKESK(p.into())
159 }
160}
161
162#[cfg(test)]
163impl Arbitrary for PKESK3 {
164 fn arbitrary(g: &mut Gen) -> Self {
165 let (ciphertext, pk_algo) = loop {
166 let ciphertext = Ciphertext::arbitrary(g);
167 if let Some(pk_algo) = ciphertext.pk_algo() {
168 break (ciphertext, pk_algo);
169 }
170 };
171
172 let keyid = bool::arbitrary(g).then_some(KeyID::arbitrary(g));
173 PKESK3::new(keyid, pk_algo, ciphertext).unwrap()
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use crate::Cert;
181 use crate::PacketPile;
182 use crate::packet::*;
183 use crate::parse::Parse;
184 use crate::serialize::MarshalInto;
185 use crate::types::Curve;
186
187 quickcheck! {
188 fn roundtrip(p: PKESK3) -> bool {
189 let q = PKESK3::from_bytes(&p.to_vec().unwrap()).unwrap();
190 assert_eq!(p, q);
191 true
192 }
193 }
194
195 #[test]
196 fn decrypt_rsa() {
197 if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
198 eprintln!("Skipping test, algorithm is not supported.");
199 return;
200 }
201
202 let cert = Cert::from_bytes(
203 crate::tests::key("testy-private.pgp")).unwrap();
204 let pile = PacketPile::from_bytes(
205 crate::tests::message("encrypted-to-testy.pgp")).unwrap();
206 let mut keypair =
207 cert.subkeys().next().unwrap()
208 .key().clone().parts_into_secret().unwrap().into_keypair().unwrap();
209
210 let pkesk: &PKESK =
211 pile.descendants().next().unwrap().downcast_ref().unwrap();
212
213 let plain = pkesk.decrypt(&mut keypair, None).unwrap();
214 let plain_ =
215 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256))
216 .unwrap();
217 assert_eq!(plain, plain_);
218
219 eprintln!("plain: {:?}", plain);
220 }
221
222 #[test]
223 fn decrypt_ecdh_cv25519() {
224 if ! (PublicKeyAlgorithm::EdDSA.is_supported()
225 && Curve::Ed25519.is_supported()
226 && PublicKeyAlgorithm::ECDH.is_supported()
227 && Curve::Cv25519.is_supported()) {
228 eprintln!("Skipping test, algorithm is not supported.");
229 return;
230 }
231
232 let cert = Cert::from_bytes(
233 crate::tests::key("testy-new-private.pgp")).unwrap();
234 let pile = PacketPile::from_bytes(
235 crate::tests::message("encrypted-to-testy-new.pgp")).unwrap();
236 let mut keypair =
237 cert.subkeys().next().unwrap()
238 .key().clone().parts_into_secret().unwrap().into_keypair().unwrap();
239
240 let pkesk: &PKESK =
241 pile.descendants().next().unwrap().downcast_ref().unwrap();
242
243 let plain = pkesk.decrypt(&mut keypair, None).unwrap();
244 let plain_ =
245 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256))
246 .unwrap();
247 assert_eq!(plain, plain_);
248
249 eprintln!("plain: {:?}", plain);
250 }
251
252 #[test]
253 fn decrypt_ecdh_nistp256() {
254 if ! (PublicKeyAlgorithm::ECDSA.is_supported()
255 && PublicKeyAlgorithm::ECDH.is_supported()
256 && Curve::NistP256.is_supported()) {
257 eprintln!("Skipping test, algorithm is not supported.");
258 return;
259 }
260
261 let cert = Cert::from_bytes(
262 crate::tests::key("testy-nistp256-private.pgp")).unwrap();
263 let pile = PacketPile::from_bytes(
264 crate::tests::message("encrypted-to-testy-nistp256.pgp")).unwrap();
265 let mut keypair =
266 cert.subkeys().next().unwrap()
267 .key().clone().parts_into_secret().unwrap().into_keypair().unwrap();
268
269 let pkesk: &PKESK =
270 pile.descendants().next().unwrap().downcast_ref().unwrap();
271
272 let plain = pkesk.decrypt(&mut keypair, None)
273 .expect("ECDH decryption using P-256 key should work");
274 let plain_ =
275 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256))
276 .unwrap();
277 assert_eq!(plain, plain_);
278
279 eprintln!("plain: {:?}", plain);
280 }
281
282 #[test]
283 fn decrypt_ecdh_nistp384() {
284 if ! (PublicKeyAlgorithm::ECDSA.is_supported()
285 && PublicKeyAlgorithm::ECDH.is_supported()
286 && Curve::NistP384.is_supported()) {
287 eprintln!("Skipping test, algorithm is not supported.");
288 return;
289 }
290
291 let cert = Cert::from_bytes(
292 crate::tests::key("testy-nistp384-private.pgp")).unwrap();
293 let pile = PacketPile::from_bytes(
294 crate::tests::message("encrypted-to-testy-nistp384.pgp")).unwrap();
295 let mut keypair =
296 cert.subkeys().next().unwrap()
297 .key().clone().parts_into_secret().unwrap().into_keypair().unwrap();
298
299 let pkesk: &PKESK =
300 pile.descendants().next().unwrap().downcast_ref().unwrap();
301
302 let plain = pkesk.decrypt(&mut keypair, None)
303 .expect("ECDH decryption using P-384 key should work");
304 let plain_ =
305 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256))
306 .unwrap();
307 assert_eq!(plain, plain_);
308
309 eprintln!("plain: {:?}", plain);
310 }
311
312 #[test]
313 #[allow(deprecated)]
314 fn decrypt_elgamal() -> Result<()> {
315 if ! (PublicKeyAlgorithm::DSA.is_supported()
316 && PublicKeyAlgorithm::ElGamalEncrypt.is_supported()) {
317 eprintln!("Skipping test, algorithm is not supported.");
318 return Ok(());
319 }
320
321 let cert = Cert::from_bytes(
322 crate::tests::key("dsa2048-elgamal3072-private.pgp"))?;
323 let pile = PacketPile::from_bytes(
324 crate::tests::message("encrypted-to-dsa2048-elgamal3072.pgp"))?;
325 let mut keypair =
326 cert.subkeys().next().unwrap()
327 .key().clone().parts_into_secret()?.into_keypair()?;
328
329 let pkesk: &PKESK =
330 pile.descendants().next().unwrap().downcast_ref().unwrap();
331
332 let plain = pkesk.decrypt(&mut keypair, None).unwrap();
333 let plain_ =
334 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256))
335 .unwrap();
336 assert_eq!(plain, plain_);
337
338 eprintln!("plain: {:?}", plain);
339 Ok(())
340 }
341
342 #[test]
343 fn decrypt_ecdh_nistp521() {
344 if ! (PublicKeyAlgorithm::ECDSA.is_supported()
345 && PublicKeyAlgorithm::ECDH.is_supported()
346 && Curve::NistP521.is_supported()) {
347 eprintln!("Skipping test, algorithm is not supported.");
348 return;
349 }
350
351 let cert = Cert::from_bytes(
352 crate::tests::key("testy-nistp521-private.pgp")).unwrap();
353 let pile = PacketPile::from_bytes(
354 crate::tests::message("encrypted-to-testy-nistp521.pgp")).unwrap();
355 let mut keypair =
356 cert.subkeys().next().unwrap()
357 .key().clone().parts_into_secret().unwrap().into_keypair().unwrap();
358
359 let pkesk: &PKESK =
360 pile.descendants().next().unwrap().downcast_ref().unwrap();
361
362 let plain = pkesk.decrypt(&mut keypair, None)
363 .expect("ECDH decryption using P-521 key should work");
364 let plain_ =
365 pkesk.decrypt(&mut keypair, Some(SymmetricAlgorithm::AES256))
366 .unwrap();
367 assert_eq!(plain, plain_);
368
369 eprintln!("plain: {:?}", plain);
370 }
371
372
373 #[test]
374 fn decrypt_with_short_cv25519_secret_key() {
375 if ! (PublicKeyAlgorithm::ECDH.is_supported()
376 && Curve::Cv25519.is_supported()) {
377 eprintln!("Skipping test, algorithm is not supported.");
378 return;
379 }
380
381 use super::PKESK3;
382 use crate::crypto::SessionKey;
383 use crate::{HashAlgorithm, SymmetricAlgorithm};
384 use crate::packet::key::{Key4, UnspecifiedRole};
385
386 let mut secret_key = [
388 0x0,0x0,
389 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
390 0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,
391 0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x0,0x0
392 ];
393 secret_key[31] &= 0x7f;
401 secret_key[31] |= 0x40;
402
403 let key: Key<_, UnspecifiedRole> = Key4::import_secret_cv25519(
404 &secret_key,
405 HashAlgorithm::SHA256,
406 SymmetricAlgorithm::AES256,
407 None,
408 ).unwrap().into();
409
410 let sess_key = SessionKey::new(32).unwrap();
411 let pkesk = PKESK3::for_recipient(SymmetricAlgorithm::AES256, &sess_key,
412 &key).unwrap();
413 let mut keypair = key.into_keypair().unwrap();
414 pkesk.decrypt(&mut keypair, None).unwrap();
415 }
416
417 #[test]
421 fn cve_2021_3580_ciphertext_too_long() -> Result<()> {
422 if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
423 eprintln!("Skipping test, algorithm is not supported.");
424 return Ok(());
425 }
426
427 let cert = Cert::from_bytes(
429 crate::tests::key("testy-private.pgp"))?;
430 let mut keypair = cert.primary_key().key().clone()
431 .parts_into_secret()?.into_keypair()?;
432
433 let pile = PacketPile::from_bytes(b"-----BEGIN PGP ARMORED FILE-----
434
435wcDNAwAAAAAAAAAAAQwGI5SkpcRMjkiOKx332kxv+2Xh4y1QTefPilKOPOlHYFa0
436rnnLaQVEACKJNQ38YuCFUvtpK4IN2grjlj71IP24+KDp3ZuVWnVTS6JcyE10Y9iq
437uGvKdS0C17XCze2LD4ouVOrUZHGXpeDT47w6DsHb/0UE85h56wpk2CzO1XFQzHxX
438HR2DDLqqeFVzTv0peYiQfLHl7kWXijTNEqmYhFCzxuICXzuClAAJM+fVIRfcm2tm
4392R4AxOQGv9DlWfZwbkpKfj/uuo0CAe21n4NT+NzdVgPlff/hna3yGgPe1B+vjq4e
440jfxHg+pvo/HTLkV+c2HAGbM1bCb/5TedGd1nAMSAIOu/J/WQp/l3HtEv63HaVPZJ
441JInJ6L/KyPwjm/ieZx5EWOLJgFRWGCrBGnb8T81lkFey7uZR5Xiq+9KoUhHQFw8N
442joc0YUVyhUBVFf4B0zVZRUfqZyJtJ07Sl5xppI12U1HQCTjn7Fp8BHMPKuBotYzv
4431Q4f00k6Txctw+LDRM17/w==
444=VtwB
445-----END PGP ARMORED FILE-----
446")?;
447 let pkesk: &PKESK =
448 pile.descendants().next().unwrap().downcast_ref().unwrap();
449 let _ = pkesk.decrypt(&mut keypair, None);
451
452 Ok(())
453 }
454
455 #[test]
459 fn cve_2021_3580_zero_ciphertext() -> Result<()> {
460 if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
461 eprintln!("Skipping test, algorithm is not supported.");
462 return Ok(());
463 }
464
465 let cert = Cert::from_bytes(
467 crate::tests::key("testy-private.pgp"))?;
468 let mut keypair = cert.primary_key().key().clone()
469 .parts_into_secret()?.into_keypair()?;
470
471 let pile = PacketPile::from_bytes(b"-----BEGIN PGP ARMORED FILE-----
472
473wQwDAAAAAAAAAAABAAA=
474=H/1T
475-----END PGP ARMORED FILE-----
476")?;
477 let pkesk: &PKESK =
478 pile.descendants().next().unwrap().downcast_ref().unwrap();
479 let _ = pkesk.decrypt(&mut keypair, None);
481
482 Ok(())
483 }
484}