use core::convert::{TryFrom, TryInto};
use s2n_codec::{decoder_value, Encoder, EncoderValue};
use subtle::ConstantTimeEq;
pub const LEN: usize = 128 / 8;
#[allow(clippy::derive_hash_xor_eq)]
#[derive(Copy, Clone, Debug, Eq, Hash)]
pub struct Token([u8; LEN]);
impl Token {
pub const ZEROED: Self = Self([0; LEN]);
pub fn into_inner(self) -> [u8; LEN] {
self.0
}
}
impl From<[u8; LEN]> for Token {
fn from(bytes: [u8; LEN]) -> Self {
Self(bytes)
}
}
impl TryFrom<&[u8]> for Token {
type Error = core::array::TryFromSliceError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes = bytes.try_into()?;
Ok(Self(bytes))
}
}
impl AsRef<[u8]> for Token {
fn as_ref(&self) -> &[u8] {
&self.0[..]
}
}
impl AsMut<[u8]> for Token {
fn as_mut(&mut self) -> &mut [u8] {
self.0.as_mut()
}
}
impl PartialEq for Token {
fn eq(&self, other: &Self) -> bool {
self.0.ct_eq(&other.0).into()
}
}
decoder_value!(
impl<'a> Token {
fn decode(buffer: Buffer) -> Result<Self> {
let (value, buffer) = buffer.decode_slice(LEN)?;
let value: &[u8] = value.into_less_safe_slice();
let token = Token::try_from(value).expect("slice len already verified");
Ok((token, buffer))
}
}
);
impl EncoderValue for Token {
fn encoding_size(&self) -> usize {
LEN
}
fn encode<E: Encoder>(&self, encoder: &mut E) {
self.as_ref().encode(encoder)
}
}
pub trait Generator: 'static + Send {
const ENABLED: bool = true;
fn generate(&mut self, local_connection_id: &[u8]) -> Token;
}
#[cfg(any(test, feature = "testing"))]
pub mod testing {
use crate::{
stateless_reset,
stateless_reset::token::{Token, LEN},
};
pub const TEST_TOKEN_1: Token = Token(11111111123456578987654321u128.to_be_bytes());
pub const TEST_TOKEN_2: Token = Token(222222222123456578987654321u128.to_be_bytes());
pub const TEST_TOKEN_3: Token = Token(333333333123456578987654321u128.to_be_bytes());
pub const TEST_TOKEN_4: Token = Token(444444444123456578987654321u128.to_be_bytes());
const KEY: u8 = 123;
#[derive(Debug, Default)]
pub struct Generator();
impl stateless_reset::token::Generator for Generator {
fn generate(&mut self, connection_id: &[u8]) -> Token {
let mut token = [0; LEN];
for (index, byte) in connection_id.as_ref().iter().enumerate() {
token[index] = byte ^ KEY;
}
token.into()
}
}
}
#[cfg(test)]
mod tests {
use crate::stateless_reset::token::{testing::TEST_TOKEN_1, LEN};
#[test]
fn equality_test() {
let token_1 = TEST_TOKEN_1;
let token_2 = TEST_TOKEN_1;
assert_eq!(token_1, token_2);
for i in 0..LEN {
let mut token = TEST_TOKEN_1;
token.0[i] = !TEST_TOKEN_1.0[i];
assert_ne!(TEST_TOKEN_1, token);
}
}
}