General & Crypto

This commit is contained in:
Alex Emmet 2026-06-20 15:25:36 +02:00
commit 02f94993c7
27 changed files with 1881 additions and 47 deletions

171
crypto/src/aead.rs Normal file
View file

@ -0,0 +1,171 @@
use crate::error::CryptoError;
#[cfg(any(feature = "chacha20poly1305", feature = "aes-gcm"))]
use rand_core::OsRng;
#[cfg(any(feature = "chacha20poly1305", feature = "aes-gcm"))]
use rand_core::RngCore;
pub trait AeadEncrypt {
fn encrypt(&self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>, CryptoError>;
}
pub trait AeadDecrypt {
fn decrypt(&self, ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>, CryptoError>;
}
pub trait AeadCipher: AeadEncrypt + AeadDecrypt {
fn key_size() -> usize;
}
#[cfg(feature = "chacha20poly1305")]
pub struct ChaCha20Poly1305 {
key: [u8; 32],
}
#[cfg(feature = "chacha20poly1305")]
impl ChaCha20Poly1305 {
pub fn new(key: [u8; 32]) -> Self {
Self { key }
}
}
#[cfg(feature = "chacha20poly1305")]
impl AeadEncrypt for ChaCha20Poly1305 {
fn encrypt(&self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>, CryptoError> {
use chacha20poly1305::aead::{Aead, KeyInit, Payload};
use chacha20poly1305::XChaCha20Poly1305;
use chacha20poly1305::XNonce;
let key = chacha20poly1305::Key::from_slice(&self.key);
let cipher = XChaCha20Poly1305::new(key);
let mut nonce = [0u8; 24];
OsRng.fill_bytes(&mut nonce);
let nonce_ref = XNonce::from_slice(&nonce);
let payload = Payload {
msg: plaintext,
aad,
};
let mut ciphertext = cipher
.encrypt(nonce_ref, payload)
.map_err(|_| CryptoError::EncryptionFailed)?;
let mut out = Vec::with_capacity(nonce.len() + ciphertext.len());
out.extend_from_slice(&nonce);
out.append(&mut ciphertext);
Ok(out)
}
}
#[cfg(feature = "chacha20poly1305")]
impl AeadDecrypt for ChaCha20Poly1305 {
fn decrypt(&self, ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>, CryptoError> {
use chacha20poly1305::aead::{Aead, KeyInit, Payload};
use chacha20poly1305::XChaCha20Poly1305;
use chacha20poly1305::XNonce;
if ciphertext.len() < 24 {
return Err(CryptoError::InvalidNonceLength);
}
let (nonce, ct) = ciphertext.split_at(24);
let key = chacha20poly1305::Key::from_slice(&self.key);
let cipher = XChaCha20Poly1305::new(key);
let nonce_ref = XNonce::from_slice(nonce);
let payload = Payload {
msg: ct,
aad,
};
cipher
.decrypt(nonce_ref, payload)
.map_err(|_| CryptoError::DecryptionFailed)
}
}
#[cfg(feature = "chacha20poly1305")]
impl AeadCipher for ChaCha20Poly1305 {
fn key_size() -> usize {
32
}
}
#[cfg(feature = "aes-gcm")]
pub struct Aes256Gcm {
key: [u8; 32],
}
#[cfg(feature = "aes-gcm")]
impl Aes256Gcm {
pub fn new(key: [u8; 32]) -> Self {
Self { key }
}
}
#[cfg(feature = "aes-gcm")]
impl AeadEncrypt for Aes256Gcm {
fn encrypt(&self, plaintext: &[u8], aad: &[u8]) -> Result<Vec<u8>, CryptoError> {
use aes_gcm::aead::{Aead, KeyInit, Payload};
use aes_gcm::Aes256Gcm as AesGcmInner;
use aes_gcm::Nonce;
let key = aes_gcm::Key::<AesGcmInner>::from_slice(&self.key);
let cipher = AesGcmInner::new(key);
let mut nonce = [0u8; 12];
OsRng.fill_bytes(&mut nonce);
let nonce_ref = Nonce::from_slice(&nonce);
let payload = Payload {
msg: plaintext,
aad,
};
let mut ciphertext = cipher
.encrypt(nonce_ref, payload)
.map_err(|_| CryptoError::EncryptionFailed)?;
let mut out = Vec::with_capacity(nonce.len() + ciphertext.len());
out.extend_from_slice(&nonce);
out.append(&mut ciphertext);
Ok(out)
}
}
#[cfg(feature = "aes-gcm")]
impl AeadDecrypt for Aes256Gcm {
fn decrypt(&self, ciphertext: &[u8], aad: &[u8]) -> Result<Vec<u8>, CryptoError> {
use aes_gcm::aead::{Aead, KeyInit, Payload};
use aes_gcm::Aes256Gcm as AesGcmInner;
use aes_gcm::Nonce;
if ciphertext.len() < 12 {
return Err(CryptoError::InvalidNonceLength);
}
let (nonce, ct) = ciphertext.split_at(12);
let key = aes_gcm::Key::<AesGcmInner>::from_slice(&self.key);
let cipher = AesGcmInner::new(key);
let nonce_ref = Nonce::from_slice(nonce);
let payload = Payload {
msg: ct,
aad,
};
cipher
.decrypt(nonce_ref, payload)
.map_err(|_| CryptoError::DecryptionFailed)
}
}
#[cfg(feature = "aes-gcm")]
impl AeadCipher for Aes256Gcm {
fn key_size() -> usize {
32
}
}