use std::cmp;
use std::convert::TryInto;
use std::fmt;
use std::io;
use buffered_reader::BufferedReader;
use crate::types::{
AEADAlgorithm,
SymmetricAlgorithm,
};
use crate::utils::{
write_be_u64,
};
use crate::Error;
use crate::Result;
use crate::crypto::SessionKey;
use crate::crypto::mem::secure_cmp;
use crate::seal;
use crate::parse::Cookie;
/// Disables authentication checks.
///
/// This is DANGEROUS, and is only useful for debugging problems with
/// malformed AEAD-encrypted messages.
const DANGER_DISABLE_AUTHENTICATION: bool = false;
/// Converts a chunk size to a usize.
pub(crate) fn chunk_size_usize(chunk_size: u64) -> Result<usize> {
chunk_size.try_into()
.map_err(|_| Error::InvalidOperation(
format!("AEAD chunk size exceeds size of \
virtual memory: {}", chunk_size)).into())
}
/// An AEAD mode of operation.
///
/// # Sealed trait
///
/// This trait is [sealed] and cannot be implemented for types outside this crate.
/// Therefore it can be extended in a non-breaking way.
/// If you want to implement the trait inside the crate
/// you also need to implement the `seal::Sealed` marker trait.
///
/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
pub trait Aead : seal::Sealed {
/// Adds associated data `ad`.
fn update(&mut self, ad: &[u8]);
/// Encrypts one block `src` to `dst`.
fn encrypt(&mut self, dst: &mut [u8], src: &[u8]);
/// Decrypts one block `src` to `dst`.
fn decrypt(&mut self, dst: &mut [u8], src: &[u8]);
/// Produce the digest.
fn digest(&mut self, digest: &mut [u8]);
/// Length of the digest in bytes.
fn digest_size(&self) -> usize;
}
/// Whether AEAD cipher is used for data encryption or decryption.
pub(crate) enum CipherOp {
/// Cipher is used for data encryption.
Encrypt,
/// Cipher is used for data decryption.
Decrypt,
}
impl AEADAlgorithm {
/// Returns the digest size of the AEAD algorithm.
pub fn digest_size(&self) -> Result<usize> {
use self::AEADAlgorithm::*;
match self {
// According to RFC4880bis, Section 5.16.1.
EAX => Ok(16),
// According to RFC4880bis, Section 5.16.2.
OCB => Ok(16),
_ => Err(Error::UnsupportedAEADAlgorithm(self.clone()).into()),
}
}
/// Returns the initialization vector size of the AEAD algorithm.
pub fn iv_size(&self) -> Result<usize> {
use self::AEADAlgorithm::*;
match self {
// According to RFC4880bis, Section 5.16.1.
EAX => Ok(16),
// According to RFC4880bis, Section 5.16.2, the IV is "at
// least 15 octets long". GnuPG hardcodes 15 in
// openpgp_aead_algo_info.
OCB => Ok(15),
_ => Err(Error::UnsupportedAEADAlgorithm(self.clone()).into()),
}
}
}
const AD_PREFIX_LEN: usize = 5;
/// A `Read`er for decrypting AEAD-encrypted data.
pub struct Decryptor<'a> {
// The encrypted data.
source: Box<dyn BufferedReader<Cookie> + 'a>,
sym_algo: SymmetricAlgorithm,
aead: AEADAlgorithm,
key: SessionKey,
iv: Box<[u8]>,
ad: [u8; AD_PREFIX_LEN + 8 + 8],
digest_size: usize,
chunk_size: usize,
chunk_index: u64,
bytes_decrypted: u64,
// Up to a chunk of unread data.
buffer: Vec<u8>,
}
impl<'a> Decryptor<'a> {
/// Instantiate a new AEAD decryptor.