1#![forbid(unsafe_code)]
4#![warn(unused_crate_dependencies)]
5
6use std::fmt::{Debug, Display, Formatter};
7use std::mem;
8
9use structbuf::{Packer, Unpacker};
10use zeroize::{Zeroize, ZeroizeOnDrop};
11
12pub use crate::{cmac::*, p256::*};
13
14mod cmac;
15mod p256;
16
17pub trait Codec: Sized {
19 fn pack(&self, p: &mut Packer);
21
22 #[must_use]
28 fn unpack(p: &mut Unpacker) -> Option<Self>;
29}
30
31macro_rules! u128_codec {
33 ($T:ty) => {
34 impl $crate::Codec for $T {
35 #[inline(always)]
36 fn pack(&self, p: &mut Packer) {
37 p.u128(self.0);
38 }
39
40 #[inline(always)]
41 fn unpack(p: &mut Unpacker) -> Option<Self> {
42 Some(Self(p.u128()))
43 }
44 }
45 };
46}
47
48macro_rules! ct_newtype {
50 ($T:ty) => {
51 impl subtle::ConstantTimeEq for $T {
52 #[inline(always)]
53 fn ct_eq(&self, other: &Self) -> subtle::Choice {
54 self.0.ct_eq(&other.0)
55 }
56 }
57
58 impl PartialEq for $T {
59 #[inline(always)]
60 fn eq(&self, other: &Self) -> bool {
61 bool::from(subtle::ConstantTimeEq::ct_eq(self, other))
62 }
63 }
64 };
65}
66
67#[derive(Clone, Copy, Debug)]
70#[must_use]
71#[repr(transparent)]
72pub struct Addr([u8; 7]);
73
74impl Addr {
75 #[inline]
77 pub fn from_le_bytes(is_random: bool, mut v: [u8; 6]) -> Self {
78 v.reverse();
79 let mut a = [0; 7];
80 a[0] = u8::from(is_random);
81 a[1..].copy_from_slice(&v);
82 Self(a)
83 }
84}
85
86#[derive(Clone, Copy, Debug)]
89#[must_use]
90#[repr(transparent)]
91pub struct IoCap([u8; 3]);
92
93impl IoCap {
94 #[inline(always)]
96 pub fn new(auth_req: u8, oob_data: bool, io_cap: u8) -> Self {
97 Self([auth_req, u8::from(oob_data), io_cap])
98 }
99}
100
101#[derive(Clone, Copy, Debug, Eq, PartialEq)]
103#[must_use]
104#[repr(transparent)]
105pub struct Nonce(u128);
106
107u128_codec!(Nonce);
108
109impl Nonce {
110 #[allow(clippy::new_without_default)]
116 #[inline]
117 pub fn new() -> Self {
118 use rand_core::{OsRng, RngCore};
119 let mut b = [0; mem::size_of::<u128>()];
120 OsRng.fill_bytes(b.as_mut_slice());
121 let n = u128::from_ne_bytes(b);
122 assert_ne!(n, 0);
123 Self(n)
124 }
125
126 #[inline]
129 pub fn f4(&self, u: &PublicKeyX, v: &PublicKeyX, z: u8) -> Confirm {
130 let mut m = AesCmac::new(&Key::new(self.0));
131 m.update(u.as_be_bytes())
132 .update(v.as_be_bytes())
133 .update([z]);
134 Confirm(m.finalize())
135 }
136
137 #[inline]
140 pub fn g2(&self, pkax: &PublicKeyX, pkbx: &PublicKeyX, nb: &Self) -> NumCompare {
141 let mut m = AesCmac::new(&Key::new(self.0));
142 m.update(pkax.as_be_bytes())
143 .update(pkbx.as_be_bytes())
144 .update(nb.0.to_be_bytes());
145 #[allow(clippy::cast_possible_truncation)]
146 NumCompare(m.finalize() as u32 % 1_000_000)
147 }
148}
149
150#[derive(Clone, Copy, Debug, Eq)]
152#[must_use]
153#[repr(transparent)]
154pub struct Confirm(u128);
155
156u128_codec!(Confirm);
157ct_newtype!(Confirm);
158
159#[derive(Clone, Copy, Eq, PartialEq)]
162#[must_use]
163#[repr(transparent)]
164pub struct NumCompare(u32);
165
166impl Debug for NumCompare {
167 #[inline]
168 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
169 f.debug_tuple("NumCompare")
170 .field(&format_args!("{:06}", self.0))
171 .finish()
172 }
173}
174
175impl Display for NumCompare {
176 #[inline]
177 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
178 write!(f, "{:06}", self.0)
179 }
180}
181
182#[must_use]
185#[repr(transparent)]
186pub struct MacKey(Key);
187
188debug_secret!(MacKey);
189
190impl MacKey {
191 #[inline]
194 pub fn f6(&self, n1: Nonce, n2: Nonce, r: u128, io_cap: IoCap, a1: Addr, a2: Addr) -> Check {
195 let mut m = AesCmac::new(&self.0);
196 m.update(n1.0.to_be_bytes())
197 .update(n2.0.to_be_bytes())
198 .update(r.to_be_bytes())
199 .update(io_cap.0)
200 .update(a1.0)
201 .update(a2.0);
202 Check(m.finalize())
203 }
204}
205
206#[derive(Eq, PartialEq, Zeroize, ZeroizeOnDrop, serde::Deserialize, serde::Serialize)]
208#[must_use]
209#[repr(transparent)]
210#[serde(transparent)]
211pub struct LTK(#[serde(with = "u128ser")] u128);
212
213debug_secret!(LTK);
214
215impl LTK {
216 #[inline(always)]
218 pub const fn new(k: u128) -> Self {
219 Self(k)
220 }
221}
222
223impl From<<K> for u128 {
224 #[inline(always)]
225 fn from(k: <K) -> Self {
226 k.0
227 }
228}
229
230#[derive(Clone, Copy, Debug, Eq)]
232#[must_use]
233#[repr(transparent)]
234pub struct Check(u128);
235
236u128_codec!(Check);
237ct_newtype!(Check);
238
239#[doc(hidden)]
241pub mod u128ser {
242 use std::fmt;
243
244 use serde::{de, ser};
245
246 pub fn serialize<T, S>(v: &T, s: S) -> Result<S::Ok, S::Error>
247 where
248 T: Into<u128> + Copy,
249 S: ser::Serializer,
250 {
251 use std::io::Write;
253 let mut b = std::io::Cursor::new([0_u8; 32]);
254 write!(b, "{:032X}", (*v).into()).expect("buffer overflow");
255 s.serialize_str(std::str::from_utf8(b.get_ref()).expect("invalid string"))
256 }
257
258 pub fn deserialize<'de, T, D>(d: D) -> Result<T, D::Error>
259 where
260 D: de::Deserializer<'de>,
261 T: TryFrom<u128>,
262 T::Error: fmt::Display,
263 {
264 struct U128;
265 impl de::Visitor<'_> for U128 {
266 type Value = u128;
267 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
268 f.write_str("128-bit hex string")
269 }
270 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
271 u128::from_str_radix(v, 16).map_err(de::Error::custom)
272 }
273 }
274 (d.deserialize_str(U128)).and_then(|v| T::try_from(v).map_err(de::Error::custom))
275 }
276}
277
278#[allow(clippy::unusual_byte_groupings)]
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn nonce() {
285 assert_ne!(Nonce::new(), Nonce::new());
287 }
288
289 #[test]
291 fn nonce_f4() {
292 let u = PublicKeyX::from_be_bytes(u256(
293 0x20b003d2_f297be2c_5e2c83a7_e9f9a5b9,
294 0xeff49111_acf4fddb_cc030148_0e359de6,
295 ));
296 let v = PublicKeyX::from_be_bytes(u256(
297 0x55188b3d_32f6bb9a_900afcfb_eed4e72a,
298 0x59cb9ac2_f19d7cfb_6b4fdd49_f47fc5fd,
299 ));
300 let x = Nonce(0xd5cb8454_d177733e_ffffb2ec_712baeab);
301 assert_eq!(x.f4(&u, &v, 0).0, 0xf2c916f1_07a9bd1c_f1eda1be_a974872d);
302 }
303
304 #[allow(clippy::unreadable_literal)]
306 #[test]
307 fn nonce_g2() {
308 let u = PublicKeyX::from_be_bytes(u256(
309 0x20b003d2_f297be2c_5e2c83a7_e9f9a5b9,
310 0xeff49111_acf4fddb_cc030148_0e359de6,
311 ));
312 let v = PublicKeyX::from_be_bytes(u256(
313 0x55188b3d_32f6bb9a_900afcfb_eed4e72a,
314 0x59cb9ac2_f19d7cfb_6b4fdd49_f47fc5fd,
315 ));
316 let x = Nonce(0xd5cb8454_d177733e_ffffb2ec_712baeab);
317 let y = Nonce(0xa6e8e7cc_25a75f6e_216583f7_ff3dc4cf);
318 assert_eq!(x.g2(&u, &v, &y), NumCompare(0x2f9ed5ba % 1_000_000));
319 }
320
321 #[test]
323 fn mac_key_f6() {
324 let k = MacKey(Key::new(0x2965f176_a1084a02_fd3f6a20_ce636e20));
325 let n1 = Nonce(0xd5cb8454_d177733e_ffffb2ec_712baeab);
326 let n2 = Nonce(0xa6e8e7cc_25a75f6e_216583f7_ff3dc4cf);
327 let r = 0x12a3343b_b453bb54_08da42d2_0c2d0fc8;
328 let io_cap = IoCap([0x01, 0x01, 0x02]);
329 let a1 = Addr([0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce]);
330 let a2 = Addr([0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1]);
331 let c = k.f6(n1, n2, r, io_cap, a1, a2);
332 assert_eq!(c.0, 0xe3c47398_9cd0e8c5_d26c0b09_da958f61);
333 }
334}