use std::fmt;
use std::io::{self, Write};
use std::iter;
use time;
use nettle::{Hash, Yarrow, Random};
use {
crypto,
Error,
Fingerprint,
HashAlgorithm,
Result,
crypto::Password,
crypto::SessionKey,
packet::prelude::*,
packet::signature,
TPK,
};
use packet::ctb::CTB;
use packet::BodyLength;
use super::{
PartialBodyFilter,
Serialize,
writer,
};
use constants::{
AEADAlgorithm,
CompressionAlgorithm,
DataFormat,
SignatureType,
SymmetricAlgorithm,
};
use conversions::Time;
#[doc(hidden)]
#[derive(Debug)]
pub struct Cookie {
level: usize,
private: Private,
}
#[derive(Debug)]
enum Private {
Nothing,
Signer,
}
impl Cookie {
fn new(level: usize) -> Self {
Cookie {
level: level,
private: Private::Nothing,
}
}
}
impl Default for Cookie {
fn default() -> Self {
Cookie::new(0)
}
}
pub struct Message {
}
impl Message {
pub fn new<'a, W: 'a + io::Write>(w: W) -> writer::Stack<'a, Cookie> {
writer::Generic::new(w, Cookie::new(0))
}
}
impl<'a> From<&'a mut io::Write> for writer::Stack<'a, Cookie> {
fn from(w: &'a mut io::Write) -> Self {
writer::Generic::new(w, Cookie::new(0))
}
}
pub struct ArbitraryWriter<'a> {
inner: writer::BoxStack<'a, Cookie>,
}
impl<'a> ArbitraryWriter<'a> {
pub fn new(mut inner: writer::Stack<'a, Cookie>, tag: Tag)
-> Result<writer::Stack<'a, Cookie>> {
let level = inner.as_ref().cookie_ref().level + 1;
CTB::new(tag).serialize(&mut inner)?;
Ok(writer::Stack::from(Box::new(ArbitraryWriter {
inner: PartialBodyFilter::new(inner, Cookie::new(level)).into()
})))
}
}
impl<'a> fmt::Debug for ArbitraryWriter<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ArbitraryWriter")
.field("inner", &self.inner)
.finish()
}
}
impl<'a> Write for ArbitraryWriter<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
impl<'a> writer::Stackable<'a, Cookie> for ArbitraryWriter<'a> {
fn into_inner(self: Box<Self>) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
Box::new(self.inner).into_inner()
}
fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
unimplemented!()
}
fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unimplemented!()
}
fn inner_ref(&self) -> Option<&writer::Stackable<'a, Cookie>> {
self.inner.inner_ref()
}
fn inner_mut(&mut self) -> Option<&mut writer::Stackable<'a, Cookie>> {
self.inner.inner_mut()
}
fn cookie_set(&mut self, cookie: Cookie) -> Cookie {
self.inner.cookie_set(cookie)
}
fn cookie_ref(&self) -> &Cookie {
self.inner.cookie_ref()
}
fn cookie_mut(&mut self) -> &mut Cookie {
self.inner.cookie_mut()
}
}
pub struct Signer<'a> {
inner: Option<writer::BoxStack<'a, Cookie>>,
signers: Vec<&'a mut dyn crypto::Signer>,
intended_recipients: Option<Vec<Fingerprint>>,
detached: bool,
hash: Box<Hash>,
cookie: Cookie,
}
impl<'a> Signer<'a> {
pub fn new<H>(inner: writer::Stack<'a, Cookie>,
signers: Vec<&'a mut dyn crypto::Signer>,
hash_algo: H)
-> Result<writer::Stack<'a, Cookie>>
where H: Into<Option<HashAlgorithm>>
{
Self::make(inner, signers, None, false, hash_algo)
}
pub fn with_intended_recipients<H>(inner: writer::Stack<'a, Cookie>,
signers: Vec<&'a mut dyn crypto::Signer>,
recipients: &[&'a TPK],
hash_algo: H)
-> Result<writer::Stack<'a, Cookie>>
where H: Into<Option<HashAlgorithm>>
{
Self::make(inner, signers,
Some(recipients.iter().map(|r| r.fingerprint()).collect()),
false, hash_algo)
}
pub fn detached<H>(inner: writer::Stack<'a, Cookie>,
signers: Vec<&'a mut dyn crypto::Signer>,
hash_algo: H)
-> Result<writer::Stack<'a, Cookie>>
where H: Into<Option<HashAlgorithm>>
{
Self::make(inner, signers, None, true, hash_algo)
}
fn make<H>(inner: writer::Stack<'a, Cookie>,
signers: Vec<&'a mut dyn crypto::Signer>,
intended_recipients: Option<Vec<Fingerprint>>, detached: bool,
hash_algo: H)
-> Result<writer::Stack<'a, Cookie>>
where H: Into<Option<HashAlgorithm>>
{
let mut inner = writer::BoxStack::from(inner);
let hash_algo = hash_algo.into().unwrap_or(HashAlgorithm::SHA512);
if signers.len() == 0 {
return Err(Error::InvalidArgument(
"No signing keys given".into()).into());
}
if ! detached {
for (i, keypair) in signers.iter().enumerate() {
let key = keypair.public();
let mut ops = OnePassSig3::new(SignatureType::Binary);
ops.set_pk_algo(key.pk_algo());
ops.set_hash_algo(hash_algo);
ops.set_issuer(key.keyid());
ops.set_last(i == signers.len() - 1);
ops.serialize(&mut inner)?;
}
}
let level = inner.cookie_ref().level + 1;
Ok(writer::Stack::from(Box::new(Signer {
inner: Some(inner),
signers: signers,
intended_recipients: intended_recipients,
detached: detached,
hash: hash_algo.context()?,
cookie: Cookie {
level: level,
private: Private::Signer,
},
})))
}
fn emit_signatures(&mut self) -> Result<()> {
if let Some(ref mut sink) = self.inner {
for signer in self.signers.iter_mut() {
let mut hash = self.hash.clone();
let mut sig = signature::Builder::new(SignatureType::Binary)
.set_signature_creation_time(time::now().canonicalize())?
.set_issuer_fingerprint(signer.public().fingerprint())?
.set_issuer(signer.public().keyid())?;
if let Some(ref ir) = self.intended_recipients {
sig = sig.set_intended_recipients(ir.clone())?;
}
let sig = sig.sign_hash(*signer, HashAlgorithm::SHA512, hash)?;
sig.serialize(sink)?;
}
}
Ok(())
}
}
impl<'a> Drop for Signer<'a> {
fn drop(&mut self) {
let _ = self.emit_signatures();
}
}
impl<'a> fmt::Debug for Signer<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Signer")
.field("inner", &self.inner)
.field("cookie", &self.cookie)
.finish()
}
}
impl<'a> Write for Signer<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let written = match self.inner.as_mut() {
Some(ref mut w) if ! self.detached => w.write(buf),
Some(_) => Ok(buf.len()),
None => Ok(buf.len()),
};
if let Ok(amount) = written {
self.hash.update(&buf[..amount]);
}
written
}
fn flush(&mut self) -> io::Result<()> {
match self.inner.as_mut() {
Some(ref mut w) => w.flush(),
None => Ok(()),
}
}
}
impl<'a> writer::Stackable<'a, Cookie> for Signer<'a> {
fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
Ok(self.inner.take())
}
fn mount(&mut self, new: writer::BoxStack<'a, Cookie>) {
self.inner = Some(new);
}
fn inner_mut(&mut self) -> Option<&mut writer::Stackable<'a, Cookie>> {
if let Some(ref mut i) = self.inner {
Some(i)
} else {
None
}
}
fn inner_ref(&self) -> Option<&writer::Stackable<'a, Cookie>> {
if let Some(ref i) = self.inner {
Some(i)
} else {
None
}
}
fn into_inner(mut self: Box<Self>)
-> Result<Option<writer::BoxStack<'a, Cookie>>> {
self.emit_signatures()?;
Ok(self.inner.take())
}
fn cookie_set(&mut self, cookie: Cookie) -> Cookie {
::std::mem::replace(&mut self.cookie, cookie)
}
fn cookie_ref(&self) -> &Cookie {
&self.cookie
}
fn cookie_mut(&mut self) -> &mut Cookie {
&mut self.cookie
}
}
pub struct LiteralWriter<'a> {
inner: writer::BoxStack<'a, Cookie>,
signature_writer: Option<writer::BoxStack<'a, Cookie>>,
}
impl<'a> LiteralWriter<'a> {
pub fn new(inner: writer::Stack<'a, Cookie>,
format: DataFormat,
filename: Option<&[u8]>,
date: Option<time::Tm>)
-> Result<writer::Stack<'a, Cookie>> {
let mut inner = writer::BoxStack::from(inner);
let level = inner.cookie_ref().level + 1;
let mut template = Literal::new(format);
template.set_date(date);
if let Some(f) = filename {
template.set_filename_from_bytes(f)?;
}
let signer_above =
if let &Cookie {
private: Private::Signer{..},
..
} = inner.cookie_ref() {
true
} else {
false
};
let mut signature_writer = None;
if signer_above {
let stack = inner.pop()?;
let stack = stack.unwrap();
signature_writer = Some(inner);
inner = stack;
}
CTB::new(Tag::Literal).serialize(&mut inner)?;
let mut inner
= PartialBodyFilter::new(writer::Stack::from(inner), Cookie::new(level));
template.serialize_headers(&mut inner, false)?;
Ok(writer::Stack::from(Box::new(Self {
inner: inner.into(),
signature_writer: signature_writer,
})))
}
}
impl<'a> fmt::Debug for LiteralWriter<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("LiteralWriter")
.field("inner", &self.inner)
.finish()
}
}
impl<'a> Write for LiteralWriter<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let written = self.inner.write(buf);
if let (&Ok(ref amount), &mut Some(ref mut sig))
= (&written, &mut self.signature_writer) {
sig.write_all(&buf[..*amount])?;
};
written
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
impl<'a> writer::Stackable<'a, Cookie> for LiteralWriter<'a> {
fn into_inner(mut self: Box<Self>)
-> Result<Option<writer::BoxStack<'a, Cookie>>> {
let signer = self.signature_writer.take();
let stack = self.inner
.into_inner()?.unwrap();
if let Some(mut signer) = signer {
signer.mount(stack);
Ok(Some(signer))
} else {
Ok(Some(stack))
}
}
fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
unimplemented!()
}
fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unimplemented!()
}
fn inner_ref(&self) -> Option<&writer::Stackable<'a, Cookie>> {
self.inner.inner_ref()
}
fn inner_mut(&mut self) -> Option<&mut writer::Stackable<'a, Cookie>> {
self.inner.inner_mut()
}
fn cookie_set(&mut self, cookie: Cookie) -> Cookie {
self.inner.cookie_set(cookie)
}
fn cookie_ref(&self) -> &Cookie {
self.inner.cookie_ref()
}
fn cookie_mut(&mut self) -> &mut Cookie {
self.inner.cookie_mut()
}
}
pub struct Compressor<'a> {
inner: writer::BoxStack<'a, Cookie>,
}
impl<'a> Compressor<'a> {
pub fn new(inner: writer::Stack<'a, Cookie>, algo: CompressionAlgorithm)
-> Result<writer::Stack<'a, Cookie>> {
let mut inner = writer::BoxStack::from(inner);
let level = inner.cookie_ref().level + 1;
CTB::new(Tag::CompressedData).serialize(&mut inner)?;
let mut inner: writer::Stack<'a, Cookie>
= PartialBodyFilter::new(writer::Stack::from(inner),
Cookie::new(level));
inner.as_mut().write_u8(algo.into())?;
let inner: writer::Stack<'a, Cookie> = match algo {
CompressionAlgorithm::Uncompressed =>
writer::Identity::new(inner, Cookie::new(level)),
#[cfg(feature = "compression-deflate")]
CompressionAlgorithm::Zip =>
writer::ZIP::new(inner, Cookie::new(level)),
#[cfg(feature = "compression-deflate")]
CompressionAlgorithm::Zlib =>
writer::ZLIB::new(inner, Cookie::new(level)),
#[cfg(feature = "compression-bzip2")]
CompressionAlgorithm::BZip2 =>
writer::BZ::new(inner, Cookie::new(level)),
_ => unimplemented!(),
};
Ok(writer::Stack::from(Box::new(Self{inner: inner.into()})))
}
}
impl<'a> fmt::Debug for Compressor<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Compressor")
.field("inner", &self.inner)
.finish()
}
}
impl<'a> io::Write for Compressor<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
impl<'a> writer::Stackable<'a, Cookie> for Compressor<'a> {
fn into_inner(self: Box<Self>) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
Box::new(self.inner).into_inner()?.unwrap().into_inner()
}
fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
unimplemented!()
}
fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unimplemented!()
}
fn inner_ref(&self) -> Option<&writer::Stackable<'a, Cookie>> {
self.inner.inner_ref()
}
fn inner_mut(&mut self) -> Option<&mut writer::Stackable<'a, Cookie>> {
self.inner.inner_mut()
}
fn cookie_set(&mut self, cookie: Cookie) -> Cookie {
self.inner.cookie_set(cookie)
}
fn cookie_ref(&self) -> &Cookie {
self.inner.cookie_ref()
}
fn cookie_mut(&mut self) -> &mut Cookie {
self.inner.cookie_mut()
}
}
pub struct Encryptor<'a> {
inner: Option<writer::BoxStack<'a, Cookie>>,
hash: Box<Hash>,
cookie: Cookie,
}
pub enum EncryptionMode {
AtRest,
ForTransport,
}
impl<'a> Encryptor<'a> {
pub fn new<C>(mut inner: writer::Stack<'a, Cookie>,
passwords: &[&Password], tpks: &[&TPK],
encryption_mode: EncryptionMode,
cipher_algo: C)
-> Result<writer::Stack<'a, Cookie>>
where C: Into<Option<SymmetricAlgorithm>>
{
if tpks.len() + passwords.len() == 0 {
return Err(Error::InvalidArgument(
"Neither recipient keys nor passwords given".into()).into());
}
let mut rng = Yarrow::default();
struct AEADParameters {
algo: AEADAlgorithm,
chunk_size: usize,
nonce: Box<[u8]>,
}
let aead = if tpks.len() > 0 && tpks.iter().all(|t| {
t.primary_key_signature().map(|s| s.features().supports_aead())
.unwrap_or(false)
}) {
let mut nonce = vec![0; AEADAlgorithm::EAX.iv_size()?];
rng.random(&mut nonce);
Some(AEADParameters {
algo: AEADAlgorithm::EAX, chunk_size: 4096, nonce: nonce.into_boxed_slice(),
})
} else {
None
};
let level = inner.as_ref().cookie_ref().level + 1;
let algo = cipher_algo.into().unwrap_or(SymmetricAlgorithm::AES256);
let sk = SessionKey::new(&mut rng, algo.key_size()?);
for tpk in tpks {
let can_encrypt = |key: &Key, sig: Option<&Signature>| -> bool {
if let Some(sig) = sig {
(match encryption_mode {
EncryptionMode::AtRest =>
sig.key_flags().can_encrypt_at_rest(),
EncryptionMode::ForTransport =>
sig.key_flags().can_encrypt_for_transport(),
}
&& sig.signature_alive()
&& sig.key_alive(key))
} else {
false
}
};
let subkeys = tpk.subkeys().filter_map(|skb| {
let key = skb.subkey();
if can_encrypt(key, skb.binding_signature()) {
Some(key)
} else {
None
}
});
let primary_can_encrypt =
can_encrypt(tpk.primary(), tpk.primary_key_signature());
let keys =
iter::once(tpk.primary())
.filter(|_| primary_can_encrypt)
.chain(subkeys);
let mut count = 0;
for key in keys {
if let Ok(pkesk) = PKESK3::for_recipient(algo, &sk, key) {
pkesk.serialize(&mut inner)?;
count += 1;
}
}
if count == 0 {
return Err(Error::InvalidOperation(
format!("Key {} has no suitable encryption subkey",
tpk)).into());
}
}
for password in passwords {
if let Some(aead) = aead.as_ref() {
let skesk = SKESK5::with_password(algo, aead.algo,
Default::default(),
&sk, password).unwrap();
skesk.serialize(&mut inner)?;
} else {
let skesk = SKESK4::with_password(algo, Default::default(),
&sk, password).unwrap();
skesk.serialize(&mut inner)?;
}
}
let encryptor = if let Some(aead) = aead {
CTB::new(Tag::AED).serialize(&mut inner)?;
let mut inner = PartialBodyFilter::new(inner, Cookie::new(level));
let aed = AED1::new(algo, aead.algo, aead.chunk_size, aead.nonce)?;
aed.serialize_headers(&mut inner)?;
writer::AEADEncryptor::new(
inner.into(),
Cookie::new(level),
aed.symmetric_algo(),
aed.aead(),
aed.chunk_size(),
aed.iv(),
&sk,
)?
} else {
CTB::new(Tag::SEIP).serialize(&mut inner)?;
let mut inner = PartialBodyFilter::new(inner, Cookie::new(level));
inner.write_all(&[1])?;
let encryptor = writer::Encryptor::new(
inner.into(),
Cookie::new(level),
algo,
&sk,
)?;
let mut encryptor = writer::Stack::from(Box::new(Self{
inner: Some(encryptor.into()),
hash: HashAlgorithm::SHA1.context().unwrap(),
cookie: Cookie::new(level),
}));
let mut iv = vec![0; algo.block_size()?];
rng.random(&mut iv);
encryptor.write_all(&iv)?;
encryptor.write_all(&iv[iv.len() - 2..])?;
encryptor
};
Ok(encryptor)
}
fn emit_mdc(&mut self) -> Result<writer::BoxStack<'a, Cookie>> {
if let Some(mut w) = self.inner.take() {
let mut header = Vec::new();
CTB::new(Tag::MDC).serialize(&mut header)?;
BodyLength::Full(20).serialize(&mut header)?;
self.hash.update(&header);
MDC::from(self.hash.clone()).serialize(&mut w)?;
let mut w = w.into_inner()?.unwrap();
let mut w = w.into_inner()?.unwrap();
Ok(w)
} else {
Err(Error::InvalidOperation(
"Inner writer already taken".into()).into())
}
}
}
impl<'a> Drop for Encryptor<'a> {
fn drop(&mut self) {
let _ = self.emit_mdc();
}
}
impl<'a> fmt::Debug for Encryptor<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Encryptor")
.field("inner", &self.inner)
.finish()
}
}
impl<'a> Write for Encryptor<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let written = match self.inner.as_mut() {
Some(ref mut w) => w.write(buf),
None => Ok(buf.len()),
};
if let Ok(amount) = written {
self.hash.update(&buf[..amount]);
}
written
}
fn flush(&mut self) -> io::Result<()> {
match self.inner.as_mut() {
Some(ref mut w) => w.flush(),
None => Ok(()),
}
}
}
impl<'a> writer::Stackable<'a, Cookie> for Encryptor<'a> {
fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
unimplemented!()
}
fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unimplemented!()
}
fn inner_ref(&self) -> Option<&writer::Stackable<'a, Cookie>> {
if let Some(ref i) = self.inner {
Some(i)
} else {
None
}
}
fn inner_mut(&mut self) -> Option<&mut writer::Stackable<'a, Cookie>> {
if let Some(ref mut i) = self.inner {
Some(i)
} else {
None
}
}
fn into_inner(mut self: Box<Self>) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
Ok(Some(self.emit_mdc()?))
}
fn cookie_set(&mut self, cookie: Cookie) -> Cookie {
::std::mem::replace(&mut self.cookie, cookie)
}
fn cookie_ref(&self) -> &Cookie {
&self.cookie
}
fn cookie_mut(&mut self) -> &mut Cookie {
&mut self.cookie
}
}
#[cfg(test)]
mod test {
use std::io::Read;
use {Packet, PacketPile, packet::CompressedData};
use parse::{Parse, PacketParserResult, PacketParser};
use super::*;
use constants::DataFormat::Text as T;
macro_rules! bytes {
( $x:expr ) => { include_bytes!(concat!("../../tests/data/", $x)) };
}
#[test]
fn arbitrary() {
let mut o = vec![];
{
let m = Message::new(&mut o);
let mut ustr = ArbitraryWriter::new(m, Tag::Literal).unwrap();
ustr.write_all(b"t").unwrap(); ustr.write_all(b"\x00").unwrap(); ustr.write_all(b"\x00\x00\x00\x00").unwrap(); ustr.write_all(b"Hello world.").unwrap(); }
let mut pp = PacketParser::from_bytes(&o).unwrap().unwrap();
if let Packet::Literal(ref l) = pp.packet {
assert_eq!(l.format(), DataFormat::Text);
assert_eq!(l.filename(), None);
assert_eq!(l.date(), None);
} else {
panic!("Unexpected packet type.");
}
let mut body = vec![];
pp.read_to_end(&mut body).unwrap();
assert_eq!(&body, b"Hello world.");
let (_, ppr) = pp.recurse().unwrap();
assert!(ppr.is_none());
}
#[test]
fn stream_0() {
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 reference = Vec::new();
reference.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(one.into())
.push(two.into())
.into());
reference.push(three.into());
let mut o = vec![];
{
let m = Message::new(&mut o);
let c = Compressor::new(
m, CompressionAlgorithm::Uncompressed).unwrap();
let mut ls = LiteralWriter::new(c, T, None, None).unwrap();
write!(ls, "one").unwrap();
let c = ls.finalize_one().unwrap().unwrap(); let mut ls = LiteralWriter::new(c, T, None, None).unwrap();
write!(ls, "two").unwrap();
let c = ls.finalize_one().unwrap().unwrap(); let c = c.finalize_one().unwrap().unwrap(); let mut ls = LiteralWriter::new(c, T, None, None).unwrap();
write!(ls, "three").unwrap();
}
let pile = PacketPile::from(reference);
let pile2 = PacketPile::from_bytes(&o).unwrap();
if pile != pile2 {
eprintln!("REFERENCE...");
pile.pretty_print();
eprintln!("REPARSED...");
pile2.pretty_print();
panic!("Reparsed packet does not match reference packet!");
}
}
#[test]
fn stream_1() {
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 reference = Vec::new();
reference.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(one.into())
.push(two.into())
.into())
.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(three.into())
.push(four.into())
.into())
.into());
let mut o = vec![];
{
let m = Message::new(&mut o);
let c0 = Compressor::new(
m, CompressionAlgorithm::Uncompressed).unwrap();
let c = Compressor::new(
c0, CompressionAlgorithm::Uncompressed).unwrap();
let mut ls = LiteralWriter::new(c, T, None, None).unwrap();
write!(ls, "one").unwrap();
let c = ls.finalize_one().unwrap().unwrap();
let mut ls = LiteralWriter::new(c, T, None, None).unwrap();
write!(ls, "two").unwrap();
let c = ls.finalize_one().unwrap().unwrap();
let c0 = c.finalize_one().unwrap().unwrap();
let c = Compressor::new(
c0, CompressionAlgorithm::Uncompressed).unwrap();
let mut ls = LiteralWriter::new(c, T, None, None).unwrap();
write!(ls, "three").unwrap();
let c = ls.finalize_one().unwrap().unwrap();
let mut ls = LiteralWriter::new(c, T, None, None).unwrap();
write!(ls, "four").unwrap();
}
let pile = PacketPile::from(reference);
let pile2 = PacketPile::from_bytes(&o).unwrap();
if pile != pile2 {
eprintln!("REFERENCE...");
pile.pretty_print();
eprintln!("REPARSED...");
pile2.pretty_print();
panic!("Reparsed packet does not match reference packet!");
}
}
#[cfg(feature = "compression-deflate")]
#[test]
fn stream_big() {
let zeros = vec![0; 1024 * 1024 * 4];
let mut o = vec![];
{
let m = Message::new(&mut o);
let c = Compressor::new(m,
CompressionAlgorithm::BZip2).unwrap();
let mut ls = LiteralWriter::new(c, T, None, None).unwrap();
for _ in 0 .. 16 {
ls.write_all(&zeros).unwrap();
}
}
assert!(o.len() < 1024);
}
#[test]
fn signature() {
use crypto::KeyPair;
use packet::key::SecretKey;
use std::collections::HashMap;
use Fingerprint;
let mut keys: HashMap<Fingerprint, Key> = HashMap::new();
for tsk in &[
TPK::from_bytes(bytes!("keys/testy-private.pgp")).unwrap(),
TPK::from_bytes(bytes!("keys/testy-new-private.pgp")).unwrap(),
] {
for key in tsk.keys_all().signing_capable().map(|x| x.2)
{
keys.insert(key.fingerprint(), key.clone());
}
}
let mut o = vec![];
{
let mut signers = keys.iter().map(|(_, key)| {
match key.secret() {
Some(SecretKey::Unencrypted { ref mpis }) =>
KeyPair::new(key.clone(), mpis.clone()).unwrap(),
s =>
panic!("expected unencrypted secret key, got: {:?}", s),
}
}).collect::<Vec<KeyPair>>();
let m = Message::new(&mut o);
let signer = Signer::new(
m,
signers.iter_mut()
.map(|s| -> &mut dyn crypto::Signer {s})
.collect(),
None)
.unwrap();
let mut ls = LiteralWriter::new(signer, T, None, None).unwrap();
ls.write_all(b"Tis, tis, tis. Tis is important.").unwrap();
let signer = ls.finalize_one().unwrap().unwrap();
let _ = signer.finalize_one().unwrap().unwrap();
}
let mut ppr = PacketParser::from_bytes(&o).unwrap();
let mut good = 0;
while let PacketParserResult::Some(pp) = ppr {
if let Packet::Signature(ref sig) = pp.packet {
let key = keys.get(&sig.issuer_fingerprint().unwrap())
.unwrap();
let result = sig.verify(key).unwrap();
assert!(result);
good += 1;
}
ppr = pp.recurse().unwrap().1;
}
assert_eq!(good, 2);
}
#[test]
fn encryptor() {
let passwords: [Password; 2] = ["streng geheim".into(),
"top secret".into()];
let message = b"Hello world.";
let mut o = vec![];
{
let m = Message::new(&mut o);
let encryptor = Encryptor::new(
m, &passwords.iter().collect::<Vec<&Password>>(),
&[], EncryptionMode::ForTransport, None)
.unwrap();
let mut literal = LiteralWriter::new(encryptor, DataFormat::Binary,
None, None)
.unwrap();
literal.write_all(message).unwrap();
}
#[derive(Debug, PartialEq)]
enum State {
Start,
Decrypted(Vec<(SymmetricAlgorithm, SessionKey)>),
Deciphered,
MDC,
Done,
}
for password in &passwords {
let mut state = State::Start;
let mut ppr = PacketParser::from_bytes(&o).unwrap();
while let PacketParserResult::Some(mut pp) = ppr {
state = match state {
State::Start =>
if let Packet::SKESK(ref skesk) = pp.packet {
match skesk.decrypt(password) {
Ok((algo, key))
=> State::Decrypted(
vec![(algo, key)]),
Err(e) =>
panic!("Decryption failed: {}", e),
}
} else {
panic!("Unexpected packet: {:?}", pp.packet)
},
State::Decrypted(mut keys) =>
match pp.packet {
Packet::SEIP(_) =>
loop {
if let Some((algo, key)) = keys.pop() {
let r = pp.decrypt(algo, &key);
if r.is_ok() {
break State::Deciphered;
}
} else {
panic!("seip decryption failed");
}
},
Packet::SKESK(ref skesk) =>
match skesk.decrypt(password) {
Ok((algo, key)) => {
keys.push((algo, key));
State::Decrypted(keys)
},
Err(e) =>
panic!("Decryption failed: {}", e),
},
_ =>
panic!("Unexpected packet: {:?}", pp.packet),
},
State::Deciphered =>
if let Packet::Literal(_) = pp.packet {
let mut body = Vec::new();
pp.read_to_end(&mut body).unwrap();
assert_eq!(&body, message);
State::MDC
} else {
panic!("Unexpected packet: {:?}", pp.packet)
},
State::MDC =>
if let Packet::MDC(ref mdc) = pp.packet {
assert_eq!(mdc.hash(), mdc.computed_hash());
State::Done
} else {
panic!("Unexpected packet: {:?}", pp.packet)
},
State::Done =>
panic!("Unexpected packet: {:?}", pp.packet),
};
ppr = pp.recurse().unwrap().1;
}
assert_eq!(state, State::Done);
}
}
}