use libwifi_macros::AddressHeader;
use crate::frame::components::*;
use byteorder::{BigEndian, WriteBytesExt};
use std::{
io::{self, Write},
time::{SystemTime, UNIX_EPOCH},
};
use super::{DataFrame, NullDataFrame};
#[derive(Clone, Debug, AddressHeader)]
pub struct QosData {
pub header: DataHeader,
pub eapol_key: Option<EapolKey>,
pub data: Vec<u8>,
}
impl DataFrame for QosData {
fn header(&self) -> &DataHeader {
&self.header
}
fn eapol_key(&self) -> &Option<EapolKey> {
&self.eapol_key
}
fn data(&self) -> &Vec<u8> {
&self.data
}
}
#[derive(Clone, Debug, AddressHeader)]
pub struct QosDataCfAck {
pub header: DataHeader,
pub eapol_key: Option<EapolKey>,
pub data: Vec<u8>,
}
impl DataFrame for QosDataCfAck {
fn header(&self) -> &DataHeader {
&self.header
}
fn eapol_key(&self) -> &Option<EapolKey> {
&self.eapol_key
}
fn data(&self) -> &Vec<u8> {
&self.data
}
}
#[derive(Clone, Debug, AddressHeader)]
pub struct QosDataCfPoll {
pub header: DataHeader,
pub eapol_key: Option<EapolKey>,
pub data: Vec<u8>,
}
impl DataFrame for QosDataCfPoll {
fn header(&self) -> &DataHeader {
&self.header
}
fn eapol_key(&self) -> &Option<EapolKey> {
&self.eapol_key
}
fn data(&self) -> &Vec<u8> {
&self.data
}
}
#[derive(Clone, Debug, AddressHeader)]
pub struct QosDataCfAckCfPoll {
pub header: DataHeader,
pub eapol_key: Option<EapolKey>,
pub data: Vec<u8>,
}
impl DataFrame for QosDataCfAckCfPoll {
fn header(&self) -> &DataHeader {
&self.header
}
fn eapol_key(&self) -> &Option<EapolKey> {
&self.eapol_key
}
fn data(&self) -> &Vec<u8> {
&self.data
}
}
#[derive(Clone, Debug, AddressHeader)]
pub struct QosCfPoll {
pub header: DataHeader,
}
impl NullDataFrame for QosCfPoll {
fn header(&self) -> &DataHeader {
&self.header
}
}
#[derive(Clone, Debug, AddressHeader)]
pub struct QosCfAckCfPoll {
pub header: DataHeader,
}
impl NullDataFrame for QosCfAckCfPoll {
fn header(&self) -> &DataHeader {
&self.header
}
}
#[derive(Clone, Debug, AddressHeader)]
pub struct QosNull {
pub header: DataHeader,
}
impl NullDataFrame for QosNull {
fn header(&self) -> &DataHeader {
&self.header
}
}
#[derive(Clone, Debug)]
pub struct KeyInformation {
pub descriptor_version: u8,
pub key_type: bool,
pub key_index: u8,
pub install: bool,
pub key_ack: bool,
pub key_mic: bool,
pub secure: bool,
pub error: bool,
pub request: bool,
pub encrypted_key_data: bool,
pub smk_message: bool,
}
#[derive(Clone, Debug)]
pub struct EapolKey {
pub protocol_version: u8,
pub timestamp: SystemTime,
pub packet_type: u8,
pub packet_length: u16,
pub descriptor_type: u8,
pub key_information: u16,
pub key_length: u16,
pub replay_counter: u64,
pub key_nonce: [u8; 32],
pub key_iv: [u8; 16],
pub key_rsc: u64,
pub key_id: u64,
pub key_mic: [u8; 16],
pub key_data_length: u16,
pub key_data: Vec<u8>,
}
impl Default for EapolKey {
fn default() -> EapolKey {
EapolKey {
protocol_version: 0,
timestamp: UNIX_EPOCH,
packet_type: 0,
packet_length: 0,
descriptor_type: 0,
key_information: 0,
key_length: 0,
replay_counter: 0,
key_nonce: [0; 32],
key_iv: [0; 16],
key_rsc: 0,
key_id: 0,
key_mic: [0; 16],
key_data_length: 0,
key_data: Vec::new(),
}
}
}
impl EapolKey {
pub fn to_bytes(&self) -> io::Result<Vec<u8>> {
let mut bytes = Vec::new();
bytes.write_u8(self.protocol_version)?;
bytes.write_u8(self.packet_type)?;
bytes.write_u16::<BigEndian>(self.packet_length)?;
bytes.write_u8(self.descriptor_type)?;
bytes.write_u16::<BigEndian>(self.key_information)?;
bytes.write_u16::<BigEndian>(self.key_length)?;
bytes.write_u64::<BigEndian>(self.replay_counter)?;
bytes.write_all(&self.key_nonce)?;
bytes.write_all(&self.key_iv)?;
bytes.write_u64::<BigEndian>(self.key_rsc)?;
bytes.write_u64::<BigEndian>(self.key_id)?;
bytes.write_all(&self.key_mic)?;
bytes.write_u16::<BigEndian>(self.key_data_length)?;
bytes.write_all(&self.key_data)?;
Ok(bytes)
}
pub fn encode(&self) -> Result<Vec<u8>, std::io::Error> {
let key_data_length = self.key_data.len() as u16;
let packet_length = 1 + 2 + 2 + 8 + 32
+ 16
+ 8 + 8 + 16
+ 2 + key_data_length;
let mut buf = Vec::new();
buf.write_u8(self.protocol_version)?;
buf.write_u8(self.packet_type)?;
buf.write_u16::<BigEndian>(packet_length)?;
buf.write_u8(self.descriptor_type)?;
buf.write_u16::<BigEndian>(self.key_information)?;
buf.write_u16::<BigEndian>(self.key_length)?;
buf.write_u64::<BigEndian>(self.replay_counter)?;
buf.extend_from_slice(&self.key_nonce);
buf.extend_from_slice(&self.key_iv);
buf.write_u64::<BigEndian>(self.key_rsc)?;
buf.write_u64::<BigEndian>(self.key_id)?;
buf.extend_from_slice(&self.key_mic);
buf.write_u16::<BigEndian>(key_data_length)?;
buf.extend_from_slice(&self.key_data);
Ok(buf)
}
pub fn parse_key_information(&self) -> KeyInformation {
KeyInformation {
descriptor_version: (self.key_information & 0x0007) as u8, key_type: (self.key_information & 0x0008) != 0, key_index: ((self.key_information & 0x0030) >> 4) as u8, install: (self.key_information & 0x0040) != 0, key_ack: (self.key_information & 0x0080) != 0, key_mic: (self.key_information & 0x0100) != 0, secure: (self.key_information & 0x0200) != 0, error: (self.key_information & 0x0400) != 0, request: (self.key_information & 0x0800) != 0, encrypted_key_data: (self.key_information & 0x1000) != 0, smk_message: (self.key_information & 0x2000) != 0, }
}
pub fn determine_key_type(&self) -> MessageType {
const KEY_TYPE: u16 = 1 << 3;
const KEY_ACK: u16 = 1 << 7;
const KEY_MIC: u16 = 1 << 8;
const SECURE: u16 = 1 << 9;
const INSTALL: u16 = 1 << 6;
if self.key_information & KEY_TYPE != 0 {
match self.key_information {
ki if ki & KEY_ACK != 0
&& ki & KEY_MIC == 0
&& ki & SECURE == 0
&& ki & INSTALL == 0 =>
{
MessageType::Message1
}
ki if ki & KEY_ACK == 0
&& ki & KEY_MIC != 0
&& ki & SECURE == 0
&& ki & INSTALL == 0 =>
{
MessageType::Message2
}
ki if ki & KEY_ACK != 0
&& ki & KEY_MIC != 0
&& ki & SECURE != 0
&& ki & INSTALL != 0 =>
{
MessageType::Message3
}
ki if ki & KEY_ACK == 0
&& ki & KEY_MIC != 0
&& ki & SECURE != 0
&& ki & INSTALL == 0 =>
{
MessageType::Message4
}
_ => MessageType::Error,
}
} else {
MessageType::GTK
}
}
pub fn pmkid(&self) -> Option<Pmkid> {
if self.determine_key_type() != MessageType::Message1 {
return None;
}
let rsnsuiteoui: [u8; 3] = [0x00, 0x0f, 0xac];
if self.key_data_length as usize == 22 {
let pmkid = Pmkid::from_bytes(&self.key_data);
if pmkid.oui == rsnsuiteoui
&& pmkid.len == 0x14
&& pmkid.oui_type == 4
&& pmkid.pmkid.iter().any(|&x| x != 0)
{
return Some(pmkid);
}
}
None
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum MessageType {
Message1,
Message2,
Message3,
Message4,
GTK,
Error,
}
impl std::fmt::Display for MessageType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MessageType::Message1 => write!(f, "Message 1"),
MessageType::Message2 => write!(f, "Message 2"),
MessageType::Message3 => write!(f, "Message 3"),
MessageType::Message4 => write!(f, "Message 4"),
MessageType::GTK => write!(f, "Group Temporal Key"),
MessageType::Error => write!(f, "Unknown Message"),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Pmkid {
pub id: u8,
pub len: u8,
pub oui: [u8; 3],
pub oui_type: u8,
pub pmkid: [u8; 16],
}
impl Pmkid {
fn from_bytes(bytes: &[u8]) -> Self {
if bytes.len() != 22 {
panic!("Invalid PMKID data length");
}
let mut pmkid = Pmkid {
id: bytes[0],
len: bytes[1],
oui: [bytes[2], bytes[3], bytes[4]],
oui_type: bytes[5],
pmkid: [0; 16],
};
pmkid.pmkid.copy_from_slice(&bytes[6..]);
pmkid
}
}