summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2022-01-20 15:43:25 +0100
committerJustus Winter <justus@sequoia-pgp.org>2023-02-14 20:04:17 +0100
commit26cdea5d1bf96966e7fb82317577102810c576b2 (patch)
tree039f875171fcafe256e9e4f26993b005f1f9b05c
parent28cc59330c175d14685e0f32945bb26c4083cd53 (diff)
openpgp: SEIPv2. XXXjustus/openpgp-next-seipv2
- See https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/122
-rw-r--r--openpgp/src/crypto/aead.rs82
-rw-r--r--openpgp/src/message/grammar.lalrpop6
-rw-r--r--openpgp/src/message/lexer.rs2
-rw-r--r--openpgp/src/message/mod.rs1
-rw-r--r--openpgp/src/packet/container.rs11
-rw-r--r--openpgp/src/packet/mod.rs30
-rw-r--r--openpgp/src/packet/prelude.rs5
-rw-r--r--openpgp/src/packet/seip.rs3
-rw-r--r--openpgp/src/packet/seip/v2.rs161
-rw-r--r--openpgp/src/parse.rs109
-rw-r--r--openpgp/src/parse/stream.rs9
-rw-r--r--openpgp/src/serialize.rs95
-rw-r--r--openpgp/src/serialize/stream.rs30
-rw-r--r--sq/src/commands/dump.rs9
14 files changed, 500 insertions, 53 deletions
diff --git a/openpgp/src/crypto/aead.rs b/openpgp/src/crypto/aead.rs
index 0bded6a8..c0a38756 100644
--- a/openpgp/src/crypto/aead.rs
+++ b/openpgp/src/crypto/aead.rs
@@ -17,6 +17,7 @@ use crate::Result;
use crate::crypto::SessionKey;
use crate::seal;
use crate::parse::Cookie;
+use crate::crypto::hkdf_sha256;
/// Minimum AEAD chunk size.
///
@@ -235,6 +236,87 @@ impl Schedule for AEDv1Schedule {
}
}
+const SEIP2AD_PREFIX_LEN: usize = 5;
+pub(crate) struct SEIPv2Schedule {
+ nonce: Box<[u8]>,
+ ad: [u8; SEIP2AD_PREFIX_LEN],
+ nonce_len: usize,
+}
+
+impl SEIPv2Schedule {
+ pub(crate) fn new(session_key: &SessionKey,
+ sym_algo: SymmetricAlgorithm,
+ aead: AEADAlgorithm,
+ chunk_size: usize,
+ salt: &[u8]) -> Result<(SessionKey, Self)>
+ {
+ if !(MIN_CHUNK_SIZE..=MAX_CHUNK_SIZE).contains(&chunk_size) {
+ return Err(Error::InvalidArgument(
+ format!("Invalid AEAD chunk size: {}", chunk_size)).into());
+ }
+
+ // Derive the message key and initialization vector.
+ let key_size = sym_algo.key_size()?;
+ // The NONCE size is NONCE_LEN - 8 bytes taken from the KDF.
+ let nonce_size = aead.nonce_size()? - 8;
+ let mut key_nonce: SessionKey =
+ vec![0; key_size + nonce_size].into();
+ let ad = [
+ 0xd2, // Tag.
+ 2, // Version.
+ sym_algo.into(),
+ aead.into(),
+ chunk_size.trailing_zeros() as u8 - 6,
+ ];
+ hkdf_sha256(session_key, Some(salt), &ad, &mut key_nonce);
+ let key = Vec::from(&key_nonce[..key_size]).into();
+ let nonce = Vec::from(&key_nonce[key_size..]).into();
+
+ Ok((key, Self {
+ nonce,
+ ad,
+ nonce_len: aead.nonce_size()?,
+ }))
+ }
+}
+
+impl Schedule for SEIPv2Schedule {
+ fn next_chunk<F, R>(&self, index: u64, mut fun: F) -> R
+ where
+ F: FnMut(&[u8], &[u8]) -> R,
+ {
+ // The nonce is the NONCE (NONCE_LEN - 8 bytes taken from the
+ // KDF) concatenated with the chunk index.
+ let index_be: [u8; 8] = index.to_be_bytes();
+ let mut nonce_store = [0u8; MAX_NONCE_LEN];
+ let nonce = &mut nonce_store[..self.nonce_len];
+ nonce[..self.nonce.len()].copy_from_slice(&self.nonce);
+ nonce[self.nonce.len()..].copy_from_slice(&index_be);
+
+ fun(nonce, &self.ad)
+ }
+
+ fn final_chunk<F, R>(&self, index: u64, length: u64, mut fun: F) -> R
+ where
+ F: FnMut(&[u8], &[u8]) -> R,
+ {
+ // Prepare the associated data.
+ let mut ad = [0u8; SEIP2AD_PREFIX_LEN + 8];
+ ad[..SEIP2AD_PREFIX_LEN].copy_from_slice(&self.ad);
+ write_be_u64(&mut ad[SEIP2AD_PREFIX_LEN..], length);
+
+ // The nonce is the NONCE (NONCE_LEN - 8 bytes taken from the
+ // KDF) concatenated with the chunk index.
+ let index_be: [u8; 8] = index.to_be_bytes();
+ let mut nonce_store = [0u8; MAX_NONCE_LEN];
+ let nonce = &mut nonce_store[..self.nonce_len];
+ nonce[..self.nonce.len()].copy_from_slice(&self.nonce);
+ nonce[self.nonce.len()..].copy_from_slice(&index_be);
+
+ fun(nonce, &ad)
+ }
+}
+
/// A `Read`er for decrypting AEAD-encrypted data.
pub struct Decryptor<'a, S: Schedule> {
// The encrypted data.
diff --git a/openpgp/src/message/grammar.lalrpop b/openpgp/src/message/grammar.lalrpop
index f98b3786..03b5776f 100644
--- a/openpgp/src/message/grammar.lalrpop
+++ b/openpgp/src/message/grammar.lalrpop
@@ -21,6 +21,10 @@ Seipv1Part: () = {
SEIPv1 OPAQUE_CONTENT POP,
}
+Seipv2Part: () = {
+ SEIPv2 Message POP,
+}
+
AedPart: () = {
AED Message POP,
}
@@ -33,6 +37,7 @@ EncryptedPart: () = {
EncryptionContainer: () = {
Seipv1Part,
+ Seipv2Part,
AedPart,
};
@@ -69,6 +74,7 @@ extern {
SKESK => lexer::Token::SKESK,
PKESK => lexer::Token::PKESK,
SEIPv1 => lexer::Token::SEIPv1,
+ SEIPv2 => lexer::Token::SEIPv2,
MDC => lexer::Token::MDC,
AED => lexer::Token::AED,
OPS => lexer::Token::OPS,
diff --git a/openpgp/src/message/lexer.rs b/openpgp/src/message/lexer.rs
index 8e495e4b..5cf91e56 100644
--- a/openpgp/src/message/lexer.rs
+++ b/openpgp/src/message/lexer.rs
@@ -31,6 +31,8 @@ pub enum Token {
SEIP,
/// A version 1 SEIP packet.
SEIPv1,
+ /// A version 2 SEIP packet.
+ SEIPv2,
/// An MDC packet.
MDC,
/// An AED packet.
diff --git a/openpgp/src/message/mod.rs b/openpgp/src/message/mod.rs
index 441fc334..32895dee 100644
--- a/openpgp/src/message/mod.rs
+++ b/openpgp/src/message/mod.rs
@@ -205,6 +205,7 @@ impl MessageValidator {
Tag::SKESK => Token::SKESK,
Tag::PKESK => Token::PKESK,
Tag::SEIP if version == Some(1) => Token::SEIPv1,
+ Tag::SEIP if version == Some(2) => Token::SEIPv2,
Tag::MDC => Token::MDC,
Tag::AED => Token::AED,
Tag::OnePassSig => Token::OPS,
diff --git a/openpgp/src/packet/container.rs b/openpgp/src/packet/container.rs
index fd8c0f2f..7bfc20ba 100644
--- a/openpgp/src/packet/container.rs
+++ b/openpgp/src/packet/container.rs
@@ -12,7 +12,10 @@ use xxhash_rust::xxh3::Xxh3;
use crate::{
Packet,
- packet::Iter,
+ packet::{
+ Iter,
+ SEIP,
+ },
};
/// A packet's body holds either unprocessed bytes, processed bytes,
@@ -400,7 +403,8 @@ impl Packet {
use std::ops::Deref;
match self {
Packet::CompressedData(p) => Some(p.deref()),
- Packet::SEIP(p) => Some(p.deref()),
+ Packet::SEIP(SEIP::V1(p)) => Some(p.deref()),
+ Packet::SEIP(SEIP::V2(p)) => Some(p.deref()),
Packet::AED(p) => Some(p.deref()),
Packet::Literal(p) => Some(p.container_ref()),
Packet::Unknown(p) => Some(p.container_ref()),
@@ -413,7 +417,8 @@ impl Packet {
use std::ops::DerefMut;
match self {
Packet::CompressedData(p) => Some(p.deref_mut()),
- Packet::SEIP(p) => Some(p.deref_mut()),
+ Packet::SEIP(SEIP::V1(p)) => Some(p.deref_mut()),
+ Packet::SEIP(SEIP::V2(p)) => Some(p.deref_mut()),
Packet::AED(p) => Some(p.deref_mut()),
Packet::Literal(p) => Some(p.container_mut()),
Packet::Unknown(p) => Some(p.container_mut()),
diff --git a/openpgp/src/packet/mod.rs b/openpgp/src/packet/mod.rs
index 9f4d2ad3..a46e21d8 100644
--- a/openpgp/src/packet/mod.rs
+++ b/openpgp/src/packet/mod.rs
@@ -467,7 +467,8 @@ impl Deref for Packet {
Packet::PKESK(ref packet) => &packet.common,
Packet::SKESK(SKESK::V4(ref packet)) => &packet.common,
Packet::SKESK(SKESK::V6(ref packet)) => &packet.skesk4.common,
- Packet::SEIP(ref packet) => &packet.common,
+ Packet::SEIP(SEIP::V1(packet)) => &packet.common,
+ Packet::SEIP(SEIP::V2(packet)) => &packet.common,
Packet::MDC(ref packet) => &packet.common,
Packet::AED(ref packet) => &packet.common,
Packet::Padding(packet) => &packet.common,
@@ -494,7 +495,8 @@ impl DerefMut for Packet {
Packet::PKESK(ref mut packet) => &mut packet.common,
Packet::SKESK(SKESK::V4(ref mut packet)) => &mut packet.common,
Packet::SKESK(SKESK::V6(ref mut packet)) => &mut packet.skesk4.common,
- Packet::SEIP(ref mut packet) => &mut packet.common,
+ Packet::SEIP(SEIP::V1(packet)) => &mut packet.common,
+ Packet::SEIP(SEIP::V2(packet)) => &mut packet.common,
Packet::MDC(ref mut packet) => &mut packet.common,
Packet::AED(ref mut packet) => &mut packet.common,
Packet::Padding(packet) => &mut packet.common,
@@ -1917,6 +1919,9 @@ impl<P: key::KeyParts, R: key::KeyRole> DerefMut for Key<P, R> {
pub enum SEIP {
/// SEIP packet version 1.
V1(self::seip::SEIP1),
+
+ /// SEIP packet version 2.
+ V2(self::seip::SEIP2),
}
assert_send_and_sync!(SEIP);
@@ -1925,6 +1930,7 @@ impl SEIP {
pub fn version(&self) -> u8 {
match self {
SEIP::V1(_) => 1,
+ SEIP::V2(_) => 2,
}
}
}
@@ -1935,26 +1941,6 @@ impl From<SEIP> for Packet {
}
}
-// Trivial forwarder for singleton enum.
-impl Deref for SEIP {
- type Target = self::seip::SEIP1;
-
- fn deref(&self) -> &Self::Target {
- match self {
- SEIP::V1(ref p) => p,
- }
- }
-}
-
-// Trivial forwarder for singleton enum.
-impl DerefMut for SEIP {
- fn deref_mut(&mut self) -> &mut Self::Target {
- match self {
- SEIP::V1(ref mut p) => p,
- }
- }
-}
-
/// Holds an AEAD encrypted data packet.
///
/// An AEAD packet holds encrypted data. It is contains additional
diff --git a/openpgp/src/packet/prelude.rs b/openpgp/src/packet/prelude.rs
index 69e3515c..e7dba6dc 100644
--- a/openpgp/src/packet/prelude.rs
+++ b/openpgp/src/packet/prelude.rs
@@ -49,7 +49,10 @@ pub use crate::packet::{
key::SecretKeyMaterial,
one_pass_sig::OnePassSig3,
pkesk::PKESK3,
- seip::SEIP1,
+ seip::{
+ SEIP1,
+ SEIP2,
+ },
signature,
signature::Signature4,
signature::SignatureBuilder,
diff --git a/openpgp/src/packet/seip.rs b/openpgp/src/packet/seip.rs
index b808acf2..e74db749 100644
--- a/openpgp/src/packet/seip.rs
+++ b/openpgp/src/packet/seip.rs
@@ -8,6 +8,9 @@
use crate::packet;
use crate::Packet;
+mod v2;
+pub use v2::*;
+
/// Holds an encrypted data packet.
///
/// An encrypted data packet is a container. See [Section 5.13 of RFC
diff --git a/openpgp/src/packet/seip/v2.rs b/openpgp/src/packet/seip/v2.rs
new file mode 100644
index 00000000..85d02289
--- /dev/null
+++ b/openpgp/src/packet/seip/v2.rs
@@ -0,0 +1,161 @@
+//! Symmetrically Encrypted Integrity Protected data packets version 2.
+//!
+//! An encrypted data packet is a container. See [XXX] for details.
+
+use crate::{
+ Error,
+ packet::{
+ self,
+ Packet,
+ SEIP,
+ },
+ Result,
+ types::{
+ AEADAlgorithm,
+ SymmetricAlgorithm,
+ },
+};
+
+/// Holds an encrypted data packet.
+///
+/// An encrypted data packet is a container. See [XXX] for details.
+///
+/// # A note on equality
+///
+/// An unprocessed (encrypted) `SEIP2` packet is never considered equal
+/// to a processed (decrypted) one. Likewise, a processed (decrypted)
+/// packet is never considered equal to a structured (parsed) one.
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct SEIP2 {
+ /// CTB packet header fields.
+ pub(crate) common: packet::Common,
+
+ /// Symmetric algorithm.
+ sym_algo: SymmetricAlgorithm,
+ /// AEAD algorithm.
+ aead: AEADAlgorithm,
+ /// Chunk size.
+ chunk_size: u64,
+ /// Salt.
+ salt: [u8; 32],
+
+ /// This is a container packet.
+ container: packet::Container,
+}
+
+assert_send_and_sync!(SEIP2);
+
+impl std::ops::Deref for SEIP2 {
+ type Target = packet::Container;
+ fn deref(&self) -> &Self::Target {
+ &self.container
+ }
+}
+
+impl std::ops::DerefMut for SEIP2 {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.container
+ }
+}
+
+impl SEIP2 {
+ /// Creates a new SEIP2 packet.
+ pub fn new(sym_algo: SymmetricAlgorithm,
+ aead: AEADAlgorithm,
+ chunk_size: u64,
+ salt: [u8; 32]) -> Result<Self> {
+ if chunk_size.count_ones() != 1 {
+ return Err(Error::InvalidArgument(
+ format!("chunk size is not a power of two: {}", chunk_size))
+ .into());
+ }
+
+ if chunk_size < 64 {
+ return Err(Error::InvalidArgument(
+ format!("chunk size is too small: {}", chunk_size))
+ .into());
+ }
+
+ Ok(SEIP2 {
+ common: Default::default(),
+ sym_algo,
+ aead,
+ chunk_size,
+ salt,
+ container: Default::default(),
+ })
+ }
+
+ /// Gets the symmetric algorithm.
+ pub fn symmetric_algo(&self) -> SymmetricAlgorithm {
+ self.sym_algo
+ }
+
+ /// Sets the symmetric algorithm.
+ pub fn set_symmetric_algo(&mut self, sym_algo: SymmetricAlgorithm)
+ -> SymmetricAlgorithm {
+ std::mem::replace(&mut self.sym_algo, sym_algo)
+ }
+
+ /// Gets the AEAD algorithm.
+ pub fn aead(&self) -> AEADAlgorithm {
+ self.aead
+ }
+
+ /// Sets the AEAD algorithm.
+ pub fn set_aead(&mut self, aead: AEADAlgorithm) -> AEADAlgorithm {
+ std::mem::replace(&mut self.aead, aead)
+ }
+
+ /// Gets the chunk size.
+ pub fn chunk_size(&self) -> u64 {
+ self.chunk_size
+ }
+
+ /// Sets the chunk size.
+ pub fn set_chunk_size(&mut self, chunk_size: u64) -> Result<()> {
+ if chunk_size.count_ones() != 1 {
+ return Err(Error::InvalidArgument(
+ format!("chunk size is not a power of two: {}", chunk_size))
+ .into());
+ }
+
+ if chunk_size < 64 {
+ return Err(Error::InvalidArgument(
+ format!("chunk size is too small: {}", chunk_size))
+ .into());
+ }
+
+ self.chunk_size = chunk_size;
+ Ok(())
+ }
+
+ /// Gets the size of a chunk with a digest.
+ pub fn chunk_digest_size(&self) -> Result<u64> {
+ Ok(self.chunk_size + self.aead.digest_size()? as u64)
+ }
+
+ /// Gets the salt.
+ pub fn salt(&self) -> &[u8; 32] {
+ &self.salt
+ }
+
+ /// Sets the salt.
+ pub fn set_salt(&mut self, salt: [u8; 32]) -> [u8; 32] {
+ std::mem::replace(&mut self.salt, salt)
+ }
+}
+
+impl From<SEIP2> for SEIP {
+ fn from(p: SEIP2) -> Self {
+ SEIP::V2(p)
+ }
+}
+
+impl From<SEIP2> for Packet {
+ fn from(s: SEIP2) -> Self {
+ Packet::SEIP(s.into())
+ }
+}
diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs
index ff2a663d..a7aa3a68 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -2798,16 +2798,54 @@ impl SEIP {
fn parse<'a, T: 'a + BufferedReader<Cookie>>(mut php: PacketHeaderParser<T>) -> Result<PacketParser<'a>> {
make_php_try!(php);
let version = php_try!(php.parse_u8("version"));
- if version != 1 {
- return php.fail("unknown version");
+ match version {
+ 1 => SEIP1::parse(php),
+ 2 => SEIP2::parse(php),
+ _ => php.fail("unknown version"),
}
+ }
+}
+impl_parse_generic_packet!(SEIP);
+
+impl SEIP1 {
+ /// Parses the body of a SEIP1 packet.
+ fn parse<'a, T: 'a + BufferedReader<Cookie>>(php: PacketHeaderParser<T>)
+ -> Result<PacketParser<'a>>
+ {
php.ok(SEIP1::new().into())
.map(|pp| pp.set_processed(false))
}
}
-impl_parse_generic_packet!(SEIP);
+impl SEIP2 {
+ /// Parses the body of a SEIP1 packet.
+ fn parse<'a, T: 'a + BufferedReader<Cookie>>(mut php: PacketHeaderParser<T>)
+ -> Result<PacketParser<'a>>
+ {
+ make_php_try!(php);
+ let cipher: SymmetricAlgorithm =
+ php_try!(php.parse_u8("sym_algo")).into();
+ let aead: AEADAlgorithm =
+ php_try!(php.parse_u8("aead_algo")).into();
+ let chunk_size = php_try!(php.parse_u8("chunk_size"));
+
+ // DRAFT 4880bis-08, section 5.16: "An implementation MUST
+ // support chunk size octets with values from 0 to 56. Chunk
+ // size octets with other values are reserved for future
+ // extensions."
+ if chunk_size > 56 {
+ return php.fail("unsupported chunk size");
+ }
+ let chunk_size: u64 = 1 << (chunk_size + 6);
+ let salt_v = php_try!(php.parse_bytes("salt", 32));
+ let mut salt = [0u8; 32];
+ salt.copy_from_slice(&salt_v);
+
+ let seip2 = php_try!(Self::new(cipher, aead, chunk_size, salt));
+ php.ok(seip2.into()).map(|pp| pp.set_processed(false))
+ }
+}
impl MDC {
/// Parses the body of an MDC packet.
@@ -4852,7 +4890,9 @@ impl <'a> PacketParser<'a> {
Packet::Unknown(p) => set_or_extend(rest, p.container_mut(), false),
Packet::CompressedData(p) =>
set_or_extend(rest, p.deref_mut(), self.processed),
- Packet::SEIP(p) =>
+ Packet::SEIP(SEIP::V1(p)) =>
+ set_or_extend(rest, p.deref_mut(), self.processed),
+ Packet::SEIP(SEIP::V2(p)) =>
set_or_extend(rest, p.deref_mut(), self.processed),
Packet::AED(p) =>
set_or_extend(rest, p.deref_mut(), self.processed),
@@ -5316,7 +5356,7 @@ impl<'a> PacketParser<'a> {
}
match self.packet.clone() {
- Packet::SEIP(_) => {
+ Packet::SEIP(SEIP::V1(_)) => {
// Get the first blocksize plus two bytes and check
// whether we can decrypt them using the provided key.
// Don't actually consume them in case we can't.
@@ -5388,6 +5428,65 @@ impl<'a> PacketParser<'a> {
Ok(())
},
+ Packet::SEIP(SEIP::V2(seip)) => {
+ let chunk_size =
+ aead::chunk_size_usize(seip.chunk_size())?;
+
+ // Read the first chunk and check whether we can
+ // decrypt it using the provided key. Don't actually
+ // consume them in case we can't.
+ {
+ // We need a bit more than one chunk so that
+ // `aead::Decryptor` won't see EOF and think that
+ // it has a partial block and it needs to verify
+ // the final chunk.
+ let amount = aead::chunk_size_usize(
+ seip.chunk_digest_size()?
+ + seip.aead().digest_size()? as u64)?;
+
+ let data = self.data(amount)?;
+ let (message_key, schedule) = aead::SEIPv2Schedule::new(
+ &key,
+ seip.symmetric_algo(),
+ seip.aead(),
+ chunk_size,
+ seip.salt())?;
+
+ let dec = aead::Decryptor::new(
+ seip.symmetric_algo(), seip.aead(), chunk_size,
+ schedule, message_key,
+ &data[..cmp::min(data.len(), amount)])?;
+ let mut chunk = Vec::new();
+ dec.take(seip.chunk_size() as u64).read_to_end(&mut chunk)?;
+ }
+
+ // Ok, we can decrypt the data. Push a Decryptor and
+ // a HashedReader on the `BufferedReader` stack.
+
+ // This can't fail, because we create a decryptor
+ // above with the same parameters.
+ let (message_key, schedule) = aead::SEIPv2Schedule::new(
+ &key,
+ seip.symmetric_algo(),
+ seip.aead(),
+ chunk_size,
+ seip.salt())?;
+
+ let reader = self.take_reader();
+ let mut reader = aead::BufferedReaderDecryptor::with_cookie(
+ seip.symmetric_algo(), seip.aead(), chunk_size,
+ schedule, message_key, reader, Cookie::default()).unwrap();
+ reader.cookie_mut().level = Some(self.recursion_depth());
+
+ t!("Pushing aead::Decryptor, level {:?}.",
+ reader.cookie_ref().level);
+
+ self.reader = Box::new(reader);
+ self.processed = true;
+
+ Ok(())
+ },
+
Packet::AED(AED::V1(aed)) => {
let chunk_size =
aead::chunk_size_usize(aed.chunk_size())?;
diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs
index 1f3234cc..d5e11182 100644
--- a/openpgp/src/parse/stream.rs
+++ b/openpgp/src/parse/stream.rs
@@ -120,6 +120,7 @@ use crate::{
key,
OnePassSig,
PKESK,
+ SEIP,
SKESK,
},
KeyHandle,
@@ -2369,10 +2370,10 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> {
}
}
- let sym_algo_hint = if let Packet::AED(ref aed) = pp.packet {
- Some(aed.symmetric_algo())
- } else {
- None
+ let sym_algo_hint = match &pp.packet {
+ Packet::SEIP(SEIP::V2(seip)) => Some(seip.symmetric_algo()),
+ Packet::AED(aed) => Some(aed.symmetric_algo()),
+ _ => None,
};
match pp.packet {
diff --git a/openpgp/src/serialize.rs b/openpgp/src/serialize.rs
index a802b786..0fb3269a 100644
--- a/openpgp/src/serialize.rs
+++ b/openpgp/src/serialize.rs
@@ -2561,7 +2561,36 @@ impl MarshalInto for SKESK6 {
impl seal::Sealed for SEIP {}
impl Marshal for SEIP {
- /// Writes a serialized version of the specified `SEIP`
+ fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
+ match self {
+ SEIP::V1(p) => p.serialize(o),
+ SEIP::V2(p) => p.serialize(o),
+ }
+ }
+}
+
+impl NetLength for SEIP {
+ fn net_len(&self) -> usize {
+ match self {
+ SEIP::V1(p) => p.net_len(),
+ SEIP::V2(p) => p.net_len(),
+ }
+ }
+}
+
+impl MarshalInto for SEIP {
+ fn serialized_len(&self) -> usize {
+ self.net_len()
+ }
+
+ fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
+ generic_serialize_into(self, MarshalInto::serialized_len(self), buf)
+ }
+}
+
+impl seal::Sealed for SEIP1 {}
+impl Marshal for SEIP1 {
+ /// Writes a serialized version of the specified `SEIP1`
/// packet to `o`.
///
/// # Errors
@@ -2572,7 +2601,7 @@ impl Marshal for SEIP {
fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
match self.body() {
Body::Unprocessed(bytes) => {
- o.write_all(&[self.version()])?;
+ o.write_all(&[1])?;
o.write_all(bytes)?;
Ok(())
},
@@ -2583,7 +2612,7 @@ impl Marshal for SEIP {
}
}
-impl NetLength for SEIP {
+impl NetLength for SEIP1 {
fn net_len(&self) -> usize {
match self.body() {
Body::Unprocessed(bytes) => 1 /* Version */ + bytes.len(),
@@ -2592,7 +2621,65 @@ impl NetLength for SEIP {
}
}
-impl MarshalInto for SEIP {
+impl MarshalInto for SEIP1 {
+ fn serialized_len(&self) -> usize {
+ self.net_len()
+ }
+
+ fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
+ generic_serialize_into(self, MarshalInto::serialized_len(self), buf)
+ }
+}
+
+impl SEIP2 {
+ /// Writes the headers of the `SEIP2` data packet to `o`.
+ fn serialize_headers(&self, o: &mut dyn std::io::Write) -> Result<()> {
+ o.write_all(&[2, // Version.
+ self.symmetric_algo().into(),
+ self.aead().into(),
+ self.chunk_size().trailing_zeros() as u8 - 6])?;
+ o.write_all(self.salt())?;
+ Ok(())
+ }
+}
+
+impl seal::Sealed for SEIP2 {}
+impl Marshal for SEIP2 {
+ /// Writes a serialized version of the specified `AED`
+ /// packet