#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
pub mod gcm;
#[cfg(feature = "alloc")]
pub mod chacha20poly1305;
#[cfg(feature = "alloc")]
pub mod xchacha20poly1305;
#[cfg(feature = "alloc")]
pub use self::gcm::Gcm;
#[cfg(feature = "alloc")]
pub use self::chacha20poly1305::ChaCha20Poly1305;
#[cfg(feature = "alloc")]
pub use self::xchacha20poly1305::XChaCha20Poly1305;
use crate::error::{Error, Result};
use crate::types::{Nonce, SecretBytes};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use rand::{CryptoRng, RngCore};
use zeroize::Zeroize;
pub trait AeadAlgorithm {
const KEY_SIZE: usize;
const TAG_SIZE: usize;
fn name() -> &'static str;
}
pub enum ChaCha20Poly1305Algorithm {}
impl AeadAlgorithm for ChaCha20Poly1305Algorithm {
const KEY_SIZE: usize = 32;
const TAG_SIZE: usize = 16;
fn name() -> &'static str {
"ChaCha20-Poly1305"
}
}
pub trait Operation<T> {
fn execute(self) -> Result<T>;
fn reset(&mut self);
}
pub trait AeadEncryptOperation<'a, A: AeadAlgorithm>: Operation<Vec<u8>> {
fn with_nonce(self, nonce: &'a Nonce<12>) -> Self;
fn with_aad(self, aad: &'a [u8]) -> Self;
fn encrypt(self, plaintext: &'a [u8]) -> Result<Vec<u8>>;
}
pub trait AeadDecryptOperation<'a, A: AeadAlgorithm>: Operation<Vec<u8>> {
fn with_nonce(self, nonce: &'a Nonce<12>) -> Self;
fn with_aad(self, aad: &'a [u8]) -> Self;
fn decrypt(self, ciphertext: &'a [u8]) -> Result<Vec<u8>>;
}
pub trait AeadCipher {
type Algorithm: AeadAlgorithm;
type Key: AsRef<[u8]> + AsMut<[u8]> + Clone + Zeroize;
fn new(key: &Self::Key) -> Result<Self>
where
Self: Sized;
fn encrypt(&self) -> impl AeadEncryptOperation<'_, Self::Algorithm>;
fn decrypt(&self) -> impl AeadDecryptOperation<'_, Self::Algorithm>;
fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Key>;
fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Nonce<12>>;
fn name() -> &'static str {
Self::Algorithm::name()
}
fn key_size() -> usize {
Self::Algorithm::KEY_SIZE
}
fn tag_size() -> usize {
Self::Algorithm::TAG_SIZE
}
}
#[cfg(feature = "alloc")]
pub struct ChaCha20Poly1305Cipher {
inner: chacha20poly1305::ChaCha20Poly1305,
}
#[cfg(feature = "alloc")]
impl AeadCipher for ChaCha20Poly1305Cipher {
type Algorithm = ChaCha20Poly1305Algorithm;
type Key = SecretBytes<32>;
fn new(key: &Self::Key) -> Result<Self> {
let mut key_array = [0u8; 32];
key_array.copy_from_slice(key.as_ref());
let inner = chacha20poly1305::ChaCha20Poly1305::new(&key_array);
Ok(Self { inner })
}
fn encrypt(&self) -> impl AeadEncryptOperation<'_, Self::Algorithm> {
ChaCha20Poly1305EncryptOperation {
cipher: self,
nonce: None,
aad: None,
}
}
fn decrypt(&self) -> impl AeadDecryptOperation<'_, Self::Algorithm> {
ChaCha20Poly1305DecryptOperation {
cipher: self,
nonce: None,
aad: None,
}
}
fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Key> {
let mut key = [0u8; 32];
rng.fill_bytes(&mut key);
Ok(SecretBytes::new(key))
}
fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Nonce<12>> {
let mut nonce = [0u8; 12];
rng.fill_bytes(&mut nonce);
Ok(Nonce::<12>::new(nonce))
}
}
#[cfg(feature = "alloc")]
pub struct ChaCha20Poly1305EncryptOperation<'a> {
cipher: &'a ChaCha20Poly1305Cipher,
nonce: Option<&'a Nonce<12>>,
aad: Option<&'a [u8]>,
}
#[cfg(feature = "alloc")]
impl Operation<Vec<u8>> for ChaCha20Poly1305EncryptOperation<'_> {
fn execute(self) -> Result<Vec<u8>> {
Err(Error::param("operation", "use encrypt method instead"))
}
fn reset(&mut self) {
self.nonce = None;
self.aad = None;
}
}
#[cfg(feature = "alloc")]
impl<'a> AeadEncryptOperation<'a, ChaCha20Poly1305Algorithm>
for ChaCha20Poly1305EncryptOperation<'a>
{
fn with_nonce(mut self, nonce: &'a Nonce<12>) -> Self {
self.nonce = Some(nonce);
self
}
fn with_aad(mut self, aad: &'a [u8]) -> Self {
self.aad = Some(aad);
self
}
fn encrypt(self, plaintext: &'a [u8]) -> Result<Vec<u8>> {
let nonce = self.nonce.ok_or_else(|| {
Error::param("nonce", "nonce is required for ChaCha20Poly1305 encryption")
})?;
self.cipher.inner.encrypt(nonce, plaintext, self.aad)
}
}
#[cfg(feature = "alloc")]
pub struct ChaCha20Poly1305DecryptOperation<'a> {
cipher: &'a ChaCha20Poly1305Cipher,
nonce: Option<&'a Nonce<12>>,
aad: Option<&'a [u8]>,
}
#[cfg(feature = "alloc")]
impl Operation<Vec<u8>> for ChaCha20Poly1305DecryptOperation<'_> {
fn execute(self) -> Result<Vec<u8>> {
Err(Error::param("operation", "use decrypt method instead"))
}
fn reset(&mut self) {
self.nonce = None;
self.aad = None;
}
}
#[cfg(feature = "alloc")]
impl<'a> AeadDecryptOperation<'a, ChaCha20Poly1305Algorithm>
for ChaCha20Poly1305DecryptOperation<'a>
{
fn with_nonce(mut self, nonce: &'a Nonce<12>) -> Self {
self.nonce = Some(nonce);
self
}
fn with_aad(mut self, aad: &'a [u8]) -> Self {
self.aad = Some(aad);
self
}
fn decrypt(self, ciphertext: &'a [u8]) -> Result<Vec<u8>> {
let nonce = self.nonce.ok_or_else(|| {
Error::param("nonce", "nonce is required for ChaCha20Poly1305 decryption")
})?;
self.cipher.inner.decrypt(nonce, ciphertext, self.aad)
}
}