1 //! Symmetric-Key Encrypted Session Key Packets.
2 //!
3 //! SKESK packets hold symmetrically encrypted session keys.  The
4 //! session key is needed to decrypt the actual ciphertext.  See
5 //! [Section 5.3 of RFC 4880] for details.
6 //!
7 //! [Section 5.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.3
8 
9 use std::ops::{Deref, DerefMut};
10 
11 #[cfg(any(test, feature = "quickcheck"))]
12 use quickcheck::{Arbitrary, Gen};
13 
14 use crate::Result;
15 use crate::crypto;
16 use crate::crypto::S2K;
17 use crate::Error;
18 use crate::types::{
19     AEADAlgorithm,
20     SymmetricAlgorithm,
21 };
22 use crate::packet::{self, SKESK};
23 use crate::Packet;
24 use crate::crypto::Password;
25 use crate::crypto::SessionKey;
26 
27 impl SKESK {
28     /// Derives the key inside this SKESK from `password`. Returns a
29     /// tuple of the symmetric cipher to use with the key and the key
30     /// itself.
decrypt(&self, password: &Password) -> Result<(SymmetricAlgorithm, SessionKey)>31     pub fn decrypt(&self, password: &Password)
32         -> Result<(SymmetricAlgorithm, SessionKey)>
33     {
34         match self {
35             &SKESK::V4(ref s) => s.decrypt(password),
36             &SKESK::V5(ref s) => s.decrypt(password),
37             SKESK::__Nonexhaustive => unreachable!(),
38         }
39     }
40 }
41 
42 #[cfg(any(test, feature = "quickcheck"))]
43 impl Arbitrary for SKESK {
arbitrary<G: Gen>(g: &mut G) -> Self44     fn arbitrary<G: Gen>(g: &mut G) -> Self {
45         if bool::arbitrary(g) {
46             SKESK::V4(SKESK4::arbitrary(g))
47         } else {
48             SKESK::V5(SKESK5::arbitrary(g))
49         }
50     }
51 }
52 
53 /// Holds an symmetrically encrypted session key version 4.
54 ///
55 /// Holds an symmetrically encrypted session key.  The session key is
56 /// needed to decrypt the actual ciphertext.  See [Section 5.3 of RFC
57 /// 4880] for details.
58 ///
59 /// [Section 5.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.3
60 #[derive(Clone, Debug)]
61 pub struct SKESK4 {
62     /// CTB header fields.
63     pub(crate) common: packet::Common,
64     /// Packet version. Must be 4 or 5.
65     ///
66     /// This struct is also used by SKESK5, hence we have a version
67     /// field.
68     version: u8,
69     /// Symmetric algorithm used to encrypt the session key.
70     sym_algo: SymmetricAlgorithm,
71     /// Key derivation method for the symmetric key.
72     s2k: S2K,
73     /// The encrypted session key.
74     ///
75     /// If we recognized the S2K object during parsing, we can
76     /// successfully parse the data into S2K and ciphertext.  However,
77     /// if we do not recognize the S2K type, we do not know how large
78     /// its parameters are, so we cannot cleanly parse it, and have to
79     /// accept that the S2K's body bleeds into the rest of the data.
80     esk: std::result::Result<Option<Box<[u8]>>, // optional ciphertext.
81                              Box<[u8]>>,        // S2K body + maybe ciphertext.
82 }
83 
84 // Because the S2K and ESK cannot be cleanly separated at parse time,
85 // we need to carefully compare and hash SKESK4 packets.
86 
87 impl PartialEq for SKESK4 {
eq(&self, other: &SKESK4) -> bool88     fn eq(&self, other: &SKESK4) -> bool {
89         self.version == other.version
90             && self.sym_algo == other.sym_algo
91             // Treat S2K and ESK as opaque blob.
92             && {
93                 // XXX: This would be nicer without the allocations.
94                 use crate::serialize::MarshalInto;
95                 let mut a = self.s2k.to_vec().unwrap();
96                 let mut b = other.s2k.to_vec().unwrap();
97                 a.extend_from_slice(self.raw_esk());
98                 b.extend_from_slice(other.raw_esk());
99                 a == b
100             }
101     }
102 }
103 
104 impl Eq for SKESK4 {}
105 
106 impl std::hash::Hash for SKESK4 {
hash<H: std::hash::Hasher>(&self, state: &mut H)107     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
108         self.version.hash(state);
109         self.sym_algo.hash(state);
110         // Treat S2K and ESK as opaque blob.
111         // XXX: This would be nicer without the allocations.
112         use crate::serialize::MarshalInto;
113         let mut a = self.s2k.to_vec().unwrap();
114         a.extend_from_slice(self.raw_esk());
115         a.hash(state);
116     }
117 }
118 
119 impl SKESK4 {
120     /// Creates a new SKESK version 4 packet.
121     ///
122     /// The given symmetric algorithm is the one used to encrypt the
123     /// session key.
new(esk_algo: SymmetricAlgorithm, s2k: S2K, esk: Option<Box<[u8]>>) -> Result<SKESK4>124     pub fn new(esk_algo: SymmetricAlgorithm, s2k: S2K,
125                esk: Option<Box<[u8]>>) -> Result<SKESK4> {
126         Self::new_raw(esk_algo, s2k, Ok(esk.and_then(|esk| {
127             if esk.len() == 0 { None } else { Some(esk) }
128         })))
129     }
130 
131     /// Creates a new SKESK version 4 packet.
132     ///
133     /// The given symmetric algorithm is the one used to encrypt the
134     /// session key.
new_raw(esk_algo: SymmetricAlgorithm, s2k: S2K, esk: std::result::Result<Option<Box<[u8]>>, Box<[u8]>>) -> Result<SKESK4>135     pub(crate) fn new_raw(esk_algo: SymmetricAlgorithm, s2k: S2K,
136                           esk: std::result::Result<Option<Box<[u8]>>,
137                                                    Box<[u8]>>)
138                           -> Result<SKESK4> {
139         Ok(SKESK4{
140             common: Default::default(),
141             version: 4,
142             sym_algo: esk_algo,
143             s2k,
144             esk,
145         })
146     }
147 
148     /// Creates a new SKESK4 packet with the given password.
149     ///
150     /// This function takes two [`SymmetricAlgorithm`] arguments: The
151     /// first, `payload_algo`, is the algorithm used to encrypt the
152     /// message's payload (i.e. the one used in the [`SEIP`] or
153     /// [`AED`] packet), and the second, `esk_algo`, is used to
154     /// encrypt the session key.  Usually, one should use the same
155     /// algorithm, but if they differ, the `esk_algo` should be at
156     /// least as strong as the `payload_algo` as not to weaken the
157     /// security of the payload encryption.
158     ///
159     ///   [`SymmetricAlgorithm`]: ../../types/enum.SymmetricAlgorithm.html
160     ///   [`SEIP`]: ../enum.SEIP.html
161     ///   [`AED`]: ../enum.AED.html
with_password(payload_algo: SymmetricAlgorithm, esk_algo: SymmetricAlgorithm, s2k: S2K, session_key: &SessionKey, password: &Password) -> Result<SKESK4>162     pub fn with_password(payload_algo: SymmetricAlgorithm,
163                          esk_algo: SymmetricAlgorithm,
164                          s2k: S2K,
165                          session_key: &SessionKey, password: &Password)
166                          -> Result<SKESK4> {
167         if session_key.len() != payload_algo.key_size()? {
168             return Err(Error::InvalidArgument(format!(
169                 "Invalid size of session key, got {} want {}",
170                 session_key.len(), payload_algo.key_size()?)).into());
171         }
172 
173         // Derive key and make a cipher.
174         let key = s2k.derive_key(password, esk_algo.key_size()?)?;
175         let mut cipher = esk_algo.make_encrypt_cfb(&key[..])?;
176         let block_size = esk_algo.block_size()?;
177         let mut iv = vec![0u8; block_size];
178 
179         // We need to prefix the cipher specifier to the session key.
180         let mut psk: SessionKey = vec![0; 1 + session_key.len()].into();
181         psk[0] = payload_algo.into();
182         psk[1..].copy_from_slice(&session_key);
183         let mut esk = vec![0u8; psk.len()];
184 
185         for (pt, ct) in psk[..].chunks(block_size)
186             .zip(esk.chunks_mut(block_size)) {
187                 cipher.encrypt(&mut iv[..], ct, pt)?;
188         }
189 
190         SKESK4::new(esk_algo, s2k, Some(esk.into()))
191     }
192 
193     /// Gets the symmetric encryption algorithm.
symmetric_algo(&self) -> SymmetricAlgorithm194     pub fn symmetric_algo(&self) -> SymmetricAlgorithm {
195         self.sym_algo
196     }
197 
198     /// Sets the symmetric encryption algorithm.
set_symmetric_algo(&mut self, algo: SymmetricAlgorithm) -> SymmetricAlgorithm199     pub fn set_symmetric_algo(&mut self, algo: SymmetricAlgorithm) -> SymmetricAlgorithm {
200         ::std::mem::replace(&mut self.sym_algo, algo)
201     }
202 
203     /// Gets the key derivation method.
s2k(&self) -> &S2K204     pub fn s2k(&self) -> &S2K {
205         &self.s2k
206     }
207 
208     /// Sets the key derivation method.
set_s2k(&mut self, s2k: S2K) -> S2K209     pub fn set_s2k(&mut self, s2k: S2K) -> S2K {
210         ::std::mem::replace(&mut self.s2k, s2k)
211     }
212 
213     /// Gets the encrypted session key.
214     ///
215     /// If the [`S2K`] mechanism is not supported by Sequoia, this
216     /// function will fail.  Note that the information is not lost,
217     /// but stored in the packet.  If the packet is serialized again,
218     /// it is written out.
219     ///
220     ///   [`S2K`]: ../../crypto/enum.S2K.html
esk(&self) -> Result<Option<&[u8]>>221     pub fn esk(&self) -> Result<Option<&[u8]>> {
222         self.esk.as_ref()
223             .map(|esko| esko.as_ref().map(|esk| &esk[..]))
224             .map_err(|_| Error::MalformedPacket(
225                 format!("Unknown S2K: {:?}", self.s2k)).into())
226     }
227 
228     /// Returns the encrypted session key, possibly including the body
229     /// of the S2K object.
raw_esk(&self) -> &[u8]230     pub(crate) fn raw_esk(&self) -> &[u8] {
231         match self.esk.as_ref() {
232             Ok(Some(esk)) => &esk[..],
233             Ok(None) => &[][..],
234             Err(s2k_esk) => &s2k_esk[..],
235         }
236     }
237 
238     /// Sets the encrypted session key.
set_esk(&mut self, esk: Option<Box<[u8]>>) -> Option<Box<[u8]>>239     pub fn set_esk(&mut self, esk: Option<Box<[u8]>>) -> Option<Box<[u8]>> {
240         ::std::mem::replace(
241             &mut self.esk,
242             Ok(esk.and_then(|esk| {
243                 if esk.len() == 0 { None } else { Some(esk) }
244             })))
245             .unwrap_or(None)
246     }
247 
248     /// Derives the key inside this SKESK4 from `password`.
249     ///
250     /// Returns a tuple of the symmetric cipher to use with the key
251     /// and the key itself.
decrypt(&self, password: &Password) -> Result<(SymmetricAlgorithm, SessionKey)>252     pub fn decrypt(&self, password: &Password)
253         -> Result<(SymmetricAlgorithm, SessionKey)>
254     {
255         let key = self.s2k.derive_key(password, self.sym_algo.key_size()?)?;
256 
257         if let Some(ref esk) = self.esk()? {
258             // Use the derived key to decrypt the ESK. Unlike SEP &
259             // SEIP we have to use plain CFB here.
260             let blk_sz = self.sym_algo.block_size()?;
261             let mut iv = vec![0u8; blk_sz];
262             let mut dec  = self.sym_algo.make_decrypt_cfb(&key[..])?;
263             let mut plain: SessionKey = vec![0u8; esk.len()].into();
264             let cipher = &esk[..];
265 
266             for (pl, ct)
267                 in plain[..].chunks_mut(blk_sz).zip(cipher.chunks(blk_sz))
268             {
269                 dec.decrypt(&mut iv[..], pl, ct)?;
270             }
271 
272             // Get the algorithm from the front.
273             let sym = SymmetricAlgorithm::from(plain[0]);
274             Ok((sym, plain[1..].into()))
275         } else {
276             // No ESK, we return the derived key.
277 
278             #[allow(deprecated)]
279             match self.s2k {
280                 S2K::Simple{ .. } =>
281                     Err(Error::InvalidOperation(
282                         "SKESK4: Cannot use Simple S2K without ESK".into())
283                         .into()),
284                 _ => Ok((self.sym_algo, key)),
285             }
286         }
287     }
288 }
289 
290 impl From<SKESK4> for super::SKESK {
from(p: SKESK4) -> Self291     fn from(p: SKESK4) -> Self {
292         super::SKESK::V4(p)
293     }
294 }
295 
296 impl From<SKESK4> for Packet {
from(s: SKESK4) -> Self297     fn from(s: SKESK4) -> Self {
298         Packet::SKESK(SKESK::V4(s))
299     }
300 }
301 
302 #[cfg(any(test, feature = "quickcheck"))]
303 impl Arbitrary for SKESK4 {
arbitrary<G: Gen>(g: &mut G) -> Self304     fn arbitrary<G: Gen>(g: &mut G) -> Self {
305         SKESK4::new(SymmetricAlgorithm::arbitrary(g),
306                     S2K::arbitrary(g),
307                     Option::<Vec<u8>>::arbitrary(g).map(|v| v.into()))
308             .unwrap()
309     }
310 }
311 
312 /// Holds an symmetrically encrypted session key version 5.
313 ///
314 /// Holds an symmetrically encrypted session key.  The session key is
315 /// needed to decrypt the actual ciphertext.  See [Section 5.3 of RFC
316 /// 4880bis] for details.
317 ///
318 /// [Section 5.3 of RFC 4880]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-05#section-5.3
319 ///
320 /// This feature is [experimental](../../index.html#experimental-features).
321 #[derive(Clone, Debug)]
322 pub struct SKESK5 {
323     /// Common fields.
324     pub(crate) skesk4: SKESK4,
325     /// AEAD algorithm.
326     aead_algo: AEADAlgorithm,
327     /// Initialization vector for the AEAD algorithm.
328     ///
329     /// If we recognized the S2K object during parsing, we can
330     /// successfully parse the data into S2K, AEAED IV, and
331     /// ciphertext.  However, if we do not recognize the S2K type, we
332     /// do not know how large its parameters are, so we cannot cleanly
333     /// parse it, and have to accept that the S2K's body bleeds into
334     /// the rest of the data.  In this case, the raw data is put into
335     /// the `esk` field, and `aead_iv` is set to `None`.
336     aead_iv: Option<Box<[u8]>>,
337     /// Digest for the AEAD algorithm.
338     aead_digest: Box<[u8]>,
339 }
340 
341 // Because the S2K, IV, and ESK cannot be cleanly separated at parse
342 // time, we need to carefully compare and hash SKESK5 packets.
343 
344 impl PartialEq for SKESK5 {
eq(&self, other: &SKESK5) -> bool345     fn eq(&self, other: &SKESK5) -> bool {
346         self.skesk4.version == other.skesk4.version
347             && self.skesk4.sym_algo == other.skesk4.sym_algo
348             && self.aead_digest == other.aead_digest
349             // Treat S2K, IV, and ESK as opaque blob.
350             && {
351                 // XXX: This would be nicer without the allocations.
352                 use crate::serialize::MarshalInto;
353                 let mut a = self.skesk4.s2k.to_vec().unwrap();
354                 let mut b = other.skesk4.s2k.to_vec().unwrap();
355                 if let Ok(iv) = self.aead_iv() {
356                     a.extend_from_slice(iv);
357                 }
358                 if let Ok(iv) = other.aead_iv() {
359                     b.extend_from_slice(iv);
360                 }
361                 a.extend_from_slice(self.skesk4.raw_esk());
362                 b.extend_from_slice(other.skesk4.raw_esk());
363                 a == b
364             }
365     }
366 }
367 
368 impl Eq for SKESK5 {}
369 
370 impl std::hash::Hash for SKESK5 {
hash<H: std::hash::Hasher>(&self, state: &mut H)371     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
372         self.skesk4.version.hash(state);
373         self.skesk4.sym_algo.hash(state);
374         self.aead_digest.hash(state);
375         // Treat S2K, IV, and ESK as opaque blob.
376         // XXX: This would be nicer without the allocations.
377         use crate::serialize::MarshalInto;
378         let mut a = self.skesk4.s2k.to_vec().unwrap();
379         if let Some(iv) = self.aead_iv.as_ref() {
380             a.extend_from_slice(iv);
381         }
382         a.extend_from_slice(self.skesk4.raw_esk());
383         a.hash(state);
384     }
385 }
386 
387 impl Deref for SKESK5 {
388     type Target = SKESK4;
389 
deref(&self) -> &Self::Target390     fn deref(&self) -> &Self::Target {
391         &self.skesk4
392     }
393 }
394 
395 impl DerefMut for SKESK5 {
deref_mut(&mut self) -> &mut Self::Target396     fn deref_mut(&mut self) -> &mut Self::Target {
397         &mut self.skesk4
398     }
399 }
400 
401 impl SKESK5 {
402     /// Creates a new SKESK version 5 packet.
403     ///
404     /// The given symmetric algorithm is the one used to encrypt the
405     /// session key.
new(esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm, s2k: S2K, iv: Box<[u8]>, esk: Box<[u8]>, digest: Box<[u8]>) -> Result<Self>406     pub fn new(esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm,
407                s2k: S2K, iv: Box<[u8]>, esk: Box<[u8]>, digest: Box<[u8]>)
408                -> Result<Self> {
409         Self::new_raw(esk_algo, esk_aead, s2k, Ok((iv, esk)), digest)
410     }
411 
412     /// Creates a new SKESK version 5 packet.
413     ///
414     /// The given symmetric algorithm is the one used to encrypt the
415     /// session key.
new_raw(esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm, s2k: S2K, iv_esk: std::result::Result<(Box<[u8]>, Box<[u8]>), Box<[u8]>>, digest: Box<[u8]>) -> Result<Self>416     pub(crate) fn new_raw(esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm,
417                           s2k: S2K,
418                           iv_esk: std::result::Result<(Box<[u8]>, Box<[u8]>),
419                                                       Box<[u8]>>,
420                           digest: Box<[u8]>)
421                           -> Result<Self> {
422         let (iv, esk) = match iv_esk {
423             Ok((iv, esk)) => (Some(iv), Ok(Some(esk))),
424             Err(raw) => (None, Err(raw)),
425         };
426 
427         Ok(SKESK5{
428             skesk4: SKESK4{
429                 common: Default::default(),
430                 version: 5,
431                 sym_algo: esk_algo,
432                 s2k,
433                 esk,
434             },
435             aead_algo: esk_aead,
436             aead_iv: iv,
437             aead_digest: digest,
438         })
439     }
440 
441     /// Creates a new SKESK version 5 packet with the given password.
442     ///
443     /// This function takes two [`SymmetricAlgorithm`] arguments: The
444     /// first, `payload_algo`, is the algorithm used to encrypt the
445     /// message's payload (i.e. the one used in the [`SEIP`] or
446     /// [`AED`] packet), and the second, `esk_algo`, is used to
447     /// encrypt the session key.  Usually, one should use the same
448     /// algorithm, but if they differ, the `esk_algo` should be at
449     /// least as strong as the `payload_algo` as not to weaken the
450     /// security of the payload encryption.
451     ///
452     ///   [`SymmetricAlgorithm`]: ../../types/enum.SymmetricAlgorithm.html
453     ///   [`SEIP`]: ../enum.SEIP.html
454     ///   [`AED`]: ../enum.AED.html
with_password(payload_algo: SymmetricAlgorithm, esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm, s2k: S2K, session_key: &SessionKey, password: &Password) -> Result<Self>455     pub fn with_password(payload_algo: SymmetricAlgorithm,
456                          esk_algo: SymmetricAlgorithm,
457                          esk_aead: AEADAlgorithm, s2k: S2K,
458                          session_key: &SessionKey, password: &Password)
459                          -> Result<Self> {
460         if session_key.len() != payload_algo.key_size()? {
461             return Err(Error::InvalidArgument(format!(
462                 "Invalid size of session key, got {} want {}",
463                 session_key.len(), payload_algo.key_size()?)).into());
464         }
465 
466         // Derive key and make a cipher.
467         let key = s2k.derive_key(password, esk_algo.key_size()?)?;
468         let mut iv = vec![0u8; esk_aead.iv_size()?];
469         crypto::random(&mut iv);
470         let mut ctx = esk_aead.context(esk_algo, &key, &iv)?;
471 
472         // Prepare associated data.
473         let ad = [0xc3, 5, esk_algo.into(), esk_aead.into()];
474         ctx.update(&ad);
475 
476         // We need to prefix the cipher specifier to the session key.
477         let mut esk = vec![0u8; session_key.len()];
478         ctx.encrypt(&mut esk, &session_key);
479 
480         // Digest.
481         let mut digest = vec![0u8; esk_aead.digest_size()?];
482         ctx.digest(&mut digest);
483 
484         SKESK5::new(esk_algo, esk_aead, s2k, iv.into_boxed_slice(), esk.into(),
485                     digest.into_boxed_slice())
486     }
487 
488     /// Derives the key inside this `SKESK5` from `password`.
489     ///
490     /// Returns a tuple containing a placeholder symmetric cipher and
491     /// the key itself.  `SKESK5` packets do not contain the symmetric
492     /// cipher algorithm and instead rely on the `AED` packet that
493     /// contains it.
494     // XXX: This function should return Result<SessionKey>, but then
495     // SKESK::decrypt must return an
496     // Result<(Option<SymmetricAlgorithm>, _)> and
497     // DecryptionHelper::decrypt and PacketParser::decrypt must be
498     // adapted as well.
decrypt(&self, password: &Password) -> Result<(SymmetricAlgorithm, SessionKey)>499     pub fn decrypt(&self, password: &Password)
500                    -> Result<(SymmetricAlgorithm, SessionKey)> {
501         let key = self.s2k().derive_key(password,
502                                         self.symmetric_algo().key_size()?)?;
503 
504         if let Some(ref esk) = self.esk()? {
505             // Use the derived key to decrypt the ESK.
506             let mut cipher = self.aead_algo.context(
507                 self.symmetric_algo(), &key, &self.aead_iv()?)?;
508 
509             let ad = [0xc3, 5 /* Version.  */, self.symmetric_algo().into(),
510                       self.aead_algo.into()];
511             cipher.update(&ad);
512             let mut plain: SessionKey = vec![0; esk.len()].into();
513             let mut digest = vec![0; self.aead_algo.digest_size()?];
514             cipher.decrypt(&mut plain, esk);
515             cipher.digest(&mut digest);
516             if &digest[..] == &self.aead_digest[..] {
517                 Ok((SymmetricAlgorithm::Unencrypted, plain))
518             } else {
519                 Err(Error::ManipulatedMessage.into())
520             }
521         } else {
522             Err(Error::MalformedPacket(
523                 "No encrypted session key in v5 SKESK packet".into())
524                 .into())
525         }
526     }
527 
528     /// Gets the AEAD algorithm.
aead_algo(&self) -> AEADAlgorithm529     pub fn aead_algo(&self) -> AEADAlgorithm {
530         self.aead_algo
531     }
532 
533     /// Sets the AEAD algorithm.
set_aead_algo(&mut self, algo: AEADAlgorithm) -> AEADAlgorithm534     pub fn set_aead_algo(&mut self, algo: AEADAlgorithm) -> AEADAlgorithm {
535         ::std::mem::replace(&mut self.aead_algo, algo)
536     }
537 
538     /// Gets the AEAD initialization vector.
539     ///
540     /// If the [`S2K`] mechanism is not supported by Sequoia, this
541     /// function will fail.  Note that the information is not lost,
542     /// but stored in the packet.  If the packet is serialized again,
543     /// it is written out.
544     ///
545     ///   [`S2K`]: ../../crypto/enum.S2K.html
aead_iv(&self) -> Result<&[u8]>546     pub fn aead_iv(&self) -> Result<&[u8]> {
547         self.aead_iv.as_ref()
548             .map(|iv| &iv[..])
549             .ok_or_else(|| Error::MalformedPacket(
550                 format!("Unknown S2K: {:?}", self.s2k)).into())
551     }
552 
553     /// Sets the AEAD initialization vector.
set_aead_iv(&mut self, iv: Box<[u8]>) -> Option<Box<[u8]>>554     pub fn set_aead_iv(&mut self, iv: Box<[u8]>) -> Option<Box<[u8]>> {
555         ::std::mem::replace(&mut self.aead_iv, Some(iv))
556     }
557 
558     /// Gets the AEAD digest.
aead_digest(&self) -> &[u8]559     pub fn aead_digest(&self) -> &[u8] {
560         &self.aead_digest
561     }
562 
563     /// Sets the AEAD digest.
set_aead_digest(&mut self, digest: Box<[u8]>) -> Box<[u8]>564     pub fn set_aead_digest(&mut self, digest: Box<[u8]>) -> Box<[u8]> {
565         ::std::mem::replace(&mut self.aead_digest, digest)
566     }
567 }
568 
569 impl From<SKESK5> for super::SKESK {
from(p: SKESK5) -> Self570     fn from(p: SKESK5) -> Self {
571         super::SKESK::V5(p)
572     }
573 }
574 
575 impl From<SKESK5> for Packet {
from(s: SKESK5) -> Self576     fn from(s: SKESK5) -> Self {
577         Packet::SKESK(SKESK::V5(s))
578     }
579 }
580 
581 #[cfg(any(test, feature = "quickcheck"))]
582 impl Arbitrary for SKESK5 {
arbitrary<G: Gen>(g: &mut G) -> Self583     fn arbitrary<G: Gen>(g: &mut G) -> Self {
584         let algo = AEADAlgorithm::EAX;  // The only one we dig.
585         let mut iv = vec![0u8; algo.iv_size().unwrap()];
586         for b in iv.iter_mut() {
587             *b = u8::arbitrary(g);
588         }
589         let mut digest = vec![0u8; algo.digest_size().unwrap()];
590         for b in digest.iter_mut() {
591             *b = u8::arbitrary(g);
592         }
593         SKESK5::new(SymmetricAlgorithm::arbitrary(g),
594                     algo,
595                     S2K::arbitrary(g),
596                     iv.into_boxed_slice(),
597                     Vec::<u8>::arbitrary(g).into(),
598                     digest.into_boxed_slice())
599             .unwrap()
600     }
601 }
602 
603 #[cfg(test)]
604 mod test {
605     use super::*;
606     use crate::PacketPile;
607     use crate::parse::Parse;
608     use crate::serialize::{Marshal, MarshalInto};
609 
610     quickcheck! {
611         fn roundtrip(p: SKESK) -> bool {
612             let q = SKESK::from_bytes(&p.to_vec().unwrap()).unwrap();
613             assert_eq!(p, q);
614             true
615         }
616     }
617 
618     #[test]
sample_skesk5_packet()619     fn sample_skesk5_packet() {
620         // This sample packet is from RFC4880bis-05, section A.3.
621         let password: Password = String::from("password").into();
622         let raw = [
623             // Packet header:
624             0xc3, 0x3e,
625 
626             // Version, algorithms, S2K fields:
627             0x05, 0x07, 0x01, 0x03, 0x08, 0xcd, 0x5a, 0x9f,
628             0x70, 0xfb, 0xe0, 0xbc, 0x65, 0x90,
629 
630             // AEAD IV:
631             0xbc, 0x66, 0x9e, 0x34, 0xe5, 0x00, 0xdc, 0xae,
632             0xdc, 0x5b, 0x32, 0xaa, 0x2d, 0xab, 0x02, 0x35,
633 
634             // AEAD encrypted CEK:
635             0x9d, 0xee, 0x19, 0xd0, 0x7c, 0x34, 0x46, 0xc4,
636             0x31, 0x2a, 0x34, 0xae, 0x19, 0x67, 0xa2, 0xfb,
637 
638             // Authentication tag:
639             0x7e, 0x92, 0x8e, 0xa5, 0xb4, 0xfa, 0x80, 0x12,
640             0xbd, 0x45, 0x6d, 0x17, 0x38, 0xc6, 0x3c, 0x36,
641         ];
642         let packets: Vec<Packet> =
643             PacketPile::from_bytes(&raw[..]).unwrap().into_children().collect();
644         assert_eq!(packets.len(), 1);
645         if let Packet::SKESK(SKESK::V5(ref s)) = packets[0] {
646             assert_eq!(&s.s2k().derive_key(
647                 &password, s.symmetric_algo().key_size().unwrap()).unwrap()[..],
648                        &[0xb2, 0x55, 0x69, 0xb9, 0x54, 0x32, 0x45, 0x66,
649                          0x45, 0x27, 0xc4, 0x97, 0x6e, 0x7a, 0x5d, 0x6e][..]);
650 
651             assert_eq!(&s.decrypt(&password).unwrap().1[..],
652                        &[0x86, 0xf1, 0xef, 0xb8, 0x69, 0x52, 0x32, 0x9f,
653                          0x24, 0xac, 0xd3, 0xbf, 0xd0, 0xe5, 0x34, 0x6d][..]);
654         } else {
655             panic!("bad packet");
656         }
657 
658         let mut serialized = Vec::new();
659         packets[0].serialize(&mut serialized).unwrap();
660         assert_eq!(&raw[..], &serialized[..]);
661     }
662 }
663