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::seal;
use crate::parse::Cookie;
/// Minimum AEAD chunk size.
///
/// Implementations MUST support chunk sizes down to 64B.
const MIN_CHUNK_SIZE: usize = 1 << 6; // 64B
/// Maximum AEAD chunk size.
///
/// Implementations MUST support chunk sizes up to 4MiB.
const MAX_CHUNK_SIZE: usize = 1 << 22; // 4MiB
/// Maximum size of any Nonce used by an AEAD mode.
pub const MAX_NONCE_LEN: usize = 16;
/// 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 {
/// Encrypts one chunk `src` to `dst` adding a digest.
///
/// Note: `dst` must be large enough to accommodate both the
/// ciphertext and the digest!
fn encrypt_seal(&mut self, dst: &mut [u8], src: &[u8]) -> Result<()>;
/// Length of the digest in bytes.
fn digest_size(&self) -> usize;
/// Decrypt one chunk `src` to `dst` and verify that the digest is
/// correct.
fn decrypt_verify(&mut self, dst: &mut [u8], src: &[u8]) -> Result<()>;
}
/// 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),
GCM => Ok(16),
_ => Err(Error::UnsupportedAEADAlgorithm(*self).into()),
}
}
/// Returns the nonce size of the AEAD algorithm.
pub fn nonce_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),
GCM => Ok(12),
_ => Err(Error::UnsupportedAEADAlgorithm(*self).into()),
}
}
/// Returns the initialization vector size of the AEAD algorithm.
///
/// This function is deprecated. Please use
/// [`AEADAlgorithm::nonce_size`].
#[deprecated = "Use nonce_size"]
pub fn iv_size(&self) -> Result<usize> {
self.nonce_size()
}
}
/// Schedules nonce and additional authenticated data for use with
/// each AEAD chunk.
pub trait Schedule: Send + Sync {
/// Calls `fun` with the appropriate nonce and additional
/// authenticated data.
///