use crate::error::Result;
use crate::lookup::{lookup_aead_algorithm, lookup_symmetric_algorithm};
use crate::stream::ByteStream;
use super::Field;
#[derive(Debug, Clone)]
pub struct MarkerPacket {
pub valid: bool,
}
pub fn parse_marker(
stream: &mut ByteStream,
fields: &mut Vec<Field>,
body_offset: usize,
) -> Result<MarkerPacket> {
let marker_start = body_offset + stream.pos();
let data = stream.rest();
let valid = data == [0x50, 0x47, 0x50]; let status = if valid {
"PGP (valid)"
} else if data.len() == 3 {
"Invalid marker"
} else {
"Invalid length"
};
fields.push(Field::field(
"Marker",
status,
(marker_start, marker_start + data.len()),
));
Ok(MarkerPacket { valid })
}
#[derive(Debug, Clone)]
pub struct SymmetricallyEncryptedDataPacket {
pub encrypted_data: Vec<u8>,
}
pub fn parse_symmetrically_encrypted_data(
stream: &mut ByteStream,
fields: &mut Vec<Field>,
body_offset: usize,
) -> Result<SymmetricallyEncryptedDataPacket> {
let data_start = body_offset + stream.pos();
let encrypted_data = stream.rest();
let data_end = body_offset + stream.pos();
fields.push(Field::field(
"Encrypted Data",
format!("{} bytes (legacy CFB, no MDC)", encrypted_data.len()),
(data_start, data_end),
));
Ok(SymmetricallyEncryptedDataPacket { encrypted_data })
}
#[derive(Debug, Clone)]
pub struct AeadEncryptedDataPacket {
pub version: u8,
pub cipher_algorithm: u8,
pub aead_algorithm: u8,
pub chunk_size: u8,
pub iv: Vec<u8>,
pub encrypted_data: Vec<u8>,
}
pub fn parse_aead_encrypted_data(
stream: &mut ByteStream,
fields: &mut Vec<Field>,
body_offset: usize,
) -> Result<AeadEncryptedDataPacket> {
let version_start = body_offset + stream.pos();
let version = stream.octet()?;
fields.push(Field::field(
"Version",
version.to_string(),
(version_start, version_start + 1),
));
let cipher_start = body_offset + stream.pos();
let cipher_algorithm = stream.octet()?;
let cipher_lookup = lookup_symmetric_algorithm(cipher_algorithm);
fields.push(Field::field(
"Cipher Algorithm",
cipher_lookup.display(),
(cipher_start, cipher_start + 1),
));
let aead_start = body_offset + stream.pos();
let aead_algorithm = stream.octet()?;
let aead_lookup = lookup_aead_algorithm(aead_algorithm);
fields.push(Field::field(
"AEAD Algorithm",
aead_lookup.display(),
(aead_start, aead_start + 1),
));
let chunk_start = body_offset + stream.pos();
let chunk_size = stream.octet()?;
let chunk_bytes = 1u64 << (chunk_size + 6);
fields.push(Field::field(
"Chunk Size",
format!("{} bytes (2^{})", chunk_bytes, chunk_size + 6),
(chunk_start, chunk_start + 1),
));
let iv_len = match aead_algorithm {
1 => 16, 2 => 15, 3 => 12, _ => 16, };
let iv_start = body_offset + stream.pos();
let iv = stream.bytes(iv_len)?;
let iv_hex: String = iv.iter().map(|b| format!("{:02X}", b)).collect();
fields.push(Field::field(
"IV/Nonce",
iv_hex,
(iv_start, iv_start + iv_len),
));
let data_start = body_offset + stream.pos();
let encrypted_data = stream.rest();
let data_end = body_offset + stream.pos();
if !encrypted_data.is_empty() {
fields.push(Field::field(
"Encrypted Data",
format!("{} bytes (with auth tags)", encrypted_data.len()),
(data_start, data_end),
));
}
Ok(AeadEncryptedDataPacket {
version,
cipher_algorithm,
aead_algorithm,
chunk_size,
iv,
encrypted_data,
})
}
#[derive(Debug, Clone)]
pub struct PaddingPacket {
pub padding: Vec<u8>,
}
pub fn parse_padding(
stream: &mut ByteStream,
fields: &mut Vec<Field>,
body_offset: usize,
) -> Result<PaddingPacket> {
let padding_start = body_offset + stream.pos();
let padding = stream.rest();
let padding_end = body_offset + stream.pos();
fields.push(Field::field(
"Padding",
format!("{} bytes", padding.len()),
(padding_start, padding_end),
));
Ok(PaddingPacket { padding })
}