diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2023-02-14 19:37:54 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2023-02-14 20:03:58 +0100 |
commit | 28cc59330c175d14685e0f32945bb26c4083cd53 (patch) | |
tree | fd98e4e8a1cfcfb008538c577b1128ecabc73dac | |
parent | 242c36ac97475e3988ed13abcd7e638783542762 (diff) |
openpgp: Implement SKESKv6 from the crypto refresh.
- Use HKDF in the SKESKv6 to provide key separation. See
https://gitlab.com/openpgp-wg/rfc4880bis/-/commit/a42ea9c05479cc8b0424c85b865d796d2250586c
-rw-r--r-- | openpgp/src/packet/mod.rs | 10 | ||||
-rw-r--r-- | openpgp/src/packet/prelude.rs | 2 | ||||
-rw-r--r-- | openpgp/src/packet/skesk.rs | 244 | ||||
-rw-r--r-- | openpgp/src/parse.rs | 73 | ||||
-rw-r--r-- | openpgp/src/parse/stream.rs | 2 | ||||
-rw-r--r-- | openpgp/src/serialize.rs | 42 | ||||
-rw-r--r-- | openpgp/src/serialize/stream.rs | 2 | ||||
-rw-r--r-- | sq/src/commands/dump.rs | 16 |
8 files changed, 165 insertions, 226 deletions
diff --git a/openpgp/src/packet/mod.rs b/openpgp/src/packet/mod.rs index 3c132486..9f4d2ad3 100644 --- a/openpgp/src/packet/mod.rs +++ b/openpgp/src/packet/mod.rs @@ -466,7 +466,7 @@ impl Deref for Packet { Packet::CompressedData(ref packet) => &packet.common, Packet::PKESK(ref packet) => &packet.common, Packet::SKESK(SKESK::V4(ref packet)) => &packet.common, - Packet::SKESK(SKESK::V5(ref packet)) => &packet.skesk4.common, + Packet::SKESK(SKESK::V6(ref packet)) => &packet.skesk4.common, Packet::SEIP(ref packet) => &packet.common, Packet::MDC(ref packet) => &packet.common, Packet::AED(ref packet) => &packet.common, @@ -493,7 +493,7 @@ impl DerefMut for Packet { Packet::CompressedData(ref mut packet) => &mut packet.common, Packet::PKESK(ref mut packet) => &mut packet.common, Packet::SKESK(SKESK::V4(ref mut packet)) => &mut packet.common, - Packet::SKESK(SKESK::V5(ref mut packet)) => &mut packet.skesk4.common, + Packet::SKESK(SKESK::V6(ref mut packet)) => &mut packet.skesk4.common, Packet::SEIP(ref mut packet) => &mut packet.common, Packet::MDC(ref mut packet) => &mut packet.common, Packet::AED(ref mut packet) => &mut packet.common, @@ -1184,10 +1184,10 @@ impl DerefMut for PKESK { pub enum SKESK { /// SKESK packet version 4. V4(self::skesk::SKESK4), - /// SKESK packet version 5. + /// SKESK packet version 6. /// /// This feature is [experimental](super#experimental-features). - V5(self::skesk::SKESK5), + V6(self::skesk::SKESK6), } assert_send_and_sync!(SKESK); @@ -1196,7 +1196,7 @@ impl SKESK { pub fn version(&self) -> u8 { match self { SKESK::V4(_) => 4, - SKESK::V5(_) => 5, + SKESK::V6(_) => 6, } } } diff --git a/openpgp/src/packet/prelude.rs b/openpgp/src/packet/prelude.rs index 7e00367f..69e3515c 100644 --- a/openpgp/src/packet/prelude.rs +++ b/openpgp/src/packet/prelude.rs @@ -54,6 +54,6 @@ pub use crate::packet::{ signature::Signature4, signature::SignatureBuilder, skesk::SKESK4, - skesk::SKESK5, + skesk::SKESK6, user_attribute, }; diff --git a/openpgp/src/packet/skesk.rs b/openpgp/src/packet/skesk.rs index 412c59c1..5296baf1 100644 --- a/openpgp/src/packet/skesk.rs +++ b/openpgp/src/packet/skesk.rs @@ -12,7 +12,13 @@ use std::ops::{Deref, DerefMut}; use quickcheck::{Arbitrary, Gen}; use crate::Result; -use crate::crypto::{self, S2K, Password, SessionKey}; +use crate::crypto::{ + self, + S2K, + Password, + SessionKey, + hkdf_sha256, +}; use crate::crypto::aead::CipherOp; use crate::Error; use crate::types::{ @@ -31,7 +37,7 @@ impl SKESK { { match self { SKESK::V4(ref s) => s.decrypt(password), - SKESK::V5(ref s) => s.decrypt(password), + SKESK::V6(ref s) => s.decrypt(password), } } } @@ -42,7 +48,7 @@ impl Arbitrary for SKESK { if bool::arbitrary(g) { SKESK::V4(SKESK4::arbitrary(g)) } else { - SKESK::V5(SKESK5::arbitrary(g)) + SKESK::V6(SKESK6::arbitrary(g)) } } } @@ -60,7 +66,7 @@ pub struct SKESK4 { pub(crate) common: packet::Common, /// Packet version. Must be 4 or 5. /// - /// This struct is also used by SKESK5, hence we have a version + /// This struct is also used by SKESK6, hence we have a version /// field. version: u8, /// Symmetric algorithm used to encrypt the session key. @@ -308,74 +314,18 @@ impl Arbitrary for SKESK4 { /// [Section 5.3 of RFC 4880]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-05#section-5.3 /// /// This feature is [experimental](super::super#experimental-features). -#[derive(Clone, Debug)] -pub struct SKESK5 { +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct SKESK6 { /// Common fields. pub(crate) skesk4: SKESK4, /// AEAD algorithm. aead_algo: AEADAlgorithm, /// Initialization vector for the AEAD algorithm. - /// - /// If we recognized the S2K object during parsing, we can - /// successfully parse the data into S2K, AEAED IV, and - /// ciphertext. However, if we do not recognize the S2K type, we - /// do not know how large its parameters are, so we cannot cleanly - /// parse it, and have to accept that the S2K's body bleeds into - /// the rest of the data. In this case, the raw data is put into - /// the `esk` field, and `aead_iv` is set to `None`. - aead_iv: Option<Box<[u8]>>, - /// Digest for the AEAD algorithm. - aead_digest: Box<[u8]>, -} -assert_send_and_sync!(SKESK5); - -// Because the S2K, IV, and ESK cannot be cleanly separated at parse -// time, we need to carefully compare and hash SKESK5 packets. - -impl PartialEq for SKESK5 { - fn eq(&self, other: &SKESK5) -> bool { - self.skesk4.version == other.skesk4.version - && self.skesk4.sym_algo == other.skesk4.sym_algo - && self.aead_digest == other.aead_digest - // Treat S2K, IV, and ESK as opaque blob. - && { - // XXX: This would be nicer without the allocations. - use crate::serialize::MarshalInto; - let mut a = self.skesk4.s2k.to_vec().unwrap(); - let mut b = other.skesk4.s2k.to_vec().unwrap(); - if let Ok(iv) = self.aead_iv() { - a.extend_from_slice(iv); - } - if let Ok(iv) = other.aead_iv() { - b.extend_from_slice(iv); - } - a.extend_from_slice(self.skesk4.raw_esk()); - b.extend_from_slice(other.skesk4.raw_esk()); - a == b - } - } + aead_iv: Box<[u8]>, } +assert_send_and_sync!(SKESK6); -impl Eq for SKESK5 {} - -impl std::hash::Hash for SKESK5 { - fn hash<H: std::hash::Hasher>(&self, state: &mut H) { - self.skesk4.version.hash(state); - self.skesk4.sym_algo.hash(state); - self.aead_digest.hash(state); - // Treat S2K, IV, and ESK as opaque blob. - // XXX: This would be nicer without the allocations. - use crate::serialize::MarshalInto; - let mut a = self.skesk4.s2k.to_vec().unwrap(); - if let Some(iv) = self.aead_iv.as_ref() { - a.extend_from_slice(iv); - } - a.extend_from_slice(self.skesk4.raw_esk()); - a.hash(state); - } -} - -impl Deref for SKESK5 { +impl Deref for SKESK6 { type Target = SKESK4; fn deref(&self) -> &Self::Target { @@ -383,49 +333,33 @@ impl Deref for SKESK5 { } } -impl DerefMut for SKESK5 { +impl DerefMut for SKESK6 { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.skesk4 } } -impl SKESK5 { +impl SKESK6 { /// Creates a new SKESK version 5 packet. /// /// The given symmetric algorithm is the one used to encrypt the /// session key. - pub fn new(esk_algo: SymmetricAlgorithm, esk_aead: AEADAlgorithm, - s2k: S2K, iv: Box<[u8]>, esk: Box<[u8]>, digest: Box<[u8]>) + pub fn new(sym_algo: SymmetricAlgorithm, + aead_algo: AEADAlgorithm, + s2k: S2K, + aead_iv: Box<[u8]>, + esk: Box<[u8]>) -> Result<Self> { - Self::new_raw(esk_algo, esk_aead, s2k, Ok((iv, esk)), digest) - } - - /// Creates a new SKESK version 5 packet. - /// - /// The given symmetric algorithm is the one used to encrypt the - /// session key. - pub(crate) fn 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> { - let (iv, esk) = match iv_esk { - Ok((iv, esk)) => (Some(iv), Ok(Some(esk))), - Err(raw) => (None, Err(raw)), - }; - - Ok(SKESK5{ - skesk4: SKESK4{ + Ok(SKESK6 { + skesk4: SKESK4 { common: Default::default(), - version: 5, - sym_algo: esk_algo, + version: 6, + sym_algo, s2k, - esk, + esk: Ok(Some(esk)), }, - aead_algo: esk_aead, - aead_iv: iv, - aead_digest: digest, + aead_algo, + aead_iv, }) } @@ -455,13 +389,17 @@ impl SKESK5 { } // Derive key and make a cipher. + let ad = [0xc3, 6, esk_algo.into(), esk_aead.into()]; let key = s2k.derive_key(password, esk_algo.key_size()?)?; + + let mut kek: SessionKey = vec![0; esk_algo.key_size()?].into(); + hkdf_sha256(&key, None, &ad, &mut kek); + let mut iv = vec![0u8; esk_aead.nonce_size()?]; crypto::random(&mut iv); - let mut ctx = esk_aead.context(esk_algo, &key, &iv, CipherOp::Encrypt)?; + let mut ctx = esk_aead.context(esk_algo, &kek, &iv, CipherOp::Encrypt)?; // Prepare associated data. - let ad = [0xc3, 5, esk_algo.into(), esk_aead.into()]; ctx.update(&ad)?; // Encrypt the session key with the KEK. @@ -472,14 +410,15 @@ impl SKESK5 { let mut digest = vec![0u8; esk_aead.digest_size()?]; ctx.digest(&mut digest)?; - SKESK5::new(esk_algo, esk_aead, s2k, iv.into_boxed_slice(), esk.into(), - digest.into_boxed_slice()) + // Attach digest to the ESK, we model it as one. + esk.append(&mut digest); + SKESK6::new(esk_algo, esk_aead, s2k, iv.into_boxed_slice(), esk.into()) } - /// Derives the key inside this `SKESK5` from `password`. + /// Derives the key inside this `SKESK6` from `password`. /// /// Returns a tuple containing a placeholder symmetric cipher and - /// the key itself. `SKESK5` packets do not contain the symmetric + /// the key itself. `SKESK6` packets do not contain the symmetric /// cipher algorithm and instead rely on the `AED` packet that /// contains it. // XXX: This function should return Result<SessionKey>, but then @@ -492,22 +431,28 @@ impl SKESK5 { let key = self.s2k().derive_key(password, self.symmetric_algo().key_size()?)?; - if let Some(esk) = self.esk()? { - // Use the derived key to decrypt the ESK. - let mut cipher = self.aead_algo.context( - self.symmetric_algo(), &key, self.aead_iv()?, CipherOp::Decrypt)?; - - let ad = [0xc3, 5 /* Version. */, self.symmetric_algo().into(), - self.aead_algo.into()]; - cipher.update(&ad)?; - let mut plain: SessionKey = vec![0; esk.len()].into(); - cipher.decrypt_verify(&mut plain, esk, &self.aead_digest[..])?; - Ok((SymmetricAlgorithm::Unencrypted, plain)) - } else { - Err(Error::MalformedPacket( - "No encrypted session key in v5 SKESK packet".into()) - .into()) - } + let mut kek: SessionKey = + vec![0; self.symmetric_algo().key_size()?].into(); + let ad = [0xc3, + 6 /* Version. */, + self.symmetric_algo().into(), + self.aead_algo.into()]; + hkdf_sha256(&key, None, &ad, &mut kek); + + // Use the derived key to decrypt the ESK. + let mut cipher = self.aead_algo.context( + self.symmetric_algo(), &kek, self.aead_iv(), + CipherOp::Decrypt)?; + + // Split off the authentication tag. + let digest_len = self.aead_algo.digest_size()?; + let (esk, stored_digest) = + self.esk().split_at(self.esk().len().saturating_sub(digest_len)); + + cipher.update(&ad)?; + let mut plain: SessionKey = vec![0; esk.len()].into(); + cipher.decrypt_verify(&mut plain, esk, &stored_digest[..])?; + Ok((SymmetricAlgorithm::Unencrypted, plain)) } /// Gets the AEAD algorithm. @@ -521,66 +466,59 @@ impl SKESK5 { } /// Gets the AEAD initialization vector. - /// - /// If the [`S2K`] mechanism is not supported by Sequoia, this - /// function will fail. Note that the information is not lost, - /// but stored in the packet. If the packet is serialized again, - /// it is written out. - /// - /// [`S2K`]: super::super::crypto::S2K - pub fn aead_iv(&self) -> Result<&[u8]> { - self.aead_iv.as_ref() - .map(|iv| &iv[..]) - .ok_or_else(|| Error::MalformedPacket( - format!("Unknown S2K: {:?}", self.s2k)).into()) + pub fn aead_iv(&self) -> &[u8] { + &self.aead_iv } /// Sets the AEAD initialization vector. - pub fn set_aead_iv(&mut self, iv: Box<[u8]>) -> Option<Box<[u8]>> { - ::std::mem::replace(&mut self.aead_iv, Some(iv)) + pub fn set_aead_iv(&mut self, iv: Box<[u8]>) -> Box<[u8]> { + ::std::mem::replace(&mut self.aead_iv, iv) } - /// Gets the AEAD digest. - pub fn aead_digest(&self) -> &[u8] { - &self.aead_digest + /// Gets the encrypted session key. + pub fn esk(&self) -> &[u8] { + self.skesk4.raw_esk() } - /// Sets the AEAD digest. - pub fn set_aead_digest(&mut self, digest: Box<[u8]>) -> Box<[u8]> { - ::std::mem::replace(&mut self.aead_digest, digest) + /// Sets the encrypted session key. + pub fn set_esk(&mut self, esk: Box<[u8]>) -> Box<[u8]> { + ::std::mem::replace(&mut self.esk, Ok(Some(esk))) + .expect("v5 SKESK can always be parsed") + .expect("v5 SKESK packets always have an ESK") } } -impl From<SKESK5> for super::SKESK { - fn from(p: SKESK5) -> Self { - super::SKESK::V5(p) +impl From<SKESK6> for super::SKESK { + fn from(p: SKESK6) -> Self { + super::SKESK::V6(p) } } -impl From<SKESK5> for Packet { - fn from(s: SKESK5) -> Self { - Packet::SKESK(SKESK::V5(s)) +impl From<SKESK6> for Packet { + fn from(s: SKESK6) -> Self { + Packet::SKESK(SKESK::V6(s)) } } #[cfg(test)] -impl Arbitrary for SKESK5 { +impl Arbitrary for SKESK6 { fn arbitrary(g: &mut Gen) -> Self { let algo = AEADAlgorithm::const_default(); let mut iv = vec![0u8; algo.nonce_size().unwrap()]; for b in iv.iter_mut() { *b = u8::arbitrary(g); } - let mut digest = vec![0u8; algo.digest_size().unwrap()]; - for b in digest.iter_mut() { + let esk_len = + (u8::arbitrary(g) % 64) as usize + algo.digest_size().unwrap(); + let mut esk = vec![0u8; esk_len]; + for b in esk.iter_mut() { *b = u8::arbitrary(g); } - SKESK5::new(SymmetricAlgorithm::arbitrary(g), + SKESK6::new(SymmetricAlgorithm::arbitrary(g), algo, S2K::arbitrary(g), - iv.into_boxed_slice(), - Vec::<u8>::arbitrary(g).into(), - digest.into_boxed_slice()) + iv.into(), + esk.into()) .unwrap() } } @@ -600,7 +538,9 @@ mod test { } } - #[test] + // XXX this is outdated + //#[test] + #[allow(dead_code)] fn sample_skesk5_packet() { // This sample packet is from RFC4880bis-05, section A.3. let password: Password = String::from("password").into(); @@ -627,7 +567,7 @@ mod test { let packets: Vec<Packet> = PacketPile::from_bytes(&raw[..]).unwrap().into_children().collect(); assert_eq!(packets.len(), 1); - if let Packet::SKESK(SKESK::V5(ref s)) = packets[0] { + if let Packet::SKESK(SKESK::V6(ref s)) = packets[0] { assert_eq!(&s.s2k().derive_key( &password, s.symmetric_algo().key_size().unwrap()).unwrap()[..], &[0xb2, 0x55, 0x69, 0xb9, 0x54, 0x32, 0x45, 0x66, diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs index bd33bc8c..ff2a663d 100644 --- a/openpgp/src/parse.rs +++ b/openpgp/src/parse.rs @@ -993,6 +993,12 @@ impl S2K { Self::parse_common(php, None) } + /// Reads an S2K from `php` with explicit S2K length. + fn parse_v5<T: BufferedReader<Cookie>>(php: &mut PacketHeaderParser<T>, + s2k_len: u8) -> Result<Self> { + Self::parse_common(php, Some(s2k_len)) + } + /// Reads an S2K from `php` with optional explicit S2K length. fn parse_common<T: BufferedReader<Cookie>>(php: &mut PacketHeaderParser<T>, s2k_len: Option<u8>) @@ -2652,7 +2658,7 @@ impl SKESK { let version = php_try!(php.parse_u8("version")); match version { 4 => SKESK4::parse(php), - 5 => SKESK5::parse(php), + 6 => SKESK6::parse(php), _ => php.fail("unknown version"), } } @@ -2687,58 +2693,49 @@ impl SKESK4 { } } -impl SKESK5 { +impl SKESK6 { /// Parses the body of an SK-ESK packet. fn parse<'a, T: 'a + BufferedReader<Cookie>>(mut php: PacketHeaderParser<T>) -> Result<PacketParser<'a>> { make_php_try!(php); + + // Octet count of the following 5 fields. + let parameter_len = php_try!(php.parse_u8("parameter_len")); + if parameter_len < 1 + 1 + 1 + 2 /* S2K */ + 12 /* IV */ { + return php.fail("expected at least 16 parameter octets"); + } + let sym_algo: SymmetricAlgorithm = php_try!(php.parse_u8("sym_algo")).into(); let aead_algo: AEADAlgorithm = php_try!(php.parse_u8("aead_algo")).into(); - let s2k = php_try!(S2K::parse_v4(&mut php)); - let s2k_supported = s2k.is_supported(); - let iv_size = php_try!(aead_algo.nonce_size()); - let digest_size = php_try!(aead_algo.digest_size()); - - // The rest of the packet is (potentially) the S2K - // parameters, the AEAD IV, the ESK, and the AEAD - // digest. We don't know the size of the S2K - // parameters if the S2K method is not supported, and - // we don't know the size of the ESK. - let mut esk = php_try!(php.reader.steal_eof() - .map_err(anyhow::Error::from)); - let aead_iv = if s2k_supported && esk.len() >= iv_size { - // We know the S2K method, so the parameters have - // been parsed into the S2K object. So, `esk` - // starts with iv_size bytes of IV. - let mut iv = esk; - esk = iv.split_off(iv_size); - iv - } else { - Vec::with_capacity(0) // A dummy value. - }; - let l = esk.len(); - let aead_digest = esk.split_off(l.saturating_sub(digest_size)); - // Now fix the map. - if s2k_supported { - php.field("aead_iv", iv_size); + // The S2K object's length and the S2K. + let s2k_len = php_try!(php.parse_u8("s2k_len")); + if parameter_len < 1 + 1 + 1 + s2k_len + 12 /* IV */ { + return php.fail("S2K overflows parameter count"); } - php.field("esk", esk.len()); - php.field("aead_digest", aead_digest.len()); - let skesk = php_try!(SKESK5::new_raw( + let s2k = php_try!(S2K::parse_v5(&mut php, s2k_len)); + + // And the IV. + let iv = + if let Some(iv_len) = parameter_len.checked_sub(1 + 1 + 1 + s2k_len) { + php_try!(php.parse_bytes("iv", iv_len as usize)).into() + } else { + return php.fail("IV overflows parameter count"); + }; + + // Finally, the ESK including the AEAD tag. + let esk = php_try!(php.parse_bytes_eof("esk")).into(); + + let skesk = php_try!(SKESK6::new( sym_algo, aead_algo, s2k, - if s2k_supported { - Ok((aead_iv.into(), esk.into())) - } else { - Err(esk.into()) - }, - aead_digest.into_boxed_slice(), + iv, + esk, )); php.ok(skesk.into()) diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs index 25ff0311..1f3234cc 100644 --- a/openpgp/src/parse/stream.rs +++ b/openpgp/src/parse/stream.rs @@ -2386,7 +2386,7 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> { { let decryption_proxy = |algo, secret: &SessionKey| { // Take the algo from the AED packet over - // the dummy one from the SKESK5 packet. + // the dummy one from the SKESK6 packet. let algo = sym_algo_hint.unwrap_or(algo); let result = pp.decrypt(algo, secret); if let Ok(_) = result { diff --git a/openpgp/src/serialize.rs b/openpgp/src/serialize.rs index 3d3bc0dd..a802b786 100644 --- a/openpgp/src/serialize.rs +++ b/openpgp/src/serialize.rs @@ -2450,7 +2450,7 @@ impl Marshal for SKESK { fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { match self { SKESK::V4(ref s) => s.serialize(o), - SKESK::V5(ref s) => s.serialize(o), + SKESK::V6(ref s) => s.serialize(o), } } } @@ -2459,7 +2459,7 @@ impl NetLength for SKESK { fn net_len(&self) -> usize { match self { SKESK::V4(ref s) => s.net_len(), - SKESK::V5(ref s) => s.net_len(), + SKESK::V6(ref s) => s.net_len(), } } } @@ -2468,7 +2468,7 @@ impl MarshalInto for SKESK { fn serialized_len(&self) -> usize { match self { SKESK::V4(ref s) => s.serialized_len(), - SKESK::V5(ref s) => s.serialized_len(), + SKESK::V6(ref s) => s.serialized_len(), } } @@ -2476,7 +2476,7 @@ impl MarshalInto for SKESK { match self { SKESK::V4(s) => generic_serialize_into(s, MarshalInto::serialized_len(s), buf), - SKESK::V5(s) => + SKESK::V6(s) => generic_serialize_into(s, MarshalInto::serialized_len(s), buf), } } @@ -2512,36 +2512,44 @@ impl MarshalInto for SKESK4 { } } -impl seal::Sealed for SKESK5 {} -impl Marshal for SKESK5 { +impl seal::Sealed for SKESK6 {} +impl Marshal for SKESK6 { fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> { - write_byte(o, 5)?; // Version. + let s2k_len = self.s2k().serialized_len(); + + write_byte(o, 6)?; // Version. + // Parameter octet count. + write_byte(o, (1 // Symmetric algorithm. + + 1 // AEAD mode. + + 1 // S2K octet count. + + s2k_len + + self.aead_iv().len()) as u8)?; write_byte(o, self.symmetric_algo().into())?; write_byte(o, self.aead_algo().into())?; + // S2K octet count. + write_byte(o, s2k_len as u8)?; self.s2k().serialize(o)?; - if let Ok(iv) = self.aead_iv() { - o.write_all(iv)?; - } - o.write_all(self.raw_esk())?; - o.write_all(self.aead_digest())?; + o.write_all(self.aead_iv())?; + o.write_all(self.esk())?; Ok(()) } } -impl NetLength for SKESK5 { +impl NetLength for SKESK6 { fn net_len(&self) -> usize { 1 // Version. + + 1 // Parameter octet count. + 1 // Cipher algo. + 1 // AEAD algo. + + 1 // S2K octet count. + self.s2k().serialized_len() - + self.aead_iv().map(|iv| iv.len()).unwrap_or(0) - + self.raw_esk().len() - + self.aead_digest().len() + + self.aead_iv().len() + + self.esk().len() } } -impl MarshalInto for SKESK5 { +impl MarshalInto for SKESK6 { fn serialized_len(&self) -> usize { self.net_len() } diff --git a/openpgp/src/serialize/stream.rs b/openpgp/src/serialize/stream.rs index 42b46d88..91a1a38d 100644 --- a/openpgp/src/serialize/stream.rs +++ b/openpgp/src/serialize/stream.rs @@ -2924,7 +2924,7 @@ impl<'a> Encryptor<'a> { // Write the SKESK packet(s). for password in self.passwords.iter() { if let Some(aead) = aead.as_ref() { - let skesk = SKESK5::with_password(self.sym_algo, + let skesk = SKESK6::with_password(self.sym_algo, self.sym_algo, aead.algo, Default::default(), diff --git a/sq/src/commands/dump.rs b/sq/src/commands/dump.rs index 7a76b6d1..a9115bf7 100644 --- a/sq/src/commands/dump.rs +++ b/sq/src/commands/dump.rs @@ -676,23 +676,17 @@ impl PacketDumper { } }, - self::openpgp::packet::SKESK::V5(ref s) => { + self::openpgp::packet::SKESK::V6(ref s) => { writeln!(output, "{} Symmetric algo: {}", i, s.symmetric_algo())?; writeln!(output, "{} AEAD: {}", i, s.aead_algo())?; write!(output, "{} S2K: ", i)?; self.dump_s2k(output, i, s.s2k())?; - if let Ok(iv) = s.aead_iv() { - writeln!(output, "{} IV: {}", i, - hex::encode(iv))?; - } - if let Ok(Some(esk)) = s.esk() { - writeln!( |