use std::fmt;
use std::io::{self, Write};
use std::time::SystemTime;
use crate::{
armor,
crypto,
Error,
Fingerprint,
HashAlgorithm,
KeyID,
Result,
crypto::Password,
crypto::SessionKey,
packet::prelude::*,
packet::signature,
packet::key,
cert::prelude::*,
};
use crate::packet::header::CTB;
use crate::packet::header::BodyLength;
use super::{
Marshal,
};
use crate::types::{
AEADAlgorithm,
CompressionAlgorithm,
CompressionLevel,
DataFormat,
SignatureType,
SymmetricAlgorithm,
};
pub(crate) mod writer;
#[cfg(feature = "compression-deflate")]
pub mod padding;
mod partial_body;
use partial_body::PartialBodyFilter;
#[derive(Debug)]
struct Cookie {
level: usize,
private: Private,
}
#[derive(Debug)]
enum Private {
Nothing,
Signer,
}
impl Cookie {
fn new(level: usize) -> Self {
Cookie {
level,
private: Private::Nothing,
}
}
}
impl Default for Cookie {
fn default() -> Self {
Cookie::new(0)
}
}
#[derive(Debug)]
pub struct Message<'a>(writer::BoxStack<'a, Cookie>);
assert_send_and_sync!(Message<'_>);
impl<'a> Message<'a> {
pub fn new<W: 'a + io::Write + Send + Sync>(w: W) -> Message<'a> {
writer::Generic::new(w, Cookie::new(0))
}
pub fn finalize_one(self) -> Result<Option<Message<'a>>> {
Ok(self.0.into_inner()?.map(|bs| Self::from(bs)))
}
pub fn finalize(self) -> Result<()> {
let mut stack = self;
while let Some(s) = stack.finalize_one()? {
stack = s;
}
Ok(())
}
}
impl<'a> From<&'a mut (dyn io::Write + Send + Sync)> for Message<'a> {
fn from(w: &'a mut (dyn io::Write + Send + Sync)) -> Self {
writer::Generic::new(w, Cookie::new(0))
}
}
pub struct Armorer<'a> {
kind: armor::Kind,
headers: Vec<(String, String)>,
inner: Message<'a>,
}
assert_send_and_sync!(Armorer<'_>);
impl<'a> Armorer<'a> {
pub fn new(inner: Message<'a>) -> Self {
Self {
kind: armor::Kind::Message,
headers: Vec::with_capacity(0),
inner,
}
}
pub fn kind(mut self, kind: armor::Kind) -> Self {
self.kind = kind;
self
}
pub fn add_header<K, V>(mut self, key: K, value: V) -> Self
where K: AsRef<str>,
V: AsRef<str>,
{
self.headers.push((key.as_ref().to_string(),
value.as_ref().to_string()));
self
}
pub fn build(self) -> Result<Message<'a>> {
let level = self.inner.as_ref().cookie_ref().level;
writer::Armorer::new(
self.inner,
Cookie::new(level + 1),
self.kind,
self.headers,
)
}
}
impl<'a> fmt::Debug for Armorer<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Armorer")
.field("inner", &self.inner)
.field("kind", &self.kind)
.field("headers", &self.headers)
.finish()
}
}
pub struct ArbitraryWriter<'a> {
inner: writer::BoxStack<'a, Cookie>,
}
assert_send_and_sync!(ArbitraryWriter<'_>);
impl<'a> ArbitraryWriter<'a> {
pub fn new(mut inner: Message<'a>, tag: Tag)
-> Result<Message<'a>> {
let level = inner.as_ref().cookie_ref().level + 1;
CTB::new(tag).serialize(&mut inner)?;
Ok(Message::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>>> {
unreachable!("Only implemented by Signer")
}
fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unreachable!("Only implemented by Signer")
}
fn inner_ref(&self) -> Option<&(dyn writer::Stackable<'a, Cookie> + Send + Sync)> {
Some(self.inner.as_ref())
}
fn inner_mut(&mut self) -> Option<&mut (dyn writer::Stackable<'a, Cookie> + Send + Sync)> {
Some(self.inner.as_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()
}
fn position(&self) -> u64 {
self.inner.position()
}
}
pub struct Signer<'a> {
inner: Option<writer::BoxStack<'a, Cookie>>,
signers: Vec<Box<dyn crypto::Signer + Send + Sync + 'a>>,
intended_recipients: Vec<Fingerprint>,
detached: bool,
template: signature::SignatureBuilder,
creation_time: Option<SystemTime>,
hash: Box<dyn crypto::hash::Digest>,
cookie: Cookie,
position: u64,
}
assert_send_and_sync!(Signer<'_>);
impl<'a> Signer<'a> {
pub fn new<S>(inner: Message<'a>, signer: S) -> Self
where S: crypto::Signer + Send + Sync + 'a
{
Self::with_template(inner, signer,
signature::SignatureBuilder::new(SignatureType::Binary))
}
pub fn with_template<S, T>(inner: Message<'a>, signer: S, template: T)
-> Self
where S: crypto::Signer + Send + Sync + 'a,
T: Into<signature::SignatureBuilder>,
{
let inner = writer::BoxStack::from(inner);
let level = inner.cookie_ref().level + 1;
Signer {
inner: Some(inner),
signers: vec![Box::new(signer)],
intended_recipients: Vec::new(),
detached: false,
template: template.into(),
creation_time: None,
hash: HashAlgorithm::default().context().unwrap(),
cookie: Cookie {
level,
private: Private::Signer,
},
position: 0,
}
}
pub fn detached(mut self) -> Self {
self.detached = true;
self
}
pub fn add_signer<S>(mut self, signer: S) -> Self
where S: crypto::Signer + Send + Sync + 'a
{
self.signers.push(Box::new(signer));
self
}
pub fn add_intended_recipient(mut self, recipient: &Cert) -> Self {
self.intended_recipients.push(recipient.fingerprint());
self
}
pub fn hash_algo(mut self, algo: HashAlgorithm) -> Result<Self> {
self.hash = algo.context()?;
Ok(self)
}
pub fn creation_time<T: Into<SystemTime>>(mut self, creation_time: T)
-> Self
{
self.creation_time = Some(creation_time.into());
self
}
pub fn build(mut self) -> Result<Message<'a>>
{
assert!(self.signers.len() > 0, "The constructor adds a signer.");
assert!(self.inner.is_some(), "The constructor adds an inner writer.");
if ! self.detached {
for (i, keypair) in self.signers.iter().enumerate() {
let key = keypair.public();
let mut ops = OnePassSig3::new(self.template.typ());
ops.set_pk_algo(key.pk_algo());
ops.set_hash_algo(self.hash.algo());
ops.set_issuer(key.keyid());
ops.set_last(i == self.signers.len() - 1);
Packet::OnePassSig(ops.into())
.serialize(self.inner.as_mut().unwrap())?;
}
}
Ok(Message::from(Box::new(self)))
}
fn emit_signatures(&mut self) -> Result<()> {
if let Some(ref mut sink) = self.inner {
for signer in self.signers.iter_mut() {
let hash = self.hash.clone();
let mut sig = self.template.clone()
.set_signature_creation_time(
self.creation_time
.unwrap_or_else(SystemTime::now))?;
if ! self.intended_recipients.is_empty() {
sig = sig.set_intended_recipients(
self.intended_recipients.clone())?;
}
let sig = sig.sign_hash(signer.as_mut(), hash)?;
Packet::Signature(sig).serialize(sink)?;
}
}
Ok(())
}
}
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 {
if self.template.typ() == SignatureType::Text {
crate::parse::hash_update_text(&mut self.hash, &buf[..amount]);
} else {
self.hash.update(&buf[..amount]);
}
self.position += amount as u64;
}
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 (dyn writer::Stackable<'a, Cookie> + Send + Sync)> {
if let Some(ref mut i) = self.inner {
Some(i)
} else {
None
}
}
fn inner_ref(&self) -> Option<&(dyn writer::Stackable<'a, Cookie> + Send + Sync)> {
self.inner.as_ref().map(|r| r.as_ref())
}
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
}
fn position(&self) -> u64 {
self.position
}
}
pub struct LiteralWriter<'a> {
template: Literal,
inner: writer::BoxStack<'a, Cookie>,
signature_writer: Option<writer::BoxStack<'a, Cookie>>,
}
assert_send_and_sync!(LiteralWriter<'_>);
impl<'a> LiteralWriter<'a> {
pub fn new(inner: Message<'a>) -> Self {
LiteralWriter {
template: Literal::new(DataFormat::default()),
inner: writer::BoxStack::from(inner),
signature_writer: None,
}
}
pub fn format(mut self, format: DataFormat) -> Self {
self.template.set_format(format);
self
}
pub fn filename<B: AsRef<[u8]>>(mut self, filename: B) -> Result<Self> {
self.template.set_filename(filename.as_ref())?;
Ok(self)
}
pub fn date<T: Into<SystemTime>>(mut self, timestamp: T) -> Result<Self>
{
self.template.set_date(Some(timestamp.into()))?;
Ok(self)
}
pub fn build(mut self) -> Result<Message<'a>> {
let level = self.inner.cookie_ref().level + 1;
let signer_above =
if let &Cookie {
private: Private::Signer{..},
..
} = self.inner.cookie_ref() {
true
} else {
false
};
if signer_above {
let stack = self.inner.pop()?;
let stack = stack.unwrap();
self.signature_writer = Some(self.inner);
self.inner = stack;
}
CTB::new(Tag::Literal).serialize(&mut self.inner)?;
self.inner
= PartialBodyFilter::new(Message::from(self.inner),
Cookie::new(level)).into();
self.template.serialize_headers(&mut self.inner, false)?;
Ok(Message::from(Box::new(self)))
}
}
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>>> {
unreachable!("Only implemented by Signer")
}
fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unreachable!("Only implemented by Signer")
}
fn inner_ref(&self) -> Option<&(dyn writer::Stackable<'a, Cookie> + Send + Sync)> {
Some(self.inner.as_ref())
}
fn inner_mut(&mut self) -> Option<&mut (dyn writer::Stackable<'a, Cookie> + Send + Sync)> {
Some(self.inner.as_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()
}
fn position(&self) -> u64 {
self.inner.position()
}
}
pub struct Compressor<'a> {
algo: CompressionAlgorithm,
level: CompressionLevel,
inner: writer::BoxStack<'a, Cookie>,
}
assert_send_and_sync!(Compressor<'_>);
impl<'a> Compressor<'a> {
pub fn new(inner: Message<'a>) -> Self {
Self {
algo: Default::default(),
level: Default::default(),
inner: inner.into(),
}
}
pub fn algo(mut self, algo: CompressionAlgorithm) -> Self {
self.algo = algo;
self
}
pub fn level(mut self, level: CompressionLevel) -> Self {
self.level = level;
self
}
pub fn build(mut self) -> Result<Message<'a>> {
let level = self.inner.cookie_ref().level + 1;
CTB::new(Tag::CompressedData).serialize(&mut self.inner)?;
let inner: Message<'a>
= PartialBodyFilter::new(Message::from(self.inner),
Cookie::new(level));
Self::new_naked(inner, self.algo, self.level, level)
}
pub(crate) fn new_naked(mut inner: Message<'a>,
algo: CompressionAlgorithm,
compression_level: CompressionLevel,
level: usize)
-> Result<Message<'a>>
{
inner.as_mut().write_u8(algo.into())?;
let inner: Message<'a> = match algo {
CompressionAlgorithm::Uncompressed => {
let _ = compression_level;
writer::Identity::new(inner, Cookie::new(level))
},
#[cfg(feature = "compression-deflate")]
CompressionAlgorithm::Zip =>
writer::ZIP::new(inner, Cookie::new(level), compression_level),
#[cfg(feature = "compression-deflate")]
CompressionAlgorithm::Zlib =>
writer::ZLIB::new(inner, Cookie::new(level), compression_level),
#[cfg(feature = "compression-bzip2")]
CompressionAlgorithm::BZip2 =>
writer::BZ::new(inner, Cookie::new(level), compression_level),
a =>
return Err(Error::UnsupportedCompressionAlgorithm(a).into()),
};
Ok(Message::from(Box::new(Self {
algo,
level: compression_level,
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>>> {
unreachable!("Only implemented by Signer")
}
fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unreachable!("Only implemented by Signer")
}
fn inner_ref(&self) -> Option<&(dyn writer::Stackable<'a, Cookie> + Send + Sync)> {
Some(self.inner.as_ref())
}
fn inner_mut(&mut self) -> Option<&mut (dyn writer::Stackable<'a, Cookie> + Send + Sync)> {
Some(self.inner.as_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()
}
fn position(&self) -> u64 {
self.inner.position()
}
}
#[derive(Debug)]
pub struct Recipient<'a> {
keyid: KeyID,
key: &'a Key<key::PublicParts, key::UnspecifiedRole>,
}
assert_send_and_sync!(Recipient<'_>);
impl<'a, P, R> From<&'a Key<P, R>> for Recipient<'a>
where P: key::KeyParts,
R: key::KeyRole,
{
fn from(key: &'a Key<P, R>) -> Self {
Self::new(key.keyid(), key.parts_as_public().role_as_unspecified())
}
}
impl<'a, P, R, R2> From<ValidKeyAmalgamation<'a, P, R, R2>>
for Recipient<'a>
where P: key::KeyParts,
R: key::KeyRole,
R2: Copy,
{
fn from(ka: ValidKeyAmalgamation<'a, P, R, R2>) -> Self {
ka.key().into()
}
}
impl<'a> Recipient<'a> {
pub fn new<P, R>(keyid: KeyID, key: &'a Key<P, R>) -> Recipient<'a>
where P: key::KeyParts,
R: key::KeyRole,
{
Recipient {
keyid,
key: key.parts_as_public().role_as_unspecified(),
}
}
pub fn keyid(&self) -> &KeyID {
&self.keyid
}
pub fn set_keyid(mut self, keyid: KeyID) -> Self {
self.keyid = keyid;
self
}
}
pub struct Encryptor<'a> {
inner: Option<writer::BoxStack<'a, Cookie>>,
recipients: Vec<Recipient<'a>>,
passwords: Vec<Password>,
sym_algo: SymmetricAlgorithm,
aead_algo: Option<AEADAlgorithm>,
hash: Box<dyn crypto::hash::Digest>,
cookie: Cookie,
}
assert_send_and_sync!(Encryptor<'_>);
impl<'a> Encryptor<'a> {
pub fn for_recipients<R>(inner: Message<'a>, recipients: R) -> Self
where R: IntoIterator,
R::Item: Into<Recipient<'a>>,
{
Self {
inner: Some(inner.into()),
recipients: recipients.into_iter().map(|r| r.into()).collect(),
passwords: Vec::new(),
sym_algo: Default::default(),
aead_algo: Default::default(),
hash: HashAlgorithm::SHA1.context().unwrap(),
cookie: Default::default(), }
}
pub fn with_passwords<P>(inner: Message<'a>, passwords: P) -> Self
where P: IntoIterator,
P::Item: Into<Password>,
{
Self {
inner: Some(inner.into()),
recipients: Vec::new(),
passwords: passwords.into_iter().map(|p| p.into()).collect(),
sym_algo: Default::default(),
aead_algo: Default::default(),
hash: HashAlgorithm::SHA1.context().unwrap(),
cookie: Default::default(), }
}
pub fn add_recipients<R>(mut self, recipients: R) -> Self
where R: IntoIterator,
R::Item: Into<Recipient<'a>>,
{
for r in recipients {
self.recipients.push(r.into());
}
self
}
pub fn add_passwords<P>(mut self, passwords: P) -> Self
where P: IntoIterator,
P::Item: Into<Password>,
{
for p in passwords {
self.passwords.push(p.into());
}
self
}
pub fn symmetric_algo(mut self, algo: SymmetricAlgorithm) -> Self {
self.sym_algo = algo;
self
}
#[cfg(test)]
pub fn aead_algo(mut self, algo: AEADAlgorithm) -> Self {
self.aead_algo = Some(algo);
self
}
const AEAD_CHUNK_SIZE : usize = 4096;
pub fn build(mut self) -> Result<Message<'a>> {
if self.recipients.len() + self.passwords.len() == 0 {
return Err(Error::InvalidOperation(
"Neither recipients nor passwords given".into()).into());
}
struct AEADParameters {
algo: AEADAlgorithm,
chunk_size: usize,
nonce: Box<[u8]>,
}
let aead = if let Some(algo) = self.aead_algo {
let mut nonce = vec![0; algo.iv_size()?];
crypto::random(&mut nonce);
Some(AEADParameters {
algo,
chunk_size: Self::AEAD_CHUNK_SIZE,
nonce: nonce.into_boxed_slice(),
})
} else {
None
};
let mut inner = self.inner.take().expect("Added in constructors");
let level = inner.as_ref().cookie_ref().level + 1;
let sk = SessionKey::new(self.sym_algo.key_size()?);
for recipient in self.recipients.iter() {
let mut pkesk =
PKESK3::for_recipient(self.sym_algo, &sk, recipient.key)?;
pkesk.set_recipient(recipient.keyid.clone());
Packet::PKESK(pkesk.into()).serialize(&mut inner)?;
}
for password in self.passwords.iter() {
if let Some(aead) = aead.as_ref() {
let skesk = SKESK5::with_password(self.sym_algo,
self.sym_algo,
aead.algo,
Default::default(),
&sk, password).unwrap();
Packet::SKESK(skesk.into()).serialize(&mut inner)?;
} else {
let skesk = SKESK4::with_password(self.sym_algo,
self.sym_algo,
Default::default(),
&sk, password).unwrap();
Packet::SKESK(skesk.into()).serialize(&mut inner)?;
}
}
if let Some(aead) = aead {
CTB::new(Tag::AED).serialize(&mut inner)?;
let mut inner = PartialBodyFilter::new(Message::from(inner),
Cookie::new(level));
let aed = AED1::new(self.sym_algo, aead.algo,
aead.chunk_size as u64, aead.nonce)?;
aed.serialize_headers(&mut inner)?;
writer::AEADEncryptor::new(
inner.into(),
Cookie::new(level),
aed.symmetric_algo(),
aed.aead(),
aead.chunk_size,
aed.iv(),
&sk,
)
} else {
CTB::new(Tag::SEIP).serialize(&mut inner)?;
let mut inner = PartialBodyFilter::new(Message::from(inner),
Cookie::new(level));
inner.write_all(&[1])?;
self.inner = Some(writer::Encryptor::new(
inner.into(),
Cookie::new(level),
self.sym_algo,
&sk,
)?.into());
self.cookie = Cookie::new(level);
let mut iv = vec![0; self.sym_algo.block_size()?];
crypto::random(&mut iv);
self.write_all(&iv)?;
self.write_all(&iv[iv.len() - 2..])?;
Ok(Message::from(Box::new(self)))
}
}
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);
Packet::MDC(MDC::from(self.hash.clone())).serialize(&mut w)?;
let w = w.into_inner()?.unwrap();
let w = w.into_inner()?.unwrap();
Ok(w)
} else {
Err(Error::InvalidOperation(
"Inner writer already taken".into()).into())
}
}
}
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>>> {
unreachable!("Only implemented by Signer")
}
fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unreachable!("Only implemented by Signer")
}
fn inner_ref(&self) -> Option<&(dyn writer::Stackable<'a, Cookie> + Send + Sync)> {
self.inner.as_ref().map(|r| r.as_ref())
}
fn inner_mut(&mut self) -> Option<&mut (dyn writer::Stackable<'a, Cookie> + Send + Sync)> {
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
}
fn position(&self) -> u64 {
self.inner.as_ref().map(|i| i.position()).unwrap_or(0)
}
}
#[cfg(test)]
mod test {
use std::io::Read;
use crate::{Packet, PacketPile, packet::CompressedData};
use crate::parse::{Parse, PacketParserResult, PacketParser};
use super::*;
use crate::types::DataFormat::Text as T;
use crate::policy::Policy;
use crate::policy::StandardPolicy as P;
#[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(); ustr.finalize().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_eof());
}
#[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)
.algo(CompressionAlgorithm::Uncompressed).build().unwrap();
let mut ls = LiteralWriter::new(c).format(T).build().unwrap();
write!(ls, "one").unwrap();
let c = ls.finalize_one().unwrap().unwrap(); let mut ls = LiteralWriter::new(c).format(T).build().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).format(T).build().unwrap();
write!(ls, "three").unwrap();
ls.finalize().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)
.algo(CompressionAlgorithm::Uncompressed).build().unwrap();
let c = Compressor::new(c0)
.algo(CompressionAlgorithm::Uncompressed).build().unwrap();
let mut ls = LiteralWriter::new(c).format(T).build().unwrap();
write!(ls, "one").unwrap();
let c = ls.finalize_one().unwrap().unwrap();
let mut ls = LiteralWriter::new(c).format(T).build().unwrap();
write!(ls, "two").unwrap();
let c = ls.finalize_one().unwrap().unwrap();
let c0 = c.finalize_one().unwrap().unwrap();
let c = Compressor::new(c0)
.algo(CompressionAlgorithm::Uncompressed).build().unwrap();
let mut ls = LiteralWriter::new(c).format(T).build().unwrap();
write!(ls, "three").unwrap();
let c = ls.finalize_one().unwrap().unwrap();
let mut ls = LiteralWriter::new(c).format(T).build().unwrap();
write!(ls, "four").unwrap();
ls.finalize().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-bzip2")]
#[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)
.algo(CompressionAlgorithm::BZip2).build().unwrap();
let mut ls = LiteralWriter::new(c).build().unwrap();
for _ in 0 .. 16 {
ls.write_all(&zeros).unwrap();
}
}
assert!(o.len() < 1024);
}
#[test]
fn signature() {
let p = &P::new();
use crate::crypto::KeyPair;
use std::collections::HashMap;
use crate::Fingerprint;
let mut keys: HashMap<Fingerprint, key::UnspecifiedPublic> = HashMap::new();
for tsk in &[
Cert::from_bytes(crate::tests::key("testy-private.pgp")).unwrap(),
Cert::from_bytes(crate::tests::key("testy-new-private.pgp")).unwrap(),
] {
for key in tsk.keys().with_policy(p, crate::frozen_time())
.for_signing().map(|ka| ka.key())
{
keys.insert(key.fingerprint(), key.clone());
}
}
let mut o = vec![];
{
let mut signers = keys.iter().map(|(_, key)| {
key.clone().parts_into_secret().unwrap().into_keypair()
.expect("expected unencrypted secret key")
}).collect::<Vec<KeyPair>>();
let m = Message::new(&mut o);
let mut signer = Signer::new(m, signers.pop().unwrap());
for s in signers.into_iter() {
signer = signer.add_signer(s);
}
let signer = signer.build().unwrap();
let mut ls = LiteralWriter::new(signer).build().unwrap();
ls.write_all(b"Tis, tis, tis. Tis is important.").unwrap();
let _ = ls.finalize().unwrap();
}
let mut ppr = PacketParser::from_bytes(&o).unwrap();
let mut good = 0;
while let PacketParserResult::Some(mut pp) = ppr {
if let Packet::Signature(sig) = &mut pp.packet {
let key = keys.get(&sig.issuer_fingerprints().nth(0).unwrap())
.unwrap();
sig.verify(key).unwrap();
good += 1;
}
ppr = pp.recurse().unwrap().1;
}
assert_eq!(good, 2);
}
#[test]
fn encryptor() {
let passwords = vec!["streng geheim".into(),
"top secret".into()];
let message = b"Hello world.";
let mut o = vec![];
{
let m = Message::new(&mut o);
let encryptor = Encryptor::with_passwords(m, passwords.clone())
.build().unwrap();
let mut literal = LiteralWriter::new(encryptor).build()
.unwrap();
literal.write_all(message).unwrap();
literal.finalize().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.digest(), mdc.computed_digest());
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);
}
}
#[test]
fn aead_messages() -> Result<()> {
use std::cmp;
use crate::parse::{
stream::{
DecryptorBuilder,
DecryptionHelper,
VerificationHelper,
MessageStructure,
},
};
use crate::cert::prelude::*;
use crate::serialize::stream::{LiteralWriter, Message};
let (tsk, _) = CertBuilder::new()
.set_cipher_suite(CipherSuite::Cv25519)
.add_transport_encryption_subkey()
.generate().unwrap();
struct Helper<'a> {
policy: &'a dyn Policy,
tsk: &'a Cert,
};
impl<'a> VerificationHelper for Helper<'a> {
fn get_certs(&mut self, _ids: &[crate::KeyHandle])
-> Result<Vec<Cert>> {
Ok(Vec::new())
}
fn check(&mut self, _structure: MessageStructure) -> Result<()> {
Ok(())
}
}
impl<'a> DecryptionHelper for Helper<'a> {
fn decrypt<D>(&mut self, pkesks: &[PKESK], _skesks: &[SKESK],
sym_algo: Option<SymmetricAlgorithm>,
mut decrypt: D) -> Result<Option<crate::Fingerprint>>
where D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool
{
let mut keypair = self.tsk.keys().with_policy(self.policy, None)
.for_transport_encryption()
.map(|ka| ka.key()).next().unwrap()
.clone().parts_into_secret().unwrap()
.into_keypair().unwrap();
pkesks[0].decrypt(&mut keypair, sym_algo)
.map(|(algo, session_key)| decrypt(algo, &session_key));
Ok(None)
}
}
let p = &P::new();
for chunks in 0..3 {
for msg_len in
cmp::max(24, chunks * Encryptor::AEAD_CHUNK_SIZE) - 24
..chunks * Encryptor::AEAD_CHUNK_SIZE + 24
{
eprintln!("Encrypting message of size: {}", msg_len);
let mut content : Vec<u8> = Vec::new();
for i in 0..msg_len {
content.push(b'0' + ((i % 10) as u8));
}
let mut msg = vec![];
{
let m = Message::new(&mut msg);
let recipients = tsk
.keys().with_policy(p, None)
.for_storage_encryption().for_transport_encryption();
let encryptor = Encryptor::for_recipients(m, recipients)
.aead_algo(AEADAlgorithm::EAX)
.build().unwrap();
let mut literal = LiteralWriter::new(encryptor).build()
.unwrap();
literal.write_all(&content).unwrap();
literal.finalize().unwrap();
}
for &read_len in &[
37,
Encryptor::AEAD_CHUNK_SIZE - 1,
Encryptor::AEAD_CHUNK_SIZE,
100 * Encryptor::AEAD_CHUNK_SIZE
] {
for &do_err in &[ false, true ] {
let mut msg = msg.clone();
if do_err {
let l = msg.len() - 1;
if msg[l] == 0 {
msg[l] = 1;
} else {
msg[l] = 0;
}
}
let h = Helper { policy: p, tsk: &tsk };
let mut v = match DecryptorBuilder::from_bytes(&msg)?
.with_policy(p, None, h)
{
Ok(v) => v,
Err(_) if do_err => continue,
Err(err) => panic!("Decrypting message: {}", err),
};
let mut buffer = Vec::new();
buffer.resize(read_len, 0);
let mut decrypted_content = Vec::new();
loop {
match v.read(&mut buffer[..read_len]) {
Ok(0) if do_err =>
panic!("Expected an error, got EOF"),
Ok(0) => break,
Ok(len) =>
decrypted_content.extend_from_slice(
&buffer[..len]),
Err(_) if do_err => break,
Err(err) =>
panic!("Decrypting data: {:?}", err),
}
}
if do_err {
for _ in 0..3 {
assert!(v.read(&mut buffer[..read_len]).is_err());
}
}
assert_eq!(msg_len, decrypted_content.len());
assert_eq!(content, decrypted_content);
}
}
}
}
Ok(())
}
#[test]
fn signature_at_time() {
use crate::cert::prelude::*;
use crate::serialize::stream::{LiteralWriter, Message};
use crate::crypto::KeyPair;
let p = &P::new();
let (cert, _) = CertBuilder::new()
.add_signing_subkey()
.set_cipher_suite(CipherSuite::Cv25519)
.generate().unwrap();
let ka = cert.keys().with_policy(p, None).for_signing().nth(0).unwrap();
let timestamp = ka.key().creation_time()
+ std::time::Duration::from_secs(14 * 24 * 60 * 60);
assert!(ka.key().creation_time() < timestamp);
let mut o = vec![];
{
let signer_keypair : KeyPair =
ka.key().clone().parts_into_secret().unwrap().into_keypair()
.expect("expected unencrypted secret key");
let m = Message::new(&mut o);
let signer = Signer::new(m, signer_keypair);
let signer = signer.creation_time(timestamp);
let signer = signer.build().unwrap();
let mut ls = LiteralWriter::new(signer).build().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(mut pp) = ppr {
if let Packet::Signature(sig) = &mut pp.packet {
assert_eq!(sig.signature_creation_time(), Some(timestamp));
sig.verify(ka.key()).unwrap();
good += 1;
}
ppr = pp.recurse().unwrap().1;
}
assert_eq!(good, 1);
}
#[test]
fn issue_530_signing() -> Result<()> {
use std::io::Write;
use crate::*;
use crate::packet::signature;
use crate::serialize::stream::{Message, Signer};
use crate::policy::StandardPolicy;
use crate::{Result, Cert};
use crate::parse::Parse;
use crate::parse::stream::*;
let normalized_data = b"one\r\ntwo\r\nthree";
let p = &StandardPolicy::new();
let cert: Cert =
Cert::from_bytes(crate::tests::key("testy-new-private.pgp"))?;
for data in &[
&b"one\r\ntwo\r\nthree"[..], b"one\ntwo\nthree", b"one\ntwo\r\nthree", b"one\r\ntwo\nthree",
b"one\rtwo\rthree", ] {
eprintln!("{:?}", String::from_utf8(data.to_vec())?);
let signing_keypair = cert.keys().secret()
.with_policy(p, None).supported()
.alive().revoked(false).for_signing()
.nth(0).unwrap()
.key().clone().into_keypair()?;
let mut signature = vec![];
{
let message = Message::new(&mut signature);
let mut message = Signer::with_template(
message, signing_keypair,
signature::SignatureBuilder::new(SignatureType::Text)
).detached().build()?;
message.write_all(data)?;
message.finalize()?;
}
struct Helper {};
impl VerificationHelper for Helper {
fn get_certs(&mut self, _ids: &[KeyHandle]) -> Result<Vec<Cert>>
{
Ok(vec![
Cert::from_bytes(crate::tests::key("testy-new.pgp"))?])
}
fn check(&mut self, structure: MessageStructure) -> Result<()> {
for (i, layer) in structure.iter().enumerate() {
assert_eq!(i, 0);
if let MessageLayer::SignatureGroup { results } = layer
{
assert_eq!(results.len(), 1);
results[0].as_ref().unwrap();
assert!(results[0].is_ok());
return Ok(());
} else {
unreachable!();
}
}
unreachable!()
}
}
let h = Helper {};
let mut v = DetachedVerifierBuilder::from_bytes(&signature)?
.with_policy(p, None, h)?;
v.verify_bytes(data)?;
v.verify_bytes(normalized_data)?;
}
Ok(())
}
}