pub mod compressed_data;
pub mod fingerprint;
pub mod literal_data;
pub mod mdc;
pub mod misc;
pub mod one_pass_signature;
pub mod pkesk;
pub mod public_key;
pub mod secret_key;
pub mod seipd;
pub mod signature;
pub mod skesk;
pub mod subpackets;
pub mod tags;
pub mod user_attribute;
pub mod user_id;
use std::sync::Arc;
use crate::error::{Error, Result};
use crate::stream::ByteStream;
use tags::PacketTag;
#[derive(Debug, Clone)]
pub struct Field {
pub name: Arc<str>,
pub value: Arc<str>,
pub indent: u8,
pub span: (usize, usize),
}
impl Field {
pub fn new(
name: impl Into<Arc<str>>,
value: impl Into<Arc<str>>,
indent: u8,
span: (usize, usize),
) -> Self {
Self {
name: name.into(),
value: value.into(),
indent,
span,
}
}
pub fn packet(
name: impl Into<Arc<str>>,
value: impl Into<Arc<str>>,
span: (usize, usize),
) -> Self {
Self::new(name, value, 0, span)
}
#[allow(clippy::self_named_constructors)]
pub fn field(
name: impl Into<Arc<str>>,
value: impl Into<Arc<str>>,
span: (usize, usize),
) -> Self {
Self::new(name, value, 1, span)
}
pub fn subfield(
name: impl Into<Arc<str>>,
value: impl Into<Arc<str>>,
span: (usize, usize),
) -> Self {
Self::new(name, value, 2, span)
}
}
#[derive(Debug, Clone)]
pub struct Packet {
pub start: usize,
pub end: usize,
pub tag: PacketTag,
pub body: PacketBody,
pub fields: Vec<Field>,
pub children: Vec<Packet>,
pub child_buffer: Option<Arc<[u8]>>,
}
impl Packet {
pub fn new(
start: usize,
end: usize,
tag: PacketTag,
body: PacketBody,
fields: Vec<Field>,
) -> Self {
Self {
start,
end,
tag,
body,
fields,
children: Vec::new(),
child_buffer: None,
}
}
}
#[derive(Debug, Clone)]
pub enum PacketBody {
Pkesk(pkesk::PkeskPacket),
Signature(signature::SignaturePacket),
Skesk(skesk::SkeskPacket),
OnePassSignature(one_pass_signature::OnePassSignaturePacket),
SecretKey(secret_key::SecretKeyPacket),
PublicKey(public_key::PublicKeyPacket),
SecretSubkey(secret_key::SecretKeyPacket),
CompressedData(compressed_data::CompressedDataPacket),
SymmetricallyEncryptedData(misc::SymmetricallyEncryptedDataPacket),
Marker(misc::MarkerPacket),
LiteralData(literal_data::LiteralDataPacket),
UserId(user_id::UserIdPacket),
PublicSubkey(public_key::PublicKeyPacket),
UserAttribute(user_attribute::UserAttributePacket),
Seipd(seipd::SeipdPacket),
Mdc(mdc::MdcPacket),
AeadEncryptedData(misc::AeadEncryptedDataPacket),
Padding(misc::PaddingPacket),
Unknown(Vec<u8>),
}
pub fn parse_packets(bytes: Arc<[u8]>) -> Result<Vec<Packet>> {
parse_packets_at_depth(bytes, 0)
}
#[cfg(feature = "decompress")]
const MAX_DEPTH: usize = 4;
fn parse_packets_at_depth(bytes: Arc<[u8]>, depth: usize) -> Result<Vec<Packet>> {
let mut stream = ByteStream::from_arc(bytes);
let mut packets = Vec::new();
while !stream.is_empty() {
let packet = parse_packet(&mut stream, depth)?;
packets.push(packet);
}
Ok(packets)
}
fn parse_packet(stream: &mut ByteStream, depth: usize) -> Result<Packet> {
let packet_start = stream.abs_pos();
let mut fields = Vec::new();
let header_start = stream.abs_pos();
let header_byte = stream.octet()?;
if header_byte & 0x80 == 0 {
return Err(Error::InvalidPacketHeader(packet_start));
}
let new_format = header_byte & 0x40 != 0;
let (tag, body_length) = if new_format {
let tag = PacketTag::from_u8(header_byte & 0x3F);
let len = parse_new_length(stream)?;
(tag, len)
} else {
let tag = PacketTag::from_u8((header_byte >> 2) & 0x0F);
let len_type = header_byte & 0x03;
let len = parse_old_length(stream, len_type)?;
(tag, len)
};
let header_end = stream.abs_pos();
let packet_name: Arc<str> = format!("Packet: {}", tag).into();
fields.push(Field::packet(
packet_name,
format!("{} bytes", body_length),
(header_start, header_end),
));
let body_start = stream.abs_pos();
let mut body_stream = stream.slice(stream.pos(), stream.pos() + body_length);
stream.skip(body_length)?;
let packet_end = stream.abs_pos();
let body = parse_packet_body(tag, &mut body_stream, &mut fields, body_start)?;
let mut children = Vec::new();
let mut child_buffer = None;
if let PacketBody::CompressedData(ref cd) = body {
expand_compressed(
cd,
depth,
&mut fields,
&mut children,
&mut child_buffer,
(body_start, packet_end),
);
}
Ok(Packet {
start: packet_start,
end: packet_end,
tag,
body,
fields,
children,
child_buffer,
})
}
#[cfg(feature = "decompress")]
fn expand_compressed(
cd: &compressed_data::CompressedDataPacket,
depth: usize,
fields: &mut Vec<Field>,
children: &mut Vec<Packet>,
child_buffer: &mut Option<Arc<[u8]>>,
span: (usize, usize),
) {
if depth >= MAX_DEPTH {
fields.push(Field::field(
"Decompressed",
"max nesting depth reached; not expanded",
span,
));
return;
}
match compressed_data::decompress(cd.algorithm, &cd.compressed_data) {
Ok(buf) => {
let buf: Arc<[u8]> = buf.into();
match parse_packets_at_depth(Arc::clone(&buf), depth + 1) {
Ok(packets) => {
fields.push(Field::field(
"Decompressed",
format!("{} bytes, {} packets", buf.len(), packets.len()),
span,
));
*children = packets;
*child_buffer = Some(buf);
}
Err(e) => {
fields.push(Field::field("Decompressed", format!("error: {}", e), span));
}
}
}
Err(msg) => {
fields.push(Field::field(
"Decompressed",
format!("error: {}", msg),
span,
));
}
}
}
#[cfg(not(feature = "decompress"))]
fn expand_compressed(
_cd: &compressed_data::CompressedDataPacket,
_depth: usize,
_fields: &mut Vec<Field>,
_children: &mut Vec<Packet>,
_child_buffer: &mut Option<Arc<[u8]>>,
_span: (usize, usize),
) {
}
fn parse_new_length(stream: &mut ByteStream) -> Result<usize> {
let first = stream.octet()? as usize;
if first < 192 {
Ok(first)
} else if first < 224 {
let second = stream.octet()? as usize;
Ok(((first - 192) << 8) + second + 192)
} else if first == 255 {
Ok(stream.uint32()? as usize)
} else {
Ok(1 << (first & 0x1F))
}
}
fn parse_old_length(stream: &mut ByteStream, len_type: u8) -> Result<usize> {
match len_type {
0 => Ok(stream.octet()? as usize),
1 => Ok(stream.uint16()? as usize),
2 => Ok(stream.uint32()? as usize),
3 => Ok(stream.remaining()),
_ => unreachable!(),
}
}
fn parse_packet_body(
tag: PacketTag,
stream: &mut ByteStream,
fields: &mut Vec<Field>,
body_offset: usize,
) -> Result<PacketBody> {
match tag {
PacketTag::PublicKeyEncryptedSessionKey => {
let pkesk = pkesk::parse_pkesk(stream, fields, body_offset)?;
Ok(PacketBody::Pkesk(pkesk))
}
PacketTag::Signature => {
let sig = signature::parse_signature(stream, fields, body_offset)?;
Ok(PacketBody::Signature(sig))
}
PacketTag::SymmetricKeyEncryptedSessionKey => {
let skesk = skesk::parse_skesk(stream, fields, body_offset)?;
Ok(PacketBody::Skesk(skesk))
}
PacketTag::OnePassSignature => {
let ops = one_pass_signature::parse_one_pass_signature(stream, fields, body_offset)?;
Ok(PacketBody::OnePassSignature(ops))
}
PacketTag::SecretKey => {
let sk = secret_key::parse_secret_key(stream, fields, body_offset)?;
Ok(PacketBody::SecretKey(sk))
}
PacketTag::PublicKey => {
let pk = public_key::parse_public_key(stream, fields, body_offset)?;
Ok(PacketBody::PublicKey(pk))
}
PacketTag::SecretSubkey => {
let sk = secret_key::parse_secret_key(stream, fields, body_offset)?;
Ok(PacketBody::SecretSubkey(sk))
}
PacketTag::CompressedData => {
let cd = compressed_data::parse_compressed_data(stream, fields, body_offset)?;
Ok(PacketBody::CompressedData(cd))
}
PacketTag::SymmetricallyEncryptedData => {
let sed = misc::parse_symmetrically_encrypted_data(stream, fields, body_offset)?;
Ok(PacketBody::SymmetricallyEncryptedData(sed))
}
PacketTag::Marker => {
let marker = misc::parse_marker(stream, fields, body_offset)?;
Ok(PacketBody::Marker(marker))
}
PacketTag::LiteralData => {
let ld = literal_data::parse_literal_data(stream, fields, body_offset)?;
Ok(PacketBody::LiteralData(ld))
}
PacketTag::UserId => {
let uid = user_id::parse_user_id(stream, fields, body_offset)?;
Ok(PacketBody::UserId(uid))
}
PacketTag::PublicSubkey => {
let pk = public_key::parse_public_key(stream, fields, body_offset)?;
Ok(PacketBody::PublicSubkey(pk))
}
PacketTag::UserAttribute => {
let ua = user_attribute::parse_user_attribute(stream, fields, body_offset)?;
Ok(PacketBody::UserAttribute(ua))
}
PacketTag::SymmetricallyEncryptedIntegrityProtectedData => {
let seipd = seipd::parse_seipd(stream, fields, body_offset)?;
Ok(PacketBody::Seipd(seipd))
}
PacketTag::ModificationDetectionCode => {
let mdc = mdc::parse_mdc(stream, fields, body_offset)?;
Ok(PacketBody::Mdc(mdc))
}
PacketTag::AeadEncryptedData => {
let aead = misc::parse_aead_encrypted_data(stream, fields, body_offset)?;
Ok(PacketBody::AeadEncryptedData(aead))
}
PacketTag::Padding => {
let padding = misc::parse_padding(stream, fields, body_offset)?;
Ok(PacketBody::Padding(padding))
}
_ => {
let data = stream.rest();
if !data.is_empty() {
let data_start = body_offset + stream.pos() - data.len();
let data_end = body_offset + stream.pos();
fields.push(Field::field(
"Data",
format!("{} bytes", data.len()),
(data_start, data_end),
));
}
Ok(PacketBody::Unknown(data))
}
}
}