pub mod aead_trait;
pub mod aes_gcm;
pub mod chacha20poly1305;
pub mod stream;
pub use aead_trait::CrabAead;
pub use aes_gcm::{AesGcm128, AesGcm256};
pub use chacha20poly1305::ChaCha20Poly1305;
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(
feature = "serde-support",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct Ciphertext {
#[cfg_attr(feature = "serde-support", serde(with = "serde_bytes_base64"))]
pub nonce: Vec<u8>,
#[cfg_attr(feature = "serde-support", serde(with = "serde_bytes_base64"))]
pub ciphertext: Vec<u8>,
#[cfg_attr(feature = "serde-support", serde(with = "serde_bytes_base64"))]
pub tag: Vec<u8>,
}
#[cfg(feature = "serde-support")]
mod serde_bytes_base64 {
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&crate::encoding::base64_encode(bytes))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
crate::encoding::base64_decode(&s).map_err(serde::de::Error::custom)
}
}
impl Ciphertext {
pub fn new(nonce: Vec<u8>, ciphertext: Vec<u8>, tag: Vec<u8>) -> Self {
Self {
nonce,
ciphertext,
tag,
}
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut result =
Vec::with_capacity(self.nonce.len() + self.ciphertext.len() + self.tag.len());
result.extend_from_slice(&self.nonce);
result.extend_from_slice(&self.ciphertext);
result.extend_from_slice(&self.tag);
result
}
pub fn from_bytes(
data: &[u8],
nonce_len: usize,
tag_len: usize,
) -> crate::errors::CrabResult<Self> {
use crate::errors::CrabError;
if data.len() < nonce_len + tag_len {
return Err(CrabError::invalid_input(format!(
"Ciphertext too short: expected at least {} bytes, got {}",
nonce_len + tag_len,
data.len()
)));
}
let nonce = data[..nonce_len].to_vec();
let ciphertext = data[nonce_len..data.len() - tag_len].to_vec();
let tag = data[data.len() - tag_len..].to_vec();
Ok(Self::new(nonce, ciphertext, tag))
}
pub fn to_base64(&self) -> String {
crate::encoding::base64_encode(&self.to_bytes())
}
pub fn from_base64(
data: &str,
nonce_len: usize,
tag_len: usize,
) -> crate::errors::CrabResult<Self> {
let bytes = crate::encoding::base64_decode(data)?;
Self::from_bytes(&bytes, nonce_len, tag_len)
}
}