use std::io::{self, Write};
use std::cmp;
use super::*;
mod partial_body;
use self::partial_body::PartialBodyFilter;
pub mod writer;
pub mod stream;
use crypto::s2k::S2K;
use packet::signature::subpacket::{
Subpacket, SubpacketValue, SubpacketLengthTrait,
};
use conversions::{
Time,
Duration,
};
use packet::{
Tag,
Unknown,
Signature,
OnePassSig,
Key,
key::SecretKey,
UserID,
UserAttribute,
Literal,
CompressedData,
PKESK,
SKESK,
SKESK4,
SKESK5,
SEIP,
MDC,
AED,
};
const TRACE : bool = false;
#[cfg(test)]
use std::path::PathBuf;
#[cfg(test)]
fn path_to(artifact: &str) -> PathBuf {
[env!("CARGO_MANIFEST_DIR"), "tests", "data", "messages", artifact]
.iter().collect()
}
pub trait Serialize {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()>;
}
pub trait SerializeKey {
fn serialize<W: io::Write>(&self, o: &mut W, tag: Tag) -> Result<()>;
}
pub trait SerializeInto {
fn serialized_len(&self) -> usize;
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize>;
fn to_vec(&self) -> Result<Vec<u8>> {
let mut o = vec![0; self.serialized_len()];
let len = self.serialize_into(&mut o[..])?;
o.truncate(len);
o.shrink_to_fit();
Ok(o)
}
}
trait NetLength {
fn net_len(&self) -> usize;
fn gross_len(&self) -> usize {
let net = self.net_len();
1 + BodyLength::Full(net as u32).serialized_len()
+ net
}
}
pub trait SerializeKeyInto {
fn serialized_len(&self, tag: Tag) -> usize;
fn serialize_into(&self, buf: &mut [u8], tag: Tag) -> Result<usize>;
fn to_vec(&self, tag: Tag) -> Result<Vec<u8>> {
let mut o = vec![0; self.serialized_len(tag)];
let len = self.serialize_into(&mut o[..], tag)?;
o.truncate(len);
o.shrink_to_fit();
Ok(o)
}
}
fn generic_serialize_into<T: Serialize + SerializeInto>(o: &T, buf: &mut [u8])
-> Result<usize> {
if buf.len() < o.serialized_len() {
return Err(Error::InvalidArgument(
format!("Invalid buffer size, expected {}, got {}",
o.serialized_len(), buf.len())).into());
}
let mut cursor = ::std::io::Cursor::new(buf);
o.serialize(&mut cursor)?;
Ok(cursor.position() as usize)
}
fn write_byte<W: io::Write>(o: &mut W, b: u8) -> io::Result<()> {
let b : [u8; 1] = [b; 1];
o.write_all(&b[..])
}
fn write_be_u16<W: io::Write>(o: &mut W, n: u16) -> io::Result<()> {
let b : [u8; 2] = [ ((n >> 8) & 0xFF) as u8, (n & 0xFF) as u8 ];
o.write_all(&b[..])
}
fn write_be_u32<W: io::Write>(o: &mut W, n: u32) -> io::Result<()> {
let b : [u8; 4] = [ (n >> 24) as u8, ((n >> 16) & 0xFF) as u8,
((n >> 8) & 0xFF) as u8, (n & 0xFF) as u8 ];
o.write_all(&b[..])
}
fn log2(x: u32) -> usize {
if x == 0 {
0
} else {
31 - x.leading_zeros() as usize
}
}
#[test]
fn log2_test() {
for i in 0..32 {
assert_eq!(log2(1u32 << i), i);
if i > 0 {
assert_eq!(log2((1u32 << i) - 1), i - 1);
assert_eq!(log2((1u32 << i) + 1), i);
}
}
}
impl Serialize for BodyLength {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
match self {
&BodyLength::Full(l) => {
if l <= 191 {
write_byte(o, l as u8)?;
} else if l <= 8383 {
let v = l - 192;
let v = v + (192 << 8);
write_be_u16(o, v as u16)?;
} else {
write_byte(o, 0xff)?;
write_be_u32(o, l)?;
}
},
&BodyLength::Partial(l) => {
if l > 1 << 30 {
return Err(Error::InvalidArgument(
format!("Partial length too large: {}", l)).into());
}
let chunk_size_log2 = log2(l);
let chunk_size = 1 << chunk_size_log2;
if l != chunk_size {
return Err(Error::InvalidArgument(
format!("Not a power of two: {}", l)).into());
}
let size_byte = 224 + chunk_size_log2;
assert!(size_byte < 255);
write_byte(o, size_byte as u8)?;
},
&BodyLength::Indeterminate =>
return Err(Error::InvalidArgument(
"Indeterminate lengths are not support for new format packets".
into()).into()),
}
Ok(())
}
}
impl SerializeInto for BodyLength {
fn serialized_len(&self) -> usize {
match self {
&BodyLength::Full(l) => {
if l <= 191 {
1
} else if l <= 8383 {
2
} else {
5
}
},
&BodyLength::Partial(_) => 1,
&BodyLength::Indeterminate => 0,
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl BodyLength {
pub fn serialize_old<W: io::Write>(&self, o: &mut W) -> Result<()> {
let mut buffer = Vec::with_capacity(4);
match self {
&BodyLength::Full(l) => {
match l {
0 ... 0xFF =>
write_byte(&mut buffer, l as u8).unwrap(),
0x1_00 ... 0xFF_FF =>
write_be_u16(&mut buffer, l as u16).unwrap(),
_ =>
write_be_u32(&mut buffer, l as u32).unwrap(),
}
},
&BodyLength::Indeterminate => {},
&BodyLength::Partial(_) =>
return Err(Error::InvalidArgument(
"Partial body lengths are not support for old format packets".
into()).into()),
}
o.write_all(&buffer)?;
Ok(())
}
}
impl Serialize for CTBNew {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let tag: u8 = self.common.tag.into();
o.write_all(&[0b1100_0000u8 | tag])?;
Ok(())
}
}
impl SerializeInto for CTBNew {
fn serialized_len(&self) -> usize { 1 }
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for CTBOld {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let tag: u8 = self.common.tag.into();
let length_type: u8 = self.length_type.into();
o.write_all(&[0b1000_0000u8 | (tag << 2) | length_type])?;
Ok(())
}
}
impl SerializeInto for CTBOld {
fn serialized_len(&self) -> usize { 1 }
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for CTB {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
match self {
&CTB::New(ref c) => c.serialize(o),
&CTB::Old(ref c) => c.serialize(o),
}?;
Ok(())
}
}
impl SerializeInto for CTB {
fn serialized_len(&self) -> usize { 1 }
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for Header {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
self.ctb.serialize(o)?;
self.length.serialize(o)?;
Ok(())
}
}
impl Serialize for KeyID {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let raw = match self {
&KeyID::V4(ref fp) => &fp[..],
&KeyID::Invalid(ref fp) => &fp[..],
};
o.write_all(raw)?;
Ok(())
}
}
impl SerializeInto for KeyID {
fn serialized_len(&self) -> usize {
match self {
&KeyID::V4(_) => 8,
&KeyID::Invalid(ref fp) => fp.len(),
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for Fingerprint {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
o.write_all(self.as_slice())?;
Ok(())
}
}
impl SerializeInto for Fingerprint {
fn serialized_len(&self) -> usize {
match self {
Fingerprint::V4(_) => 20,
Fingerprint::Invalid(ref fp) => fp.len(),
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for crypto::mpis::MPI {
fn serialize<W: io::Write>(&self, w: &mut W) -> Result<()> {
write_be_u16(w, self.bits as u16)?;
w.write_all(&self.value)?;
Ok(())
}
}
impl SerializeInto for crypto::mpis::MPI {
fn serialized_len(&self) -> usize {
2 + self.value.len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for crypto::mpis::PublicKey {
fn serialize<W: io::Write>(&self, w: &mut W) -> Result<()> {
use crypto::mpis::PublicKey::*;
match self {
&RSA { ref e, ref n } => {
n.serialize(w)?;
e.serialize(w)?;
}
&DSA { ref p, ref q, ref g, ref y } => {
p.serialize(w)?;
q.serialize(w)?;
g.serialize(w)?;
y.serialize(w)?;
}
&Elgamal { ref p, ref g, ref y } => {
p.serialize(w)?;
g.serialize(w)?;
y.serialize(w)?;
}
&EdDSA { ref curve, ref q } => {
w.write_all(&[curve.oid().len() as u8])?;
w.write_all(curve.oid())?;
q.serialize(w)?;
}
&ECDSA { ref curve, ref q } => {
w.write_all(&[curve.oid().len() as u8])?;
w.write_all(curve.oid())?;
q.serialize(w)?;
}
&ECDH { ref curve, ref q, hash, sym } => {
w.write_all(&[curve.oid().len() as u8])?;
w.write_all(curve.oid())?;
q.serialize(w)?;
w.write_all(&[3u8, 1u8, u8::from(hash), u8::from(sym)])?;
}
&Unknown { ref mpis, ref rest } => {
for mpi in mpis.iter() {
mpi.serialize(w)?;
}
w.write_all(rest)?;
}
}
Ok(())
}
}
impl SerializeInto for crypto::mpis::PublicKey {
fn serialized_len(&self) -> usize {
use crypto::mpis::PublicKey::*;
match self {
&RSA { ref e, ref n } => {
n.serialized_len() + e.serialized_len()
}
&DSA { ref p, ref q, ref g, ref y } => {
p.serialized_len() + q.serialized_len() + g.serialized_len()
+ y.serialized_len()
}
&Elgamal { ref p, ref g, ref y } => {
p.serialized_len() + g.serialized_len() + y.serialized_len()
}
&EdDSA { ref curve, ref q } => {
1 + curve.oid().len() + q.serialized_len()
}
&ECDSA { ref curve, ref q } => {
1 + curve.oid().len() + q.serialized_len()
}
&ECDH { ref curve, ref q, hash: _, sym: _ } => {
1 + curve.oid().len() + q.serialized_len() + 4
}
&Unknown { ref mpis, ref rest } => {
mpis.iter().map(|mpi| mpi.serialized_len()).sum::<usize>()
+ rest.len()
}
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for crypto::mpis::SecretKey {
fn serialize<W: io::Write>(&self, w: &mut W) -> Result<()> {
use crypto::mpis::SecretKey::*;
match self {
&RSA{ ref d, ref p, ref q, ref u } => {
d.serialize(w)?;
p.serialize(w)?;
q.serialize(w)?;
u.serialize(w)?;
}
&DSA{ ref x } => {
x.serialize(w)?;
}
&Elgamal{ ref x } => {
x.serialize(w)?;
}
&EdDSA{ ref scalar } => {
scalar.serialize(w)?;
}
&ECDSA{ ref scalar } => {
scalar.serialize(w)?;
}
&ECDH{ ref scalar } => {
scalar.serialize(w)?;
}
&Unknown { ref mpis, ref rest } => {
for mpi in mpis.iter() {
mpi.serialize(w)?;
}
w.write_all(rest)?;
}
}
Ok(())
}
}
impl SerializeInto for crypto::mpis::SecretKey {
fn serialized_len(&self) -> usize {
use crypto::mpis::SecretKey::*;
match self {
&RSA{ ref d, ref p, ref q, ref u } => {
d.serialized_len() + p.serialized_len() + q.serialized_len()
+ u.serialized_len()
}
&DSA{ ref x } => {
x.serialized_len()
}
&Elgamal{ ref x } => {
x.serialized_len()
}
&EdDSA{ ref scalar } => {
scalar.serialized_len()
}
&ECDSA{ ref scalar } => {
scalar.serialized_len()
}
&ECDH{ ref scalar } => {
scalar.serialized_len()
}
&Unknown { ref mpis, ref rest } => {
mpis.iter().map(|mpi| mpi.serialized_len()).sum::<usize>()
+ rest.len()
}
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl crypto::mpis::SecretKey {
pub fn serialize_chksumd<W: io::Write>(&self, w: &mut W) -> Result<()> {
use nettle::Hash;
use nettle::hash::insecure_do_not_use::Sha1;
self.serialize(w)?;
let mut hash = Sha1::default();
self.serialize(&mut hash)?;
let mut digest = [0u8; 20];
hash.digest(&mut digest);
w.write_all(&digest)?;
Ok(())
}
}
impl Serialize for crypto::mpis::Ciphertext {
fn serialize<W: io::Write>(&self, w: &mut W) -> Result<()> {
use crypto::mpis::Ciphertext::*;
match self {
&RSA{ ref c } => {
c.serialize(w)?;
}
&Elgamal{ ref e, ref c } => {
e.serialize(w)?;
c.serialize(w)?;
}
&ECDH{ ref e, ref key } => {
e.serialize(w)?;
w.write_all(&[key.len() as u8])?;
w.write_all(&key)?;
}
&Unknown { ref mpis, ref rest } => {
for mpi in mpis.iter() {
mpi.serialize(w)?;
}
w.write_all(rest)?;
}
}
Ok(())
}
}
impl SerializeInto for crypto::mpis::Ciphertext {
fn serialized_len(&self) -> usize {
use crypto::mpis::Ciphertext::*;
match self {
&RSA{ ref c } => {
c.serialized_len()
}
&Elgamal{ ref e, ref c } => {
e.serialized_len() + c.serialized_len()
}
&ECDH{ ref e, ref key } => {
e.serialized_len() + 1 + key.len()
}
&Unknown { ref mpis, ref rest } => {
mpis.iter().map(|mpi| mpi.serialized_len()).sum::<usize>()
+ rest.len()
}
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for crypto::mpis::Signature {
fn serialize<W: io::Write>(&self, w: &mut W) -> Result<()> {
use crypto::mpis::Signature::*;
match self {
&RSA { ref s } => {
s.serialize(w)?;
}
&DSA { ref r, ref s } => {
r.serialize(w)?;
s.serialize(w)?;
}
&Elgamal { ref r, ref s } => {
r.serialize(w)?;
s.serialize(w)?;
}
&EdDSA { ref r, ref s } => {
r.serialize(w)?;
s.serialize(w)?;
}
&ECDSA { ref r, ref s } => {
r.serialize(w)?;
s.serialize(w)?;
}
&Unknown { ref mpis, ref rest } => {
for mpi in mpis.iter() {
mpi.serialize(w)?;
}
w.write_all(rest)?;
}
}
Ok(())
}
}
impl SerializeInto for crypto::mpis::Signature {
fn serialized_len(&self) -> usize {
use crypto::mpis::Signature::*;
match self {
&RSA { ref s } => {
s.serialized_len()
}
&DSA { ref r, ref s } => {
r.serialized_len() + s.serialized_len()
}
&Elgamal { ref r, ref s } => {
r.serialized_len() + s.serialized_len()
}
&EdDSA { ref r, ref s } => {
r.serialized_len() + s.serialized_len()
}
&ECDSA { ref r, ref s } => {
r.serialized_len() + s.serialized_len()
}
&Unknown { ref mpis, ref rest } => {
mpis.iter().map(|mpi| mpi.serialized_len()).sum::<usize>()
+ rest.len()
}
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for S2K {
fn serialize<W: io::Write>(&self, w: &mut W) -> Result<()> {
match self {
&S2K::Simple{ hash } => {
w.write_all(&[0, hash.into()])?;
}
&S2K::Salted{ hash, salt } => {
w.write_all(&[1, hash.into()])?;
w.write_all(&salt[..])?;
}
&S2K::Iterated{ hash, salt, iterations } => {
w.write_all(&[3, hash.into()])?;
w.write_all(&salt[..])?;
w.write_all(&[S2K::encode_count(iterations)?])?;
}
&S2K::Private(s2k) | &S2K::Unknown(s2k) => {
w.write_all(&[s2k])?;
}
}
Ok(())
}
}
impl SerializeInto for S2K {
fn serialized_len(&self) -> usize {
match self {
&S2K::Simple{ .. } => 2,
&S2K::Salted{ .. } => 2 + 8,
&S2K::Iterated{ .. } => 2 + 8 + 1,
&S2K::Private(_) | &S2K::Unknown(_) => 1,
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for Unknown {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let body = if let Some(ref body) = self.common.body {
&body[..]
} else {
&b""[..]
};
CTB::new(self.tag()).serialize(o)?;
BodyLength::Full(body.len() as u32).serialize(o)?;
o.write_all(&body[..])?;
Ok(())
}
}
impl SerializeInto for Unknown {
fn serialized_len(&self) -> usize {
let body = self.body().unwrap_or(&b""[..]);
1 + BodyLength::Full(body.len() as u32).serialized_len() + body.len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl<'a> Serialize for Subpacket<'a> {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let tag = u8::from(self.tag)
| if self.critical { 1 << 7 } else { 0 };
let len = 1 + self.value.len();
len.serialize(o)?;
o.write_all(&[tag])?;
self.value.serialize(o)
}
}
impl<'a> SerializeInto for Subpacket<'a> {
fn serialized_len(&self) -> usize {
(1 + self.value.len()).len() + 1 + self.value.serialized_len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl<'a> Serialize for SubpacketValue<'a> {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
use self::SubpacketValue::*;
match self {
SignatureCreationTime(t) =>
write_be_u32(o, t.to_pgp()?)?,
SignatureExpirationTime(t) =>
write_be_u32(o, t.to_pgp()?)?,
ExportableCertification(e) =>
o.write_all(&[if *e { 1 } else { 0 }])?,
TrustSignature { ref level, ref trust } =>
o.write_all(&[*level, *trust])?,
RegularExpression(ref re) => {
o.write_all(re)?;
o.write_all(&[0])?;
},
Revocable(r) =>
o.write_all(&[if *r { 1 } else { 0 }])?,
KeyExpirationTime(t) =>
write_be_u32(o, t.to_pgp()?)?,
PreferredSymmetricAlgorithms(ref p) =>
for a in p {
o.write_all(&[(*a).into()])?;
},
RevocationKey { ref class, ref pk_algo, ref fp } => {
o.write_all(&[*class, (*pk_algo).into()])?;
o.write_all(fp.as_slice())?;
},
Issuer(ref id) =>
o.write_all(id.as_slice())?,
NotationData(nd) => {
write_be_u32(o, nd.flags())?;
write_be_u16(o, nd.name().len() as u16)?;
write_be_u16(o, nd.value().len() as u16)?;
o.write_all(nd.name())?;
o.write_all(nd.value())?;
},
PreferredHashAlgorithms(ref p) =>
for a in p {
o.write_all(&[(*a).into()])?;
},
PreferredCompressionAlgorithms(ref p) =>
for a in p {
o.write_all(&[(*a).into()])?;
},
KeyServerPreferences(ref p) =>
o.write_all(&p.as_vec())?,
PreferredKeyServer(ref p) =>
o.write_all(p)?,
PrimaryUserID(p) =>
o.write_all(&[if *p { 1 } else { 0 }])?,
PolicyURI(ref p) =>
o.write_all(p)?,
KeyFlags(ref f) =>
o.write_all(&f.as_vec())?,
SignersUserID(ref uid) =>
o.write_all(uid)?,
ReasonForRevocation { ref code, ref reason } => {
o.write_all(&[(*code).into()])?;
o.write_all(reason)?;
},
Features(ref f) =>
o.write_all(&f.as_vec())?,
SignatureTarget { pk_algo, hash_algo, ref digest } => {
o.write_all(&[(*pk_algo).into(), (*hash_algo).into()])?;
o.write_all(digest)?;
},
EmbeddedSignature(ref p) => match p {
&Packet::Signature(ref sig) => sig.serialize_naked(o)?,
_ => return Err(Error::InvalidArgument(
format!("Not a signature: {:?}", p)).into()),
},
IssuerFingerprint(ref fp) => match fp {
Fingerprint::V4(_) => {
o.write_all(&[4])?;
o.write_all(fp.as_slice())?;
},
_ => return Err(Error::InvalidArgument(
"Unknown kind of fingerprint".into()).into()),
}
PreferredAEADAlgorithms(ref p) =>
for a in p {
o.write_all(&[(*a).into()])?;
},
IntendedRecipient(ref fp) => match fp {
Fingerprint::V4(_) => {
o.write_all(&[4])?;
o.write_all(fp.as_slice())?;
},
_ => return Err(Error::InvalidArgument(
"Unknown kind of fingerprint".into()).into()),
}
Unknown(ref raw) =>
o.write_all(raw)?,
Invalid(ref raw) =>
o.write_all(raw)?,
}
Ok(())
}
}
impl<'a> SerializeInto for SubpacketValue<'a> {
fn serialized_len(&self) -> usize {
use self::SubpacketValue::*;
match self {
SignatureCreationTime(_) => 4,
SignatureExpirationTime(_) => 4,
ExportableCertification(_) => 1,
TrustSignature { .. } => 2,
RegularExpression(ref re) => re.len() + 1,
Revocable(_) => 1,
KeyExpirationTime(_) => 4,
PreferredSymmetricAlgorithms(ref p) => p.len(),
RevocationKey { ref fp, .. } => 2 + fp.serialized_len(),
Issuer(ref id) => id.serialized_len(),
NotationData(nd) => 4 + 2 + 2 + nd.name().len() + nd.value().len(),
PreferredHashAlgorithms(ref p) => p.len(),
PreferredCompressionAlgorithms(ref p) => p.len(),
KeyServerPreferences(ref p) => p.as_vec().len(),
PreferredKeyServer(ref p) => p.len(),
PrimaryUserID(_) => 1,
PolicyURI(ref p) => p.len(),
KeyFlags(ref f) => f.as_vec().len(),
SignersUserID(ref uid) => uid.len(),
ReasonForRevocation { ref reason, .. } => 1 + reason.len(),
Features(ref f) => f.as_vec().len(),
SignatureTarget { ref digest, .. } => 2 + digest.len(),
EmbeddedSignature(ref p) => match p {
&Packet::Signature(ref sig) => sig.serialized_len(),
_ => 0,
},
IssuerFingerprint(ref fp) => match fp {
Fingerprint::V4(_) => 1 + fp.serialized_len(),
_ => 0,
},
PreferredAEADAlgorithms(ref p) => p.len(),
IntendedRecipient(ref fp) => match fp {
Fingerprint::V4(_) => 1 + fp.serialized_len(),
_ => 0,
},
Unknown(ref raw) => raw.len(),
Invalid(ref raw) => raw.len(),
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for Signature {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let len = self.net_len();
CTB::new(Tag::Signature).serialize(o)?;
BodyLength::Full(len as u32).serialize(o)?;
self.serialize_naked(o)
}
}
impl NetLength for Signature {
fn net_len(&self) -> usize {
1 + 1 + 1 + 1 + 2 + self.hashed_area().data.len()
+ 2 + self.unhashed_area().data.len()
+ 2 + self.mpis().serialized_len()
}
}
impl SerializeInto for Signature {
fn serialized_len(&self) -> usize {
self.gross_len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Signature {
pub(crate) fn serialize_naked<W: io::Write>(&self, o: &mut W) -> Result<()> {
if self.version() != 4 {
return Err(Error::InvalidArgument(
"Don't know how to serialize \
non-version 4 packets.".into()).into());
}
write_byte(o, self.version())?;
write_byte(o, self.sigtype().into())?;
write_byte(o, self.pk_algo().into())?;
write_byte(o, self.hash_algo().into())?;
if self.hashed_area().data.len() > std::u16::MAX as usize {
return Err(Error::InvalidArgument(
"Hashed area too large".into()).into());
}
write_be_u16(o, self.hashed_area().data.len() as u16)?;
o.write_all(&self.hashed_area().data[..])?;
if self.unhashed_area().data.len() > std::u16::MAX as usize {
return Err(Error::InvalidArgument(
"Unhashed area too large".into()).into());
}
write_be_u16(o, self.unhashed_area().data.len() as u16)?;
o.write_all(&self.unhashed_area().data[..])?;
write_byte(o, self.hash_prefix()[0])?;
write_byte(o, self.hash_prefix()[1])?;
self.mpis().serialize(o)?;
Ok(())
}
}
impl Serialize for OnePassSig {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let len = self.net_len();
CTB::new(Tag::OnePassSig).serialize(o)?;
BodyLength::Full(len as u32).serialize(o)?;
if self.version() != 3 {
return Err(Error::InvalidArgument(
"Don't know how to serialize \
non-version 3 packets.".into()).into());
}
write_byte(o, self.version())?;
write_byte(o, self.sigtype().into())?;
write_byte(o, self.hash_algo().into())?;
write_byte(o, self.pk_algo().into())?;
o.write_all(self.issuer().as_slice())?;
write_byte(o, self.last_raw())?;
Ok(())
}
}
impl NetLength for OnePassSig {
fn net_len(&self) -> usize {
1 + 1 + 1 + 1 + 8 + 1 }
}
impl SerializeInto for OnePassSig {
fn serialized_len(&self) -> usize {
self.gross_len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl SerializeKey for Key {
fn serialize<W: io::Write>(&self, o: &mut W, tag: Tag) -> Result<()> {
assert!(tag == Tag::PublicKey
|| tag == Tag::PublicSubkey
|| tag == Tag::SecretKey
|| tag == Tag::SecretSubkey);
let have_secret_key =
(tag == Tag::SecretKey || tag == Tag::SecretSubkey)
&& self.secret().is_some();
let tag = match tag {
Tag::SecretKey if ! have_secret_key => Tag::PublicKey,
Tag::SecretSubkey if ! have_secret_key => Tag::PublicSubkey,
t => t,
};
let len = self.serialized_len(tag);
CTB::new(tag).serialize(o)?;
BodyLength::Full(len as u32).serialize(o)?;
if self.version() != 4 {
return Err(Error::InvalidArgument(
"Don't know how to serialize \
non-version 4 packets.".into()).into());
}
write_byte(o, self.version())?;
write_be_u32(o, self.creation_time().to_pgp()?)?;
write_byte(o, self.pk_algo().into())?;
self.mpis().serialize(o)?;
if have_secret_key {
match self.secret().unwrap() {
&SecretKey::Unencrypted { ref mpis } => {
write_byte(o, 0)?;
let mut buf = Vec::new();
mpis.serialize(&mut buf)?;
let checksum: usize = buf.iter().map(|x| *x as usize)
.sum();
o.write_all(&buf)?;
write_be_u16(o, checksum as u16)?;
},
&SecretKey::Encrypted {
ref s2k,
algorithm,
ref ciphertext,
} => {
write_byte(o, 254)?;
write_byte(o, algorithm.into())?;
s2k.serialize(o)?;
o.write_all(ciphertext)?;
},
}
}
Ok(())
}
}
impl SerializeKeyInto for Key {
fn serialized_len(&self, tag: Tag) -> usize {
let have_secret_key =
(tag == Tag::SecretKey || tag == Tag::SecretSubkey)
&& self.secret().is_some();
1 + 4 + 1
+ self.mpis().serialized_len()
+ if have_secret_key {
1 + match self.secret().as_ref().unwrap() {
&SecretKey::Unencrypted { ref mpis } =>
mpis.serialized_len() + 2,
&SecretKey::Encrypted {
ref s2k,
ref ciphertext,
..
} => 1 + s2k.serialized_len() + ciphertext.len(),
}
} else {
0
}
}
fn serialize_into(&self, buf: &mut [u8], tag: Tag) -> Result<usize> {
if buf.len() != self.serialized_len(tag) {
return Err(Error::InvalidArgument(
format!("Invalid buffer size, expected {}, got {}",
self.serialized_len(tag), buf.len())).into());
}
let mut cursor = ::std::io::Cursor::new(buf);
self.serialize(&mut cursor, tag)?;
Ok(cursor.position() as usize)
}
}
impl Serialize for UserID {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let len = self.userid().len();
CTB::new(Tag::UserID).serialize(o)?;
BodyLength::Full(len as u32).serialize(o)?;
o.write_all(self.userid())?;
Ok(())
}
}
impl SerializeInto for UserID {
fn serialized_len(&self) -> usize {
1 + BodyLength::Full(self.userid().len() as u32).serialized_len()
+ self.userid().len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for UserAttribute {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let len = self.user_attribute().len();
CTB::new(Tag::UserAttribute).serialize(o)?;
BodyLength::Full(len as u32).serialize(o)?;
o.write_all(self.user_attribute())?;
Ok(())
}
}
impl SerializeInto for UserAttribute {
fn serialized_len(&self) -> usize {
1 + BodyLength::Full(self.user_attribute().len() as u32)
.serialized_len() + self.user_attribute().len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Literal {
pub(crate) fn serialize_headers<W>(&self, o: &mut W,
write_tag: bool)
-> Result<()>
where W: io::Write
{
let filename = if let Some(ref filename) = self.filename() {
let len = cmp::min(filename.len(), 255) as u8;
&filename[..len as usize]
} else {
&b""[..]
};
let date = if let Some(d) = self.date() {
d.to_pgp()?
} else {
0
};
if write_tag {
let len = 1 + (1 + filename.len()) + 4
+ self.common.body.as_ref().map(|b| b.len()).unwrap_or(0);
CTB::new(Tag::Literal).serialize(o)?;
BodyLength::Full(len as u32).serialize(o)?;
}
write_byte(o, self.format().into())?;
write_byte(o, filename.len() as u8)?;
o.write_all(filename)?;
write_be_u32(o, date)?;
Ok(())
}
}
impl Serialize for Literal {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let body = if let Some(ref body) = self.common.body {
&body[..]
} else {
&b""[..]
};
if TRACE {
let prefix = &body[..cmp::min(body.len(), 20)];
eprintln!("Literal::serialize({}{}, {} bytes)",
String::from_utf8_lossy(prefix),
if body.len() > 20 { "..." } else { "" },
body.len());
}
self.serialize_headers(o, true)?;
o.write_all(body)?;
Ok(())
}
}
impl SerializeInto for Literal {
fn serialized_len(&self) -> usize {
let len = 1 + (1 + self.filename().map(|f| f.len()).unwrap_or(0)) + 4
+ self.common.body.as_ref().map(|b| b.len()).unwrap_or(0);
1 + BodyLength::Full(len as u32).serialized_len() + len
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for CompressedData {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
if TRACE {
eprintln!("CompressedData::serialize(\
algo: {}, {:?} children, {:?} bytes)",
self.algorithm(),
self.common.children.as_ref().map(
|cont| cont.children().len()),
self.common.body.as_ref().map(|body| body.len()));
}
let o = stream::Message::new(o);
let mut o = stream::Compressor::new(o, self.algorithm())?;
if let Some(ref children) = self.common.children {
for p in children.children() {
p.serialize(&mut o)?;
}
}
if let Some(ref data) = self.common.body {
o.write_all(data)?;
}
Ok(())
}
}
impl SerializeInto for CompressedData {
fn serialized_len(&self) -> usize {
let inner_length =
self.common.children.as_ref().map(|children| {
children.packets.iter().map(|p| p.serialized_len())
.sum()
}).unwrap_or(0)
+ self.common.body.as_ref().map(|body| body.len()).unwrap_or(0);
1 + inner_length + inner_length / 10
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for PKESK {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
if self.version() != 3 {
return Err(Error::InvalidArgument(
"Don't know how to serialize \
non-version 3 packets.".into()).into());
}
let len = self.net_len();
CTB::new(Tag::PKESK).serialize(o)?;
BodyLength::Full(len as u32).serialize(o)?;
write_byte(o, self.version())?;
self.recipient().serialize(o)?;
write_byte(o, self.pk_algo().into())?;
self.esk().serialize(o)?;
Ok(())
}
}
impl NetLength for PKESK {
fn net_len(&self) -> usize {
1 + 8 + 1 + self.esk().serialized_len()
}
}
impl SerializeInto for PKESK {
fn serialized_len(&self) -> usize {
self.gross_len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for SKESK {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
match self {
&SKESK::V4(ref s) => s.serialize(o),
&SKESK::V5(ref s) => s.serialize(o),
}
}
}
impl SerializeInto for SKESK {
fn serialized_len(&self) -> usize {
match self {
&SKESK::V4(ref s) => s.serialized_len(),
&SKESK::V5(ref s) => s.serialized_len(),
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
match self {
&SKESK::V4(ref s) => generic_serialize_into(s, buf),
&SKESK::V5(ref s) => generic_serialize_into(s, buf),
}
}
}
impl Serialize for SKESK4 {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
if self.version() != 4 {
return Err(Error::InvalidArgument(
"Don't know how to serialize \
non-version 4 packets.".into()).into());
}
let len = self.net_len();
CTB::new(Tag::SKESK).serialize(o)?;
BodyLength::Full(len as u32).serialize(o)?;
write_byte(o, self.version())?;
write_byte(o, self.symmetric_algo().into())?;
self.s2k().serialize(o)?;
if let Some(ref esk) = self.esk() {
o.write_all(&esk[..])?;
}
Ok(())
}
}
impl NetLength for SKESK4 {
fn net_len(&self) -> usize {
1 + 1 + self.s2k().serialized_len()
+ self.esk().map(|esk| esk.len()).unwrap_or(0)
}
}
impl SerializeInto for SKESK4 {
fn serialized_len(&self) -> usize {
self.gross_len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for SKESK5 {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
if self.version() != 5 {
return Err(Error::InvalidArgument(
"Don't know how to serialize \
non-version 4 packets.".into()).into());
}
let len = self.net_len();
CTB::new(Tag::SKESK).serialize(o)?;
BodyLength::Full(len as u32).serialize(o)?;
write_byte(o, self.version())?;
write_byte(o, self.symmetric_algo().into())?;
write_byte(o, self.aead_algo().into())?;
self.s2k().serialize(o)?;
o.write_all(self.aead_iv())?;
if let Some(ref esk) = self.esk() {
o.write_all(&esk[..])?;
}
o.write_all(self.aead_digest())?;
Ok(())
}
}
impl NetLength for SKESK5 {
fn net_len(&self) -> usize {
1 + 1 + 1 + self.s2k().serialized_len()
+ self.aead_iv().len()
+ self.esk().map(|esk| esk.len()).unwrap_or(0)
+ self.aead_digest().len()
}
}
impl SerializeInto for SKESK5 {
fn serialized_len(&self) -> usize {
self.gross_len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for SEIP {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
if let Some(ref _children) = self.common.children {
return Err(Error::InvalidOperation(
"Cannot encrypt, use serialize::stream::Encryptor".into())
.into());
} else {
let body_len = 1
+ self.common.body.as_ref().map(|b| b.len()).unwrap_or(0);
CTB::new(Tag::SEIP).serialize(o)?;
BodyLength::Full(body_len as u32).serialize(o)?;
o.write_all(&[self.version()])?;
if let Some(ref body) = self.common.body {
o.write_all(&body[..])?;
}
}
Ok(())
}
}
impl SerializeInto for SEIP {
fn serialized_len(&self) -> usize {
if self.common.children.is_some() {
0
} else {
1 + 1 + self.common.body.as_ref().map(|b| b.len()).unwrap_or(0)
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for MDC {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
CTB::new(Tag::MDC).serialize(o)?;
BodyLength::Full(20).serialize(o)?;
o.write_all(self.hash())?;
Ok(())
}
}
impl SerializeInto for MDC {
fn serialized_len(&self) -> usize {
1 + BodyLength::Full(20).serialized_len() + 20
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl AED {
fn serialize_headers<W: io::Write>(&self, o: &mut W)
-> Result<()> {
o.write_all(&[self.version(),
self.cipher().into(),
self.aead().into(),
self.chunk_size().trailing_zeros() as u8 - 6])?;
o.write_all(self.iv())?;
Ok(())
}
}
impl Serialize for AED {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
if let Some(ref _children) = self.common.children {
return Err(Error::InvalidOperation(
"Cannot encrypt, use serialize::stream::Encryptor".into())
.into());
} else {
let body_len = self.net_len();
CTB::new(Tag::SEIP).serialize(o)?;
BodyLength::Full(body_len as u32).serialize(o)?;
self.serialize_headers(o)?;
if let Some(ref body) = self.common.body {
o.write_all(&body[..])?;
}
}
Ok(())
}
}
impl NetLength for AED {
fn net_len(&self) -> usize {
if self.common.children.is_some() {
0
} else {
4 + self.iv().len()
+ self.common.body.as_ref().map(|b| b.len()).unwrap_or(0)
+ self.aead().digest_size().unwrap_or(0)
}
}
}
impl SerializeInto for AED {
fn serialized_len(&self) -> usize {
self.gross_len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for Packet {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
let tag = self.tag();
match self {
&Packet::Unknown(ref p) => p.serialize(o),
&Packet::Signature(ref p) => p.serialize(o),
&Packet::OnePassSig(ref p) => p.serialize(o),
&Packet::PublicKey(ref p) => p.serialize(o, tag),
&Packet::PublicSubkey(ref p) => p.serialize(o, tag),
&Packet::SecretKey(ref p) => p.serialize(o, tag),
&Packet::SecretSubkey(ref p) => p.serialize(o, tag),
&Packet::UserID(ref p) => p.serialize(o),
&Packet::UserAttribute(ref p) => p.serialize(o),
&Packet::Literal(ref p) => p.serialize(o),
&Packet::CompressedData(ref p) => p.serialize(o),
&Packet::PKESK(ref p) => p.serialize(o),
&Packet::SKESK(ref p) => p.serialize(o),
&Packet::SEIP(ref p) => p.serialize(o),
&Packet::MDC(ref p) => p.serialize(o),
&Packet::AED(ref p) => p.serialize(o),
}
}
}
impl SerializeInto for Packet {
fn serialized_len(&self) -> usize {
let tag = self.tag();
match self {
&Packet::Unknown(ref p) => p.serialized_len(),
&Packet::Signature(ref p) => p.serialized_len(),
&Packet::OnePassSig(ref p) => p.serialized_len(),
&Packet::PublicKey(ref p) => p.serialized_len(tag),
&Packet::PublicSubkey(ref p) => p.serialized_len(tag),
&Packet::SecretKey(ref p) => p.serialized_len(tag),
&Packet::SecretSubkey(ref p) => p.serialized_len(tag),
&Packet::UserID(ref p) => p.serialized_len(),
&Packet::UserAttribute(ref p) => p.serialized_len(),
&Packet::Literal(ref p) => p.serialized_len(),
&Packet::CompressedData(ref p) => p.serialized_len(),
&Packet::PKESK(ref p) => p.serialized_len(),
&Packet::SKESK(ref p) => p.serialized_len(),
&Packet::SEIP(ref p) => p.serialized_len(),
&Packet::MDC(ref p) => p.serialized_len(),
&Packet::AED(ref p) => p.serialized_len(),
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for PacketPile {
fn serialize<W: io::Write>(&self, o: &mut W) -> Result<()> {
for p in self.children() {
p.serialize(o)?;
}
Ok(())
}
}
impl SerializeInto for PacketPile {
fn serialized_len(&self) -> usize {
self.children().map(|p| p.serialized_len()).sum()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
#[cfg(test)]
mod test {
use std::fs::File;
use std::io::Read;
use super::*;
use constants::CompressionAlgorithm;
use parse::to_unknown_packet;
use parse::PacketParserBuilder;
use parse::Parse;
fn binary_pp(data: &[u8]) -> String {
let mut output = Vec::with_capacity(data.len() * 2 + 3 * data.len() / 4);
for i in 0..data.len() {
if i > 0 && i % (4 * 4 * 2) == 0 {
output.push('\n' as u8);
} else {
if i > 0 && i % 2 == 0 {
output.push(' ' as u8);
}
if i > 0 && i % (4 * 2) == 0 {
output.push(' ' as u8);
}
}
let top = data[i] >> 4;
let bottom = data[i] & 0xFu8;
if top < 10u8 {
output.push('0' as u8 + top)
} else {
output.push('A' as u8 + (top - 10u8))
}
if bottom < 10u8 {
output.push('0' as u8 + bottom)
} else {
output.push('A' as u8 + (bottom - 10u8))
}
}
String::from_utf8(output).unwrap()
}
fn packets_bitwise_compare(filename: &str, packet: &Packet,
expected: &[u8], got: &[u8]) {
let expected = to_unknown_packet(expected).unwrap();
let got = to_unknown_packet(got).unwrap();
let expected_body = if let Some(ref data) = expected.common.body {
&data[..]
} else {
&b""[..]
};
let got_body = if let Some(ref data) = got.common.body {
&data[..]
} else {
&b""[..]
};
let mut fail = false;
if expected.tag() != got.tag() {
eprintln!("Expected a {:?}, got a {:?}", expected.tag(), got.tag());
fail = true;
}
if expected_body != got_body {
eprintln!("Packet contents don't match (for {}):",
filename);
eprintln!("Expected ({} bytes):\n{}",
expected_body.len(), binary_pp(&expected_body));
eprintln!("Got ({} bytes):\n{}",
got_body.len(), binary_pp(&got_body));
eprintln!("Packet: {:#?}", packet);
fail = true;
}
if fail {
panic!("Packets don't match (for {}).", filename);
}
}
#[test]
fn serialize_test_1() {
let filenames = [
"literal-mode-b.gpg",
"literal-mode-t-partial-body.gpg",
"sig.gpg",
"public-key-bare.gpg",
"public-subkey-bare.gpg",
"userid-bare.gpg",
"s2k/mode-0-password-1234.gpg",
"s2k/mode-0-password-1234.gpg",
"s2k/mode-1-password-123456-1.gpg",
"s2k/mode-1-password-foobar-2.gpg",
"s2k/mode-3-aes128-password-13-times-0123456789.gpg",
"s2k/mode-3-aes192-password-123.gpg",
"s2k/mode-3-encrypted-key-password-bgtyhn.gpg",
"s2k/mode-3-password-9876-2.gpg",
"s2k/mode-3-password-qwerty-1.gpg",
"s2k/mode-3-twofish-password-13-times-0123456789.gpg",
];
for filename in filenames.iter() {
let path = path_to(filename);
let mut data = Vec::new();
File::open(&path).expect(&path.to_string_lossy())
.read_to_end(&mut data).expect("Reading test data");
let pile = PacketPile::from_bytes(&data[..]).unwrap();
assert_eq!(pile.children().len(), 1);
let p = pile.descendants().next().unwrap();
let mut buffer = Vec::new();
match p {
&Packet::Literal(ref l) => {
l.serialize(&mut buffer).unwrap();
},
&Packet::Signature(ref s) => {
s.serialize(&mut buffer).unwrap();
},
&Packet::PublicKey(ref pk) => {
pk.serialize(&mut buffer, Tag::PublicKey).unwrap();
},
&Packet::PublicSubkey(ref pk) => {
pk.serialize(&mut buffer, Tag::PublicSubkey).unwrap();
},
&Packet::UserID(ref userid) => {
userid.serialize(&mut buffer).unwrap();
},
&Packet::SKESK(ref skesk) => {
skesk.serialize(&mut buffer).unwrap();
},
ref p => {
panic!("Didn't expect a {:?} packet.", p.tag());
},
}
packets_bitwise_compare(filename, p, &data[..], &buffer[..]);
}
}
#[test]
fn serialize_test_1_unknown() {
let filenames = [
"compressed-data-algo-1.gpg",
"compressed-data-algo-2.gpg",
"compressed-data-algo-3.gpg",
"recursive-2.gpg",
"recursive-3.gpg",
];
for filename in filenames.iter() {
let path = path_to(filename);
let mut data = Vec::new();
File::open(&path).expect(&path.to_string_lossy())
.read_to_end(&mut data).expect("Reading test data");
let u = to_unknown_packet(&data[..]).unwrap();
let data2 = u.to_vec().unwrap();
packets_bitwise_compare(filename, &Packet::Unknown(u),
&data[..], &data2[..]);
}
}
#[cfg(feature = "compression-deflate")]
#[test]
fn serialize_test_2() {
let filenames = [
"compressed-data-algo-1.gpg",
"compressed-data-algo-2.gpg",
"compressed-data-algo-3.gpg",
"recursive-2.gpg",
"recursive-3.gpg",
];
for filename in filenames.iter() {
eprintln!("{}...", filename);
let path = path_to(filename);
let mut data = Vec::new();
File::open(&path).expect(&path.to_string_lossy())
.read_to_end(&mut data).expect("Reading test data");
let pile = PacketParserBuilder::from_bytes(&data[..]).unwrap()
.max_recursion_depth(0)
.buffer_unread_content()
.into_packet_pile().unwrap();
let po = pile.descendants().next();
if let Some(&Packet::CompressedData(ref cd)) = po {
let buffer = cd.to_vec().unwrap();
let pile2 = PacketParserBuilder::from_bytes(&buffer[..]).unwrap()
.max_recursion_depth(0)
.buffer_unread_content()
.into_packet_pile().unwrap();
if pile != pile2 {
eprintln!("Orig:");
let p = pile.children().next().unwrap();
eprintln!("{:?}", p);
let body = &p.body.as_ref().unwrap()[..];
eprintln!("Body: {}", body.len());
eprintln!("{}", binary_pp(body));
eprintln!("Reparsed:");
let p = pile2.children().next().unwrap();
eprintln!("{:?}", p);
let body = &p.body.as_ref().unwrap()[..];
eprintln!("Body: {}", body.len());
eprintln!("{}", binary_pp(body));
assert_eq!(pile, pile2);
}
} else {
panic!("Expected a compressed data data packet.");
}
}
}
#[test]
fn serialize_test_3() {
use constants::DataFormat::Text as T;
let mut messages = Vec::new();
let mut one = Literal::new(T);
one.set_body(b"one".to_vec());
let mut two = Literal::new(T);
two.set_body(b"two".to_vec());
let mut three = Literal::new(T);
three.set_body(b"three".to_vec());
let mut four = Literal::new(T);
four.set_body(b"four".to_vec());
let mut five = Literal::new(T);
five.set_body(b"five".to_vec());
let mut six = Literal::new(T);
six.set_body(b"six".to_vec());
let mut top_level = Vec::new();
top_level.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(one.clone().into())
.push(two.clone().into())
.into());
top_level.push(three.clone().into());
messages.push(top_level);
let mut top_level = Vec::new();
top_level.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(one.clone().into())
.push(two.clone().into())
.into())
.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(three.clone().into())
.push(four.clone().into())
.into())
.into());
messages.push(top_level);
let mut top_level = Vec::new();
top_level.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(one.clone().into())
.push(two.clone().into())
.into())
.into())
.into())
.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(three.clone().into())
.into())
.push(four.clone().into())
.into())
.into());
messages.push(top_level);
let mut top_level = Vec::new();
top_level.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(one.clone().into())
.push(two.clone().into())
.into());
top_level.push(
three.clone().into());
top_level.push(
four.clone().into());
top_level.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(five.into())
.push(six.into())
.into());
messages.push(top_level);
let mut top_level = Vec::new();
let mut uid = UserID::new();
uid.set_userid("Foo");
top_level.push(uid.into());
messages.push(top_level);
for m in messages.into_iter() {
let pile = PacketPile::from(m);
pile.pretty_print();
let mut buffer = Vec::new();
pile.clone().serialize(&mut buffer).unwrap();
let pile2 = PacketParserBuilder::from_bytes(&buffer[..]).unwrap()
.buffer_unread_content()
.into_packet_pile().unwrap();
if pile != pile2 {
eprintln!("ORIG...");
pile.pretty_print();
eprintln!("REPARSED...");
pile2.pretty_print();
panic!("Reparsed packet does not match original packet!");
}
}
}
#[test]
fn body_length_edge_cases() {
{
let mut buf = vec![];
BodyLength::Full(0).serialize(&mut buf).unwrap();
assert_eq!(&buf[..], &b"\x00"[..]);
}
{
let mut buf = vec![];
BodyLength::Full(1).serialize(&mut buf).unwrap();
assert_eq!(&buf[..], &b"\x01"[..]);
}
{
let mut buf = vec![];
BodyLength::Full(191).serialize(&mut buf).unwrap();
assert_eq!(&buf[..], &b"\xbf"[..]);
}
{
let mut buf = vec![];
BodyLength::Full(192).serialize(&mut buf).unwrap();
assert_eq!(&buf[..], &b"\xc0\x00"[..]);
}
{
let mut buf = vec![];
BodyLength::Full(193).serialize(&mut buf).unwrap();
assert_eq!(&buf[..], &b"\xc0\x01"[..]);
}
{
let mut buf = vec![];
BodyLength::Full(8383).serialize(&mut buf).unwrap();
assert_eq!(&buf[..], &b"\xdf\xff"[..]);
}
{
let mut buf = vec![];
BodyLength::Full(8384).serialize(&mut buf).unwrap();
assert_eq!(&buf[..], &b"\xff\x00\x00\x20\xc0"[..]);
}
{
let mut buf = vec![];
BodyLength::Full(0xffffffff).serialize(&mut buf).unwrap();
assert_eq!(&buf[..], &b"\xff\xff\xff\xff\xff"[..]);
}
}
}