use std::fmt;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
#[cfg(test)]
use quickcheck::{Arbitrary, Gen};
use crate::packet::Packet;
#[derive(Clone, Copy, Debug)]
pub enum Tag {
Reserved,
PKESK,
Signature,
SKESK,
OnePassSig,
SecretKey,
PublicKey,
SecretSubkey,
CompressedData,
SED,
Marker,
Literal,
Trust,
UserID,
PublicSubkey,
UserAttribute,
SEIP,
MDC,
AED,
Unknown(u8),
Private(u8),
}
impl Eq for Tag {}
impl PartialEq for Tag {
fn eq(&self, other: &Tag) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl PartialOrd for Tag
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Tag
{
fn cmp(&self, other: &Self) -> Ordering {
let a : u8 = (*self).into();
let b : u8 = (*other).into();
a.cmp(&b)
}
}
impl Hash for Tag {
fn hash<H: Hasher>(&self, state: &mut H) {
let t: u8 = (*self).into();
t.hash(state);
}
}
impl From<u8> for Tag {
fn from(u: u8) -> Self {
use crate::packet::Tag::*;
match u {
0 => Reserved,
1 => PKESK,
2 => Signature,
3 => SKESK,
4 => OnePassSig,
5 => SecretKey,
6 => PublicKey,
7 => SecretSubkey,
8 => CompressedData,
9 => SED,
10 => Marker,
11 => Literal,
12 => Trust,
13 => UserID,
14 => PublicSubkey,
17 => UserAttribute,
18 => SEIP,
19 => MDC,
20 => AED,
60..=63 => Private(u),
_ => Unknown(u),
}
}
}
impl From<Tag> for u8 {
fn from(t: Tag) -> u8 {
(&t).into()
}
}
impl From<&Tag> for u8 {
fn from(t: &Tag) -> u8 {
match t {
&Tag::Reserved => 0,
&Tag::PKESK => 1,
&Tag::Signature => 2,
&Tag::SKESK => 3,
&Tag::OnePassSig => 4,
&Tag::SecretKey => 5,
&Tag::PublicKey => 6,
&Tag::SecretSubkey => 7,
&Tag::CompressedData => 8,
&Tag::SED => 9,
&Tag::Marker => 10,
&Tag::Literal => 11,
&Tag::Trust => 12,
&Tag::UserID => 13,
&Tag::PublicSubkey => 14,
&Tag::UserAttribute => 17,
&Tag::SEIP => 18,
&Tag::MDC => 19,
&Tag::AED => 20,
&Tag::Private(x) => x,
&Tag::Unknown(x) => x,
}
}
}
impl From<&Packet> for Tag {
fn from(p: &Packet) -> Tag {
p.tag()
}
}
impl From<Packet> for Tag {
fn from(p: Packet) -> Tag {
p.tag()
}
}
impl fmt::Display for Tag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Tag::Reserved =>
f.write_str("Reserved - a packet tag MUST NOT have this value"),
Tag::PKESK =>
f.write_str("Public-Key Encrypted Session Key Packet"),
Tag::Signature =>
f.write_str("Signature Packet"),
Tag::SKESK =>
f.write_str("Symmetric-Key Encrypted Session Key Packet"),
Tag::OnePassSig =>
f.write_str("One-Pass Signature Packet"),
Tag::SecretKey =>
f.write_str("Secret-Key Packet"),
Tag::PublicKey =>
f.write_str("Public-Key Packet"),
Tag::SecretSubkey =>
f.write_str("Secret-Subkey Packet"),
Tag::CompressedData =>
f.write_str("Compressed Data Packet"),
Tag::SED =>
f.write_str("Symmetrically Encrypted Data Packet"),
Tag::Marker =>
f.write_str("Marker Packet"),
Tag::Literal =>
f.write_str("Literal Data Packet"),
Tag::Trust =>
f.write_str("Trust Packet"),
Tag::UserID =>
f.write_str("User ID Packet"),
Tag::PublicSubkey =>
f.write_str("Public-Subkey Packet"),
Tag::UserAttribute =>
f.write_str("User Attribute Packet"),
Tag::SEIP =>
f.write_str("Sym. Encrypted and Integrity Protected Data Packet"),
Tag::MDC =>
f.write_str("Modification Detection Code Packet"),
Tag::AED =>
f.write_str("AEAD Encrypted Data Packet"),
Tag::Private(u) =>
f.write_fmt(format_args!("Private/Experimental Packet {}", u)),
Tag::Unknown(u) =>
f.write_fmt(format_args!("Unknown Packet {}", u)),
}
}
}
#[cfg(test)]
impl Arbitrary for Tag {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
u8::arbitrary(g).into()
}
}
impl Tag {
pub fn valid_start_of_message(&self) -> bool {
*self == Tag::PublicKey || *self == Tag::SecretKey
|| *self == Tag::PKESK || *self == Tag::SKESK
|| *self == Tag::Literal || *self == Tag::CompressedData
|| *self == Tag::OnePassSig
|| *self == Tag::Signature
}
}
#[cfg(test)]
mod tests {
use super::*;
quickcheck! {
fn roundtrip(tag: Tag) -> bool {
let val: u8 = tag.into();
tag == Tag::from(val)
}
}
quickcheck! {
fn display(tag: Tag) -> bool {
let s = format!("{}", tag);
!s.is_empty()
}
}
quickcheck! {
fn unknown_private(tag: Tag) -> bool {
match tag {
Tag::Unknown(u) => u > 19 || u == 15 || u == 16,
Tag::Private(u) => u >= 60 && u <= 63,
_ => true
}
}
}
#[test]
fn parse() {
for i in 0..0x100usize {
Tag::from(i as u8);
}
}
}