1use crate::{Error, prf};
6use anyhow::ensure;
7use ieee80211::MacAddr;
8use mundane::hash::Sha256;
9use std::cmp::{max, min};
10use wlan_common::ie::rsn::akm::{self, Akm};
11use wlan_common::ie::rsn::cipher::Cipher;
12use wlan_fcg_crypto::hmac_utils;
13
14#[derive(Debug, Clone, PartialEq)]
18pub struct Ptk {
19 pub ptk: Vec<u8>,
20 kck_len: usize,
21 kek_len: usize,
22 tk_len: usize,
23 pub cipher: Cipher,
24 }
26
27impl Ptk {
28 pub fn from_ptk(ptk: Vec<u8>, akm: &Akm, cipher: Cipher) -> Result<Self, anyhow::Error> {
29 let kck_len = akm.kck_bytes().ok_or(Error::PtkHierarchyUnsupportedAkmError)? as usize;
30 let kek_len = akm.kek_bytes().ok_or(Error::PtkHierarchyUnsupportedAkmError)? as usize;
31 let tk_len: usize =
32 cipher.tk_bytes().ok_or(Error::PtkHierarchyUnsupportedCipherError)?.into();
33 ensure!(kck_len + kek_len + tk_len == ptk.len(), "invalid ptk length");
34 Ok(Ptk { ptk, kck_len, kek_len, tk_len, cipher })
35 }
36
37 #[allow(deprecated)]
39 pub fn new(
41 pmk: &[u8],
42 aa: &MacAddr,
43 spa: &MacAddr,
44 anonce: &[u8],
45 snonce: &[u8],
46 akm: &Akm,
47 cipher: Cipher,
48 ) -> Result<Ptk, anyhow::Error> {
49 ensure!(anonce.len() == 32 && snonce.len() == 32, Error::InvalidNonceSize(anonce.len()));
50
51 let pmk_len = akm
52 .pmk_bits()
53 .map(|bits| (bits / 8) as usize)
54 .ok_or(Error::PtkHierarchyUnsupportedAkmError)?;
55 ensure!(pmk.len() == pmk_len, Error::PtkHierarchyInvalidPmkError);
56
57 let kck_bits = akm.kck_bits().ok_or(Error::PtkHierarchyUnsupportedAkmError)?;
58 let kek_bits = akm.kek_bits().ok_or(Error::PtkHierarchyUnsupportedAkmError)?;
59 let tk_bits = cipher.tk_bits().ok_or(Error::PtkHierarchyUnsupportedCipherError)?;
60 let prf_bits = kck_bits + kek_bits + tk_bits;
61
62 let mut data: [u8; 76] = [0; 76];
64 data[0..6].copy_from_slice(&min(aa.as_slice(), spa.as_slice())[..]);
65 data[6..12].copy_from_slice(&max(aa.as_slice(), spa.as_slice())[..]);
66 data[12..44].copy_from_slice(&min(anonce, snonce)[..]);
67 data[44..].copy_from_slice(&max(anonce, snonce)[..]);
68
69 let ptk_bytes = match akm.suite_type {
72 akm::SAE | akm::OWE => hmac_utils::kdf_hash_length::<Sha256>(
73 pmk,
74 "Pairwise key expansion",
75 &data,
76 prf_bits as usize,
77 ),
78 _ => prf::prf(pmk, "Pairwise key expansion", &data, prf_bits as usize)?,
79 };
80 let ptk = Ptk {
81 ptk: ptk_bytes,
82 kck_len: (kck_bits / 8) as usize,
83 kek_len: (kek_bits / 8) as usize,
84 tk_len: (tk_bits / 8) as usize,
85 cipher,
86 };
87 Ok(ptk)
88 }
89
90 pub fn kck(&self) -> &[u8] {
91 &self.ptk[0..self.kck_len]
92 }
93
94 pub fn kek(&self) -> &[u8] {
95 let start = self.kck_len;
96 &self.ptk[start..start + self.kek_len]
97 }
98
99 pub fn tk(&self) -> &[u8] {
100 let start = self.kck_len + self.kek_len;
101 &self.ptk[start..start + self.tk_len]
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use hex::FromHex;
109 use wlan_common::ie::rsn::akm::PSK;
110 use wlan_common::ie::rsn::cipher::{CCMP_128, TKIP};
111
112 struct TestData {
113 pmk: Vec<u8>,
114 aa: MacAddr,
115 spa: MacAddr,
116 anonce: [u8; 32],
117 snonce: [u8; 32],
118 }
119
120 fn ieee_test_data() -> TestData {
122 let pmk = Vec::from_hex("0dc0d6eb90555ed6419756b9a15ec3e3209b63df707dd508d14581f8982721af")
123 .unwrap();
124 let aa = MacAddr::from(<[u8; 6]>::from_hex("a0a1a1a3a4a5").unwrap());
125 let spa = MacAddr::from(<[u8; 6]>::from_hex("b0b1b2b3b4b5").unwrap());
126 let anonce = <[u8; 32]>::from_hex(
127 "e0e1e2e3e4e5e6e7e8e9f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405",
128 )
129 .unwrap();
130 let snonce = <[u8; 32]>::from_hex(
131 "c0c1c2c3c4c5c6c7c8c9d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5",
132 )
133 .unwrap();
134 TestData { pmk, aa, spa, anonce, snonce }
135 }
136
137 fn new_ptk(data: &TestData, akm_suite: u8, cipher_suite: u8) -> Result<Ptk, anyhow::Error> {
138 let akm = Akm::new_dot11(akm_suite);
139 let cipher = Cipher::new_dot11(cipher_suite);
140 Ptk::new(&data.pmk[..], &data.aa, &data.spa, &data.anonce, &data.snonce, &akm, cipher)
141 }
142
143 #[test]
145 fn test_pairwise_key_hierarchy_ccmp() {
146 let data = ieee_test_data();
147 let ptk_result = new_ptk(&data, PSK, CCMP_128);
148 assert_eq!(ptk_result.is_ok(), true);
149
150 let expected_kck = Vec::from_hex("379f9852d0199236b94e407ce4c00ec8").unwrap();
152 let expected_kek = Vec::from_hex("47c9edc01c2c6e5b4910caddfb3e51a7").unwrap();
153 let expected_tk = Vec::from_hex("b2360c79e9710fdd58bea93deaf06599").unwrap();
154 let ptk = ptk_result.unwrap();
155 assert_eq!(ptk.kck(), &expected_kck[..]);
156 assert_eq!(ptk.kek(), &expected_kek[..]);
157 assert_eq!(ptk.tk(), &expected_tk[..]);
158 }
159
160 #[test]
162 fn test_pairwise_key_hierarchy_tkip() {
163 let data = ieee_test_data();
164 let ptk_result = new_ptk(&data, PSK, TKIP);
165 assert_eq!(ptk_result.is_ok(), true);
166
167 let expected_kck = Vec::from_hex("379f9852d0199236b94e407ce4c00ec8").unwrap();
169 let expected_kek = Vec::from_hex("47c9edc01c2c6e5b4910caddfb3e51a7").unwrap();
170 let expected_tk =
171 Vec::from_hex("b2360c79e9710fdd58bea93deaf06599db980afbc29c152855740a6ce5ae3827")
172 .unwrap();
173 let ptk = ptk_result.unwrap();
174 assert_eq!(ptk.kck(), &expected_kck[..]);
175 assert_eq!(ptk.kek(), &expected_kek[..]);
176 assert_eq!(ptk.tk(), &expected_tk[..]);
177 }
178
179 #[test]
180 fn test_pairwise_key_hierarchy_invalid_pmk() {
181 let mut data = ieee_test_data();
182 data.pmk.remove(0); let ptk_result = new_ptk(&data, PSK, CCMP_128);
184 assert_eq!(ptk_result.is_err(), true);
185 }
186
187 #[test]
188 fn test_pairwise_key_hierarchy_unsupported_akm() {
189 let data = ieee_test_data();
190 let ptk_result = new_ptk(&data, 200, CCMP_128);
191 assert_eq!(ptk_result.is_err(), true);
192 }
193
194 #[test]
195 fn test_pairwise_key_hierarchy_unsupported_cipher() {
196 let data = ieee_test_data();
197 let ptk_result = new_ptk(&data, PSK, 200);
198 assert_eq!(ptk_result.is_err(), true);
199 }
200}