summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-02-14 19:37:54 +0100
committerJustus Winter <justus@sequoia-pgp.org>2023-02-14 20:03:58 +0100
commit28cc59330c175d14685e0f32945bb26c4083cd53 (patch)
treefd98e4e8a1cfcfb008538c577b1128ecabc73dac
parent242c36ac97475e3988ed13abcd7e638783542762 (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.rs10
-rw-r--r--openpgp/src/packet/prelude.rs2
-rw-r--r--openpgp/src/packet/skesk.rs244
-rw-r--r--openpgp/src/parse.rs73
-rw-r--r--openpgp/src/parse/stream.rs2
-rw-r--r--openpgp/src/serialize.rs42
-rw-r--r--openpgp/src/serialize/stream.rs2
-rw-r--r--sq/src/commands/dump.rs16
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!(