use std::io;
use byteorder::{BigEndian, WriteBytesExt};
use crate::errors::Result;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Packet {
pub version: Version,
pub tag: Tag,
pub body: Vec<u8>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum PacketLength {
Fixed(usize),
Indeterminated,
Partial(usize),
}
impl From<usize> for PacketLength {
fn from(val: usize) -> PacketLength {
PacketLength::Fixed(val)
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)]
#[repr(u8)]
pub enum Tag {
PublicKeyEncryptedSessionKey = 1,
Signature = 2,
SymKeyEncryptedSessionKey = 3,
OnePassSignature = 4,
SecretKey = 5,
PublicKey = 6,
SecretSubkey = 7,
CompressedData = 8,
SymEncryptedData = 9,
Marker = 10,
LiteralData = 11,
Trust = 12,
UserId = 13,
PublicSubkey = 14,
UserAttribute = 17,
SymEncryptedProtectedData = 18,
ModDetectionCode = 19,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)]
#[repr(u8)]
#[derive(Default)]
pub enum Version {
Old = 0,
#[default]
New = 1,
}
impl Version {
pub fn write_header(self, writer: &mut impl io::Write, tag: u8, len: usize) -> Result<()> {
debug!("write_header {:?} {} {}", self, tag, len);
match self {
Version::Old => {
if len < 256 {
writer.write_all(&[0b1000_0000 | tag << 2, len as u8])?;
} else if len < 65536 {
writer.write_all(&[0b1000_0001 | tag << 2])?;
writer.write_u16::<BigEndian>(len as u16)?;
} else {
writer.write_all(&[0b1000_0010 | tag << 2])?;
writer.write_u32::<BigEndian>(len as u32)?;
}
}
Version::New => {
writer.write_all(&[0b1100_0000 | tag])?;
if len < 192 {
writer.write_all(&[len as u8])?;
} else if len < 8384 {
writer.write_all(&[
(((len - 192) >> 8) + 192) as u8,
((len - 192) & 0xFF) as u8,
])?;
} else {
writer.write_all(&[255])?;
writer.write_u32::<BigEndian>(len as u32)?;
}
}
}
Ok(())
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)]
#[repr(u8)]
#[derive(Default)]
pub enum KeyVersion {
V2 = 2,
V3 = 3,
#[default]
V4 = 4,
V5 = 5,
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
#[test]
fn test_write_header() {
let mut buf = Vec::new();
Version::New
.write_header(&mut buf, Tag::UserAttribute as u8, 12875)
.unwrap();
assert_eq!(hex::encode(buf), "d1ff0000324b");
let mut buf = Vec::new();
Version::New
.write_header(&mut buf, Tag::Signature as u8, 302)
.unwrap();
assert_eq!(hex::encode(buf), "c2c06e");
let mut buf = Vec::new();
Version::New
.write_header(&mut buf, Tag::Signature as u8, 303)
.unwrap();
assert_eq!(hex::encode(buf), "c2c06f");
}
}