summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-02-16 16:13:04 +0100
committerJustus Winter <justus@sequoia-pgp.org>2024-03-13 10:59:50 +0100
commitcf923f1ea07493c10dda6ecf21009f699eacd432 (patch)
treedbf101a3e84c39417fdada8b11ece83d5f862bb4
parentdc7a668bea6bc45fdba5bfe2565d1dcc4966251a (diff)
openpgp: Implement v2 SEIPD.
-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.rs166
-rw-r--r--openpgp/src/parse.rs104
-rw-r--r--openpgp/src/parse/stream.rs74
-rw-r--r--openpgp/src/serialize.rs95
-rw-r--r--openpgp/src/serialize/stream.rs30
13 files changed, 556 insertions, 53 deletions
diff --git a/openpgp/src/crypto/aead.rs b/openpgp/src/crypto/aead.rs
index 4cf0cfd1..706abb07 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::backend::{Backend, interface::Kdf};
/// Minimum AEAD chunk size.
///
@@ -232,6 +233,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,
+ ];
+ Backend::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 7289d748..e938c4e0 100644
--- a/openpgp/src/message/lexer.rs
+++ b/openpgp/src/message/lexer.rs
@@ -27,6 +27,8 @@ pub enum Token {
PKESK,
/// 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 2d2d6884..ec630736 100644
--- a/openpgp/src/message/mod.rs
+++ b/openpgp/src/message/mod.rs
@@ -207,6 +207,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 6956791c..81eb23b6 100644
--- a/openpgp/src/packet/mod.rs
+++ b/openpgp/src/packet/mod.rs
@@ -481,7 +481,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,
#[allow(deprecated)]
Packet::MDC(ref packet) => &packet.common,
Packet::AED(ref packet) => &packet.common,
@@ -510,7 +511,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,
#[allow(deprecated)]
Packet::MDC(ref mut packet) => &mut packet.common,
Packet::AED(ref mut packet) => &mut packet.common,
@@ -2116,6 +2118,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);
@@ -2124,6 +2129,7 @@ impl SEIP {
pub fn version(&self) -> u8 {
match self {
SEIP::V1(_) => 1,
+ SEIP::V2(_) => 2,
}
}
}
@@ -2134,26 +2140,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 c06339c1..bda7a7e2 100644
--- a/openpgp/src/packet/prelude.rs
+++ b/openpgp/src/packet/prelude.rs
@@ -51,7 +51,10 @@ pub use crate::packet::{
one_pass_sig::OnePassSig3,
one_pass_sig::OnePassSig6,
pkesk::PKESK3,
- seip::SEIP1,
+ seip::{
+ SEIP1,
+ SEIP2,
+ },
signature,
signature::Signature4,
signature::Signature6,
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..9942e02a
--- /dev/null
+++ b/openpgp/src/packet/seip/v2.rs
@@ -0,0 +1,166 @@
+//! Symmetrically Encrypted Integrity Protected data packets version 2.
+//!
+//! An encrypted data packet is a container. See [Section 5.13.2 of
+//! draft-ietf-openpgp-crypto-refresh-10] for details.
+//!
+//! [Section 5.13.2 of draft-ietf-openpgp-crypto-refresh-10]: https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-version-2-symmetrically-enc
+use crate::{
+ Error,
+ packet::{
+ self,
+ Packet,
+ SEIP,
+ },
+ Result,
+ types::{
+ AEADAlgorithm,
+ SymmetricAlgorithm,
+ },
+};
+
+/// Holds an encrypted data packet.
+///
+/// An encrypted data packet is a container. See [Section 5.13.2 of
+/// draft-ietf-openpgp-crypto-refresh-10] for details.
+///
+/// [Section 5.13.2 of draft-ietf-openpgp-crypto-refresh-10]: https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-version-2-symmetrically-enc
+///
+/// # 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 935d2412..b5dc983f 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -3447,16 +3447,49 @@ impl SEIP {
fn parse(mut php: PacketHeaderParser) -> Result<PacketParser> {
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_with_buffered_reader!(SEIP);
+
+impl SEIP1 {
+ /// Parses the body of a SEIP1 packet.
+ fn parse(php: PacketHeaderParser) -> Result<PacketParser> {
php.ok(SEIP1::new().into())
.map(|pp| pp.set_processed(false))
}
}
-impl_parse_with_buffered_reader!(SEIP);
+impl SEIP2 {
+ /// Parses the body of a SEIP1 packet.
+ fn parse(mut php: PacketHeaderParser) -> Result<PacketParser> {
+ 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"));
+
+ // An implementation MUST accept chunk size octets with values
+ // from 0 to 16. An implementation MUST NOT create data with a
+ // chunk size octet value larger than 16 (4 MiB chunks).
+ if chunk_size > 16 {
+ 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.
@@ -5569,7 +5602,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),
@@ -6033,7 +6068,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.
@@ -6105,6 +6140,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 b42ae16b..ccc3fc84 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,
@@ -2429,10 +2430,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 {
@@ -4150,6 +4151,71 @@ xHUDBRY0WIQ+50WENDPP";
.with_policy(&p, crate::frozen_time(), helper)?;
assert!(v.message_processed());
assert_eq!(v.helper_ref().good, 2);
+
+ Ok(())
+ }
+
+ /// This sample packet is from RFC9760.
+ #[test]
+ fn v6skesk_v2seip_aes128_ocb() -> Result<()> {
+ sample_skesk6_packet(
+ SymmetricAlgorithm::AES128,
+ AEADAlgorithm::OCB,
+ "password",
+ "crypto-refresh/v6skesk-aes128-ocb.pgp",
+ b"Hello, world!")
+ }
+
+ /// This sample packet is from RFC9760.
+ #[test]
+ fn v6skesk_v2seip_aes128_eax() -> Result<()> {
+ sample_skesk6_packet(
+ SymmetricAlgorithm::AES128,
+ AEADAlgorithm::EAX,
+ "password",
+ "crypto-refresh/v6skesk-aes128-eax.pgp",
+ b"Hello, world!")
+ }
+
+ /// This sample packet is from RFCXXX.
+ #[test]
+ fn v6skesk_v2seip_aes128_gcm() -> Result<()> {
+ sample_skesk6_packet(
+ SymmetricAlgorithm::AES128,
+ AEADAlgorithm::GCM,
+ "password",
+ "crypto-refresh/v6skesk-aes128-gcm.pgp",
+ b"Hello, world!")
+ }
+
+ fn sample_skesk6_packet(cipher: SymmetricAlgorithm,
+ aead: AEADAlgorithm,
+ password: &str,
+ name: &str,
+ plaintext: &[u8])
+ -> Result<()> {
+ if ! (aead.is_supported()
+ && aead.supports_symmetric_algo(&cipher))
+ {
+ eprintln!("Skipping test vector {:?}...", name);
+ return Ok(());
+ }
+
+ eprintln!("Test vector {:?}...", name);
+
+ let p = &P::new();
+ let password: Password = String::from(password).into();
+
+ let h = VHelper::for_decryption(0, 0, 0, 0, vec![], vec![],
+ vec![password]);
+ let mut d = DecryptorBuilder::from_bytes(crate::tests::file(name))?
+ .with_policy(p, None, h)?;
+ assert!(d.message_processed());
+
+ let mut content = Vec::new();
+ d.read_to_end(&mut content).unwrap();
+ assert_eq!(&content, plaintext);
+
Ok(())
}
}
diff --git a/openpgp/src/serialize.rs b/openpgp/src/serialize.rs
index 11133e01..a8cb5cf8 100644
--- a/openpgp/src/serialize.rs
+++ b/openpgp/src/serialize.rs
@@ -2929,7 +2929,36 @@ impl MarshalInto for SKESK6 {
impl seal::Sealed for SEIP {}
impl Marshal for SEIP {
- /// Writes a serialized version of the specified `SEIP`
+