#![allow(unused_imports, dead_code, unused_variables)]
use std::marker::PhantomData;
use aead::{
consts::{U10, U32},
generic_array::{typenum::Unsigned, GenericArray},
AeadCore, AeadInPlace, Key, KeyInit, KeySizeUser, Nonce, Tag,
};
use chacha20::hchacha;
use rand_core::CryptoRngCore;
use sha2::{Digest, Sha256};
use x25519_dalek::{PublicKey, ReusableSecret};
use zeroize::Zeroizing;
use crate::pairs::Pairs;
#[derive(Debug)]
pub struct PublicKeyError;
#[derive(Debug)]
pub struct EncryptionError;
type SharedKey = Zeroizing<GenericArray<u8, U32>>;
pub trait EncryptionScheme: Send {
fn public_key(&self) -> &[u8];
fn receiver_public_key(
&mut self,
receiver_index: usize,
public_key: &[u8],
) -> Result<(), PublicKeyError>;
fn encrypt(
&mut self,
associated_data: &[u8],
buffer: &mut [u8],
tail: &mut [u8],
receive: usize,
) -> Result<(), EncryptionError>;
fn decrypt(
&self,
associated_data: &[u8],
buffer: &mut [u8],
tail: &[u8],
sender: usize,
) -> Result<(), EncryptionError>;
fn overhead(&self) -> usize;
}
#[derive(Default)]
pub struct NonceCounter(u32);
impl NonceCounter {
pub fn new() -> Self {
Self(0)
}
pub fn next_nonce<S: AeadCore>(&mut self) -> Nonce<S> {
self.0 = self.0.checked_add(1).expect("nonce overflow");
let mut nonce = Nonce::<S>::default();
nonce[..4].copy_from_slice(&self.0.to_le_bytes());
nonce
}
}
pub struct AeadX25519<S> {
secret: ReusableSecret,
public_key: PublicKey,
counter: NonceCounter,
pk: Pairs<(SharedKey, PublicKey), usize>,
marker: PhantomData<S>,
}
impl<S> AeadX25519<S> {
pub fn new(rng: &mut impl CryptoRngCore) -> Self {
let secret = ReusableSecret::random_from_rng(rng);
let public_key = PublicKey::from(&secret);
Self {
secret,
public_key,
counter: NonceCounter::new(),
pk: Pairs::new(),
marker: PhantomData,
}
}
pub fn from_secret(secret: ReusableSecret) -> Self {
let public_key = PublicKey::from(&secret);
Self {
secret,
public_key,
counter: NonceCounter::new(),
pk: Pairs::new(),
marker: PhantomData,
}
}
}
impl<S> EncryptionScheme for AeadX25519<S>
where
S: AeadInPlace + KeyInit + Send,
{
fn overhead(&self) -> usize {
S::TagSize::USIZE + S::NonceSize::USIZE
}
fn encrypt(
&mut self,
associated_data: &[u8],
buffer: &mut [u8],
tail: &mut [u8],
receive: usize,
) -> Result<(), EncryptionError> {
if tail.len() != self.overhead() {
return Err(EncryptionError);
}
let (key, public_key) =
self.pk.find_pair_or_err(receive, EncryptionError)?;
let key = Zeroizing::new(
Sha256::new_with_prefix(public_key)
.chain_update(key)
.finalize(),
);
let key = Key::<S>::from_slice(key.as_slice());
let nonce = self.counter.next_nonce::<S>();
let tag = S::new(key)
.encrypt_in_place_detached(&nonce, associated_data, buffer)
.map_err(|_| EncryptionError)?;
tail[..S::TagSize::USIZE].copy_from_slice(&tag);
tail[S::TagSize::USIZE..].copy_from_slice(&nonce);
Ok(())
}
fn decrypt(
&self,
associated_data: &[u8],
buffer: &mut [u8],
tail: &[u8],
sender: usize,
) -> Result<(), EncryptionError> {
if tail.len() != self.overhead() {
return Err(EncryptionError);
}
let (key, public_key) =
self.pk.find_pair_or_err(sender, EncryptionError)?;
let key = Zeroizing::new(
Sha256::new_with_prefix(self.public_key)
.chain_update(key)
.finalize(),
);
let key = Key::<S>::from_slice(key.as_slice());
let nonce = Nonce::<S>::from_slice(&tail[S::TagSize::USIZE..]);
let tag = Tag::<S>::from_slice(&tail[..S::TagSize::USIZE]);
S::new(key)
.decrypt_in_place_detached(nonce, associated_data, buffer, tag)
.map_err(|_| EncryptionError)?;
Ok(())
}
fn public_key(&self) -> &[u8] {
self.public_key.as_bytes()
}
fn receiver_public_key(
&mut self,
receiver_index: usize,
pk: &[u8],
) -> Result<(), PublicKeyError> {
let pk: [u8; 32] = pk.try_into().map_err(|_| PublicKeyError)?;
let pk = PublicKey::from(pk);
let shared_secret = self.secret.diffie_hellman(&pk);
if !shared_secret.was_contributory() {
return Err(PublicKeyError);
}
let shared_key = Zeroizing::new(hchacha::<U10>(
GenericArray::from_slice(shared_secret.as_bytes()),
&GenericArray::default(),
));
self.pk.push(receiver_index, (shared_key, pk));
Ok(())
}
}