use ctutils::CtEq;
use noq_proto::crypto;
use rand::RngExt;
use rustls::crypto::cipher::{
AeadKey, InboundOpaqueMessage, Iv, NONCE_LEN, OutboundPlainMessage, Tls13AeadAlgorithm,
};
pub struct RustlsTokenKey {
key: [u8; 32],
aead: &'static dyn Tls13AeadAlgorithm,
}
impl RustlsTokenKey {
pub fn new(
rng: &mut impl rand::CryptoRng,
crypto_provider: &rustls::crypto::CryptoProvider,
) -> Option<Self> {
let suite = crypto_provider
.cipher_suites
.iter()
.filter_map(|suite| suite.tls13())
.next()?;
let aead = suite.aead_alg;
Some(Self {
key: rng.random(),
aead,
})
}
}
impl crypto::HandshakeTokenKey for RustlsTokenKey {
fn seal(&self, token_nonce: u128, data: &mut Vec<u8>) -> Result<(), crypto::CryptoError> {
let key = AeadKey::from(self.key);
let nonce: [u8; NONCE_LEN] = *token_nonce
.to_le_bytes()
.first_chunk()
.expect("expected u128 > 96 bit");
let iv = Iv::from(nonce);
let msg = OutboundPlainMessage {
typ: rustls::ContentType::ApplicationData,
version: rustls::ProtocolVersion::TLSv1_3,
payload: rustls::crypto::cipher::OutboundChunks::Single(&*data),
};
let out = self
.aead
.encrypter(key, iv)
.encrypt(msg, 0)
.map_err(|_| crypto::CryptoError)?;
data.clear();
data.extend(out.payload.as_ref());
Ok(())
}
fn open<'a>(
&self,
token_nonce: u128,
data: &'a mut [u8],
) -> Result<&'a [u8], crypto::CryptoError> {
let key = AeadKey::from(self.key);
let nonce: [u8; NONCE_LEN] = *token_nonce
.to_le_bytes()
.first_chunk()
.expect("expected u128 > 96 bit");
let iv = Iv::from(nonce);
let msg = InboundOpaqueMessage::new(
rustls::ContentType::ApplicationData,
rustls::ProtocolVersion::TLSv1_3,
data,
);
let plain = self
.aead
.decrypter(key, iv)
.decrypt(msg, 0)
.map_err(|_| crypto::CryptoError)?;
Ok(plain.payload)
}
}
pub(crate) struct Blake3HmacKey([u8; 32]);
impl Blake3HmacKey {
pub fn new(rng: &mut impl rand::CryptoRng) -> Self {
let mut key = [0u8; 32];
rng.fill_bytes(&mut key);
Self(key)
}
}
impl crypto::HmacKey for Blake3HmacKey {
fn sign(&self, data: &[u8], signature_out: &mut [u8]) {
signature_out.copy_from_slice(blake3::keyed_hash(&self.0, data).as_slice());
}
fn signature_len(&self) -> usize {
blake3::OUT_LEN }
fn verify(&self, data: &[u8], signature: &[u8]) -> Result<(), crypto::CryptoError> {
let reference = blake3::keyed_hash(&self.0, data);
if signature.ct_eq(reference.as_slice()).to_bool() {
Ok(())
} else {
Err(crypto::CryptoError)
}
}
}