use crate::providers::aes_gcm_siv::Nonce96;
use bitflags::bitflags;
pub const NONCE_LEN: usize = 12; pub const TAG_LEN: usize = 16;
pub mod sc {
pub const CONTROL: u32 = 0;
pub const DATA: u32 = 1;
pub const DILATE: u32 = 2;
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RecordType { Control = 0, Data = 1, Dilate = 2 }
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Role { Initiator = 0, Responder = 1 }
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Flags: u8 {
const FIN = 0x01;
const L5_POLICY = 0x80;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SessionId(pub [u8; 16]);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SubchannelId(pub u32);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Seq(pub u64);
pub const AAD_LEN_BASE: usize = 1 + 1 + 1 + 4 + 8 + 1 + 16;
pub const AAD_LEN_WITH_CAP: usize = AAD_LEN_BASE + 16;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AAD {
pub version: u8,
pub role: Role,
pub record_type: RecordType,
pub subchannel: u32,
pub seq: u64,
pub flags: Flags,
pub session_id: [u8; 16],
pub capabilities_hash16: Option<[u8; 16]>,
}
impl AAD {
pub fn encode_into(&self, out: &mut [u8]) -> usize {
let need = if self.capabilities_hash16.is_some() { AAD_LEN_WITH_CAP } else { AAD_LEN_BASE };
assert!(out.len() >= need);
let mut i = 0;
out[i] = self.version; i += 1;
out[i] = self.role as u8; i += 1;
out[i] = self.record_type as u8; i += 1;
out[i..i+4].copy_from_slice(&self.subchannel.to_be_bytes()); i += 4;
out[i..i+8].copy_from_slice(&self.seq.to_be_bytes()); i += 8;
out[i] = self.flags.bits(); i += 1;
out[i..i+16].copy_from_slice(&self.session_id); i += 16;
if let Some(h) = self.capabilities_hash16 { out[i..i+16].copy_from_slice(&h); i += 16; }
i
}
pub fn to_bytes(&self) -> Vec<u8> { let mut v = vec![0u8; if self.capabilities_hash16.is_some(){AAD_LEN_WITH_CAP}else{AAD_LEN_BASE}]; let _ = self.encode_into(&mut v[..]); v }
}
#[inline]
pub fn pack_nonce(subchannel: u32, seq: u64) -> Nonce96 {
let mut n = [0u8; 12];
n[..4].copy_from_slice(&subchannel.to_be_bytes());
n[4..].copy_from_slice(&seq.to_be_bytes());
n
}
pub fn capabilities_hash16(cap_bytes: &[u8]) -> [u8; 16] {
use sha2::{Digest, Sha256};
let h = Sha256::digest(cap_bytes);
let mut out = [0u8; 16];
out.copy_from_slice(&h[..16]);
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nonce_layout() {
let n = pack_nonce(0x11223344, 0x0102030405060708);
assert_eq!(&n[..4], &[0x11,0x22,0x33,0x44]);
assert_eq!(&n[4..], &[0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08]);
}
#[test]
fn aad_bytes_len() {
let a = AAD { version: 1, role: Role::Initiator, record_type: RecordType::Control, subchannel: sc::CONTROL, seq: 9, flags: Flags::empty(), session_id: [0u8;16], capabilities_hash16: None };
assert_eq!(a.to_bytes().len(), AAD_LEN_BASE);
let mut a2 = a; a2.capabilities_hash16 = Some([1u8;16]);
assert_eq!(a2.to_bytes().len(), AAD_LEN_WITH_CAP);
}
}