use std::sync::Arc;
use anyhow::Result;
use aws_lc_rs::{
aead::{AES_256_GCM_SIV, Aad, RandomizedNonceKey},
hmac::{HMAC_SHA512, Key, sign},
};
use bon::Builder;
use getset::MutGetters;
use tokio::{net::UdpSocket, sync::mpsc::UnboundedReceiver};
use tracing::trace;
use uuid::Uuid;
#[derive(Builder, MutGetters)]
pub(crate) struct UdpSender {
id: Uuid,
#[builder(with = |key: [u8; 32]| -> Result<_> { RandomizedNonceKey::new(&AES_256_GCM_SIV, &key).map_err(Into::into) })]
rnk: RandomizedNonceKey,
#[builder(with = |key: [u8; 64]| { Key::new(HMAC_SHA512, &key) })]
hmac: Key,
socket: Arc<UdpSocket>,
rx: UnboundedReceiver<Vec<u8>>,
}
impl UdpSender {
pub(crate) async fn handle_send(&mut self) -> Result<()> {
while let Some(bytes) = self.rx.recv().await {
let packet = self.encrypt(&bytes)?;
let len = self.socket.send(&packet).await?;
trace!("Sent {len} bytes over UDP");
}
Ok(())
}
fn encrypt(&self, data: &[u8]) -> Result<Vec<u8>> {
let mut encrypted_part = self.id.as_bytes().to_vec();
encrypted_part.extend_from_slice(data);
let nonce = self
.rnk
.seal_in_place_append_tag(Aad::empty(), &mut encrypted_part)?;
let tag = sign(&self.hmac, &encrypted_part);
let tag_bytes: [u8; 64] = tag.as_ref().try_into()?;
let len = encrypted_part.len().to_be_bytes();
let mut packet = nonce.as_ref().to_vec();
packet.extend_from_slice(&tag_bytes);
packet.extend_from_slice(&len);
packet.extend_from_slice(&encrypted_part);
Ok(packet)
}
}