summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-06-26 13:27:02 +0200
committerJustus Winter <justus@sequoia-pgp.org>2023-06-26 13:27:02 +0200
commitc4397071a3b72f64ba73e770cdbe72255abddbc6 (patch)
tree599072ea7caa1b3e6fb938dda40ec07734a30917
parent0ccfa1491a17dd24b4dc82c1d9a40d2e48aac027 (diff)
parent55e665a1894f7d27f31a34a474e4ce77d02c7768 (diff)
Merge branch 'crypto-refresh-seip-v2' into crypto-refresh
-rw-r--r--openpgp/src/cert/parser/mod.rs18
-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.rs6
-rw-r--r--openpgp/src/packet/any.rs2
-rw-r--r--openpgp/src/packet/container.rs11
-rw-r--r--openpgp/src/packet/header/mod.rs1
-rw-r--r--openpgp/src/packet/mod.rs55
-rw-r--r--openpgp/src/packet/padding.rs92
-rw-r--r--openpgp/src/packet/prelude.rs8
-rw-r--r--openpgp/src/packet/seip.rs3
-rw-r--r--openpgp/src/packet/seip/v2.rs161
-rw-r--r--openpgp/src/packet/skesk.rs374
-rw-r--r--openpgp/src/packet/tag.rs9
-rw-r--r--openpgp/src/packet/unknown.rs1
-rw-r--r--openpgp/src/parse.rs197
-rw-r--r--openpgp/src/parse/stream.rs75
-rw-r--r--openpgp/src/serialize.rs164
-rw-r--r--openpgp/src/serialize/stream.rs32
-rw-r--r--openpgp/tests/data/crypto-refresh/v6skesk-aes128-eax.pgp7
-rw-r--r--openpgp/tests/data/crypto-refresh/v6skesk-aes128-gcm.pgp7
-rw-r--r--openpgp/tests/data/crypto-refresh/v6skesk-aes128-ocb.pgp7
23 files changed, 986 insertions, 334 deletions
diff --git a/openpgp/src/cert/parser/mod.rs b/openpgp/src/cert/parser/mod.rs
index d376c0c1..aea9c101 100644
--- a/openpgp/src/cert/parser/mod.rs
+++ b/openpgp/src/cert/parser/mod.rs
@@ -757,11 +757,19 @@ impl<'a> CertParser<'a> {
// returns None.
fn parse(&mut self, p: Packet) -> Result<Option<Cert>> {
tracer!(TRACE, "CertParser::parse", 0);
- if let Packet::Marker(_) = p {
- // Ignore Marker Packet. RFC4880, section 5.8:
- //
- // Such a packet MUST be ignored when received.
- return Ok(None);
+ match p {
+ Packet::Marker(_) => {
+ // Ignore Marker Packet. RFC4880, section 5.8:
+ //
+ // Such a packet MUST be ignored when received.
+ return Ok(None);
+ },
+ Packet::Padding(_) => {
+ // "[Padding packets] MUST be ignored when received.",
+ // section 5.15 of RFC XXXX.
+ return Ok(None);
+ },
+ _ => {},
}
if !self.packets.is_empty() {
diff --git a/openpgp/src/crypto/aead.rs b/openpgp/src/crypto/aead.rs
index b6fcc578..dd0f8ed5 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 ec715380..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,
@@ -214,6 +215,11 @@ impl MessageValidator {
// section 5.8 of RFC4880.
return;
},
+ Tag::Padding => {
+ // "[Padding packets] MUST be ignored when received.",
+ // section 5.15 of RFC XXXX.
+ return;
+ },
_ => {
// Unknown token.
self.error = Some(MessageParserError::OpenPGP(
diff --git a/openpgp/src/packet/any.rs b/openpgp/src/packet/any.rs
index 8af73eaf..3238bf86 100644
--- a/openpgp/src/packet/any.rs
+++ b/openpgp/src/packet/any.rs
@@ -22,6 +22,7 @@ use crate::packet::{
SEIP,
MDC,
AED,
+ Padding,
};
/// Convenient downcasting from Packets to Packet Bodies.
@@ -136,6 +137,7 @@ impl_downcasts!(
SEIP,
MDC,
AED,
+ Padding,
);
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/header/mod.rs b/openpgp/src/packet/header/mod.rs
index 61eab916..df4b9785 100644
--- a/openpgp/src/packet/header/mod.rs
+++ b/openpgp/src/packet/header/mod.rs
@@ -207,6 +207,7 @@ impl Header {
Tag::Marker => l == 3,
Tag::Reserved => true,
+ Tag::Padding => true,
};
if ! valid {
diff --git a/openpgp/src/packet/mod.rs b/openpgp/src/packet/mod.rs
index f448e39b..c004155a 100644
--- a/openpgp/src/packet/mod.rs
+++ b/openpgp/src/packet/mod.rs
@@ -217,6 +217,8 @@ pub mod pkesk;
mod mdc;
pub use self::mdc::MDC;
pub mod aed;
+mod padding;
+pub use self::padding::Padding;
/// Enumeration of packet types.
///
@@ -285,6 +287,8 @@ pub enum Packet {
MDC(MDC),
/// AEAD Encrypted Data Packet.
AED(AED),
+ /// Padding packet.
+ Padding(Padding),
}
assert_send_and_sync!(Packet);
@@ -360,6 +364,7 @@ impl Packet {
Packet::SEIP(_) => Tag::SEIP,
Packet::MDC(_) => Tag::MDC,
Packet::AED(_) => Tag::AED,
+ Packet::Padding(_) => Tag::Padding,
}
}
@@ -402,6 +407,7 @@ impl Packet {
Packet::SEIP(p) => Some(p.version()),
Packet::MDC(_) => None,
Packet::AED(p) => Some(p.version()),
+ Packet::Padding(_) => None,
}
}
@@ -443,6 +449,7 @@ impl Packet {
Packet::MDC(x) => Hash::hash(&x, state),
Packet::AED(x) => Hash::hash(&x, state),
Packet::Unknown(x) => Hash::hash(&x, state),
+ Packet::Padding(x) => Padding::hash(x, state),
}
}
}
@@ -469,10 +476,12 @@ 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::SEIP(ref packet) => &packet.common,
+ Packet::SKESK(SKESK::V6(ref packet)) => &packet.skesk4.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,
}
}
}
@@ -496,10 +505,12 @@ 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::SEIP(ref mut packet) => &mut packet.common,
+ Packet::SKESK(SKESK::V6(ref mut packet)) => &mut packet.skesk4.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,
}
}
}
@@ -527,6 +538,7 @@ impl fmt::Debug for Packet {
SEIP(v) => write!(f, "SEIP({:?})", v),
MDC(v) => write!(f, "MDC({:?})", v),
AED(v) => write!(f, "AED({:?})", v),
+ Padding(v) => write!(f, "Padding({:?})", v),
}
}
@@ -553,7 +565,7 @@ impl Arbitrary for Packet {
fn arbitrary(g: &mut Gen) -> Self {
use crate::arbitrary_helper::gen_arbitrary_from_range;
- match gen_arbitrary_from_range(0..15, g) {
+ match gen_arbitrary_from_range(0..16, g) {
0 => Signature::arbitrary(g).into(),
1 => OnePassSig::arbitrary(g).into(),
2 => Key::<key::PublicParts, key::UnspecifiedRole>::arbitrary(g)
@@ -572,7 +584,8 @@ impl Arbitrary for Packet {
11 => CompressedData::arbitrary(g).into(),
12 => PKESK::arbitrary(g).into(),
13 => SKESK::arbitrary(g).into(),
- 14 => loop {
+ 14 => Padding::arbitrary(g).into(),
+ 15 => loop {
let mut u = Unknown::new(
Tag::arbitrary(g), anyhow::anyhow!("Arbitrary::arbitrary"));
u.set_body(Arbitrary::arbitrary(g));
@@ -1233,10 +1246,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);
@@ -1245,7 +1258,7 @@ impl SKESK {
pub fn version(&self) -> u8 {
match self {
SKESK::V4(_) => 4,
- SKESK::V5(_) => 5,
+ SKESK::V6(_) => 6,
}
}
}
@@ -2057,6 +2070,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);
@@ -2065,6 +2081,7 @@ impl SEIP {
pub fn version(&self) -> u8 {
match self {
SEIP::V1(_) => 1,
+ SEIP::V2(_) => 2,
}
}
}
@@ -2075,26 +2092,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/padding.rs b/openpgp/src/packet/padding.rs
new file mode 100644
index 00000000..6b7fab5f
--- /dev/null
+++ b/openpgp/src/packet/padding.rs
@@ -0,0 +1,92 @@
+use std::fmt;
+
+#[cfg(test)]
+use quickcheck::{Arbitrary, Gen};
+
+use crate::packet;
+use crate::Packet;
+
+/// Holds a Padding packet.
+///
+/// Padding packets are used to obscure the size of cryptographic
+/// artifacts.
+///
+/// See [Section 5.15 of RFC XXX] for details.
+///
+/// [Section 5.15 of RFC XXX]: https://openpgp-wg.gitlab.io/rfc4880bis/#name-padding-packet-tag-21
+// IMPORTANT: If you add fields to this struct, you need to explicitly
+// IMPORTANT: implement PartialEq, Eq, and Hash.
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct Padding {
+ pub(crate) common: packet::Common,
+ value: Vec<u8>,
+}
+
+assert_send_and_sync!(Padding);
+
+impl From<Vec<u8>> for Padding {
+ fn from(u: Vec<u8>) -> Self {
+ Padding {
+ common: Default::default(),
+ value: u,
+ }
+ }
+}
+
+impl fmt::Display for Padding {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let padding = String::from_utf8_lossy(&self.value[..]);
+ write!(f, "{}", padding)
+ }
+}
+
+impl fmt::Debug for Padding {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Padding {{ {} bytes }}", self.value.len())
+ }
+}
+
+impl Padding {
+ /// Creates a new Padding packet of the given size.
+ ///
+ /// Note that this is the net size, packet framing (CTB and packet
+ /// length) will come on top.
+ pub fn new(size: usize) -> Padding {
+ let mut v = vec![0; size];
+ crate::crypto::random(&mut v);
+ v.into()
+ }
+
+ /// Gets the padding packet's value.
+ pub(crate) fn value(&self) -> &[u8] {
+ self.value.as_slice()
+ }
+}
+
+impl From<Padding> for Packet {
+ fn from(s: Padding) -> Self {
+ Packet::Padding(s)
+ }
+}
+
+#[cfg(test)]
+impl Arbitrary for Padding {
+ fn arbitrary(g: &mut Gen) -> Self {
+ Vec::<u8>::arbitrary(g).into()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::parse::Parse;
+ use crate::serialize::MarshalInto;
+
+ quickcheck! {
+ fn roundtrip(p: Padding) -> bool {
+ let q = Padding::from_bytes(&p.to_vec().unwrap()).unwrap();
+ assert_eq!(p, q);
+ true
+ }
+ }
+}
diff --git a/openpgp/src/packet/prelude.rs b/openpgp/src/packet/prelude.rs
index c433dda9..bda7a7e2 100644
--- a/openpgp/src/packet/prelude.rs
+++ b/openpgp/src/packet/prelude.rs
@@ -34,6 +34,7 @@ pub use crate::packet::{
OnePassSig,
PKESK,
Packet,
+ Padding,
SEIP,
SKESK,
Signature,
@@ -50,12 +51,15 @@ pub use crate::packet::{
one_pass_sig::OnePassSig3,
one_pass_sig::OnePassSig6,
pkesk::PKESK3,
- seip::SEIP1,
+ seip::{
+ SEIP1,
+ SEIP2,
+ },
signature,
signature::Signature4,
signature::Signature6,
signature::SignatureBuilder,
skesk::SKESK4,
- skesk::SKESK5,
+ skesk::SKESK6,
user_attribute,
};
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 {