Skip to main content

trouble_host/security_manager/
crypto.rs

1#![warn(missing_docs)]
2// This file contains code from Blackrock User-Mode Bluetooth LE Library (https://github.com/mxk/burble)
3
4use core::num::NonZeroU128;
5
6use aes::cipher::{BlockEncrypt, KeyInit};
7use aes::Aes128;
8use bt_hci::param::BdAddr;
9use cmac::digest;
10use p256::ecdh;
11use rand_core::{CryptoRng, RngCore};
12
13use crate::Address;
14
15/// LE Secure Connections Long Term Key.
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18#[must_use]
19#[repr(transparent)]
20pub struct LongTermKey(pub u128);
21
22impl LongTermKey {
23    /// Creates a Long Term Key from a `u128` value.
24    #[inline(always)]
25    pub const fn new(k: u128) -> Self {
26        Self(k)
27    }
28    /// Creates a Long Term Key from a `[u8; 16]` value in little endian.
29    #[inline(always)]
30    pub const fn from_le_bytes(k: [u8; 16]) -> Self {
31        Self(u128::from_le_bytes(k))
32    }
33    /// Creates a Long Term Key from a `[u8; 16]` value in little endian.
34    #[inline(always)]
35    pub const fn to_le_bytes(self) -> [u8; 16] {
36        self.0.to_le_bytes()
37    }
38
39    /// Derives a Long Term Key from a 128-bit Encryption Root (ER) and 16-bit
40    /// Diversifier (DIV) ([Vol 3] Part H, Section B.2.2).
41    ///
42    ///   LTK = d1(ER, DIV, 0)
43    #[inline]
44    pub fn from_encryption_root(er: u128, div: u16) -> Self {
45        Self(d1(er, div, 0))
46    }
47}
48
49impl From<&LongTermKey> for u128 {
50    #[inline(always)]
51    fn from(k: &LongTermKey) -> Self {
52        k.0
53    }
54}
55
56impl core::fmt::Display for LongTermKey {
57    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
58        write!(f, "{:016x}", self.0)
59    }
60}
61
62#[cfg(feature = "defmt")]
63impl defmt::Format for LongTermKey {
64    fn format(&self, fmt: defmt::Formatter) {
65        defmt::write!(fmt, "{:016x}", self.0)
66    }
67}
68
69/// Identity Resolving Key.
70#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
71#[derive(Clone, Copy, Debug, Eq, PartialEq)]
72#[must_use]
73#[repr(transparent)]
74pub struct IdentityResolvingKey(pub NonZeroU128);
75
76impl IdentityResolvingKey {
77    /// Creates an Identity Resolving Key from a `u128` value.
78    #[inline(always)]
79    pub const fn new(k: u128) -> Option<Self> {
80        match NonZeroU128::new(k) {
81            Some(k) => Some(Self(k)),
82            None => None,
83        }
84    }
85
86    /// Creates an Identity Resolving Key from a `[u8; 16]` value in little endian.
87    #[inline(always)]
88    pub const fn from_le_bytes(k: [u8; 16]) -> Option<Self> {
89        Self::new(u128::from_le_bytes(k))
90    }
91
92    /// Derives an Identity Resolving Key from a 128-bit Identity Root (IR)
93    /// ([Vol 3] Part H, Section B.2.3).
94    ///
95    ///   IRK = d1(IR, 1, 0)
96    #[inline]
97    pub fn from_identity_root(ir: u128) -> Option<Self> {
98        Self::new(d1(ir, 1, 0))
99    }
100
101    /// Returns the Identity Resolving Key as `[u8; 16]` value in little endian.
102    #[inline(always)]
103    pub const fn to_le_bytes(self) -> [u8; 16] {
104        self.0.get().to_le_bytes()
105    }
106
107    /// Generates a resolvable private address using this key.
108    ///
109    /// The generated address follows the format described in
110    /// Bluetooth Core Specification [Vol 3] Part C, Section 10.8.2.
111    pub fn generate_resolvable_address<T: RngCore + CryptoRng>(&self, rng: &mut T) -> [u8; 6] {
112        // Generate prand (24 bits with top 2 bits set to 0b01 to indicate resolvable private address)
113        let mut prand = [0u8; 3];
114        rng.fill_bytes(&mut prand);
115
116        // Set the top 2 bits to 0b01 to indicate resolvable private address
117        prand[2] &= 0b00111111; // Clear top 2 bits
118        prand[2] |= 0b01000000; // Set 2nd bit from top
119
120        // Calculate hash using ah function
121        let hash = self.ah(prand);
122
123        // Construct the address: prand || hash
124        let mut address = [0u8; 6];
125        address[3..6].copy_from_slice(&prand);
126        address[0..3].copy_from_slice(&hash);
127
128        address
129    }
130
131    /// Resolves a resolvable private address.
132    ///
133    /// Returns true if the address was generated using this IRK.
134    pub fn resolve_address(&self, address: &BdAddr) -> bool {
135        // Extract prand (top 24 bits) and hash (bottom 24 bits)
136        let mut prand = [0u8; 3];
137        prand.copy_from_slice(&address.raw()[3..6]);
138
139        // Verify the address type bits (top 2 bits should be 0b01)
140        if (prand[2] & 0b11000000) != 0b01000000 {
141            return false; // Not a resolvable private address
142        }
143
144        prand.reverse();
145
146        // Calculate local hash
147        let mut local_hash = self.ah(prand);
148        local_hash.reverse();
149
150        // Compare with the hash in the address
151        let mut address_hash = [0u8; 3];
152        address_hash.copy_from_slice(&address.raw()[0..3]);
153        local_hash == address_hash
154    }
155
156    /// Random address hash function `ah` as defined in
157    /// Bluetooth Core Specification [Vol 3] Part H, Section 2.2.2.
158    /// https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host/security-manager-specification.html#UUID-03b4d5c9-160c-658a-7aa5-d0b2230d38f1
159    fn ah(&self, r: [u8; 3]) -> [u8; 3] {
160        let mut r_prime = [0u8; 16];
161        r_prime[13..].copy_from_slice(&r);
162
163        let cipher = Aes128::new_from_slice(&self.0.get().to_be_bytes()).unwrap();
164        cipher.encrypt_block((&mut r_prime).into());
165        // Extract least significant 24 bits (3 bytes) as the result
166        r_prime[13..16].try_into().unwrap()
167    }
168}
169
170impl From<&IdentityResolvingKey> for u128 {
171    #[inline(always)]
172    fn from(k: &IdentityResolvingKey) -> Self {
173        k.0.get()
174    }
175}
176
177impl core::fmt::Display for IdentityResolvingKey {
178    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
179        write!(f, "{:016x}", self.0)
180    }
181}
182
183#[cfg(feature = "defmt")]
184impl defmt::Format for IdentityResolvingKey {
185    fn format(&self, fmt: defmt::Formatter) {
186        defmt::write!(fmt, "{:016x}", self.0)
187    }
188}
189
190/// RFC-4493 AES-CMAC ([Vol 3] Part H, Section 2.2.5).
191#[derive(Debug)]
192#[repr(transparent)]
193pub struct AesCmac(cmac::Cmac<aes::Aes128>);
194
195impl AesCmac {
196    /// Creates new AES-CMAC state using key `k`.
197    #[inline(always)]
198    #[must_use]
199    pub(super) fn new(k: &Key) -> Self {
200        Self(digest::KeyInit::new(&k.0))
201    }
202
203    /// Creates new AES-CMAC state using an all-zero key for GAP database hash
204    /// calculation ([Vol 3] Part G, Section 7.3.1).
205    #[inline(always)]
206    #[must_use]
207    pub fn db_hash() -> Self {
208        Self::new(&Key::new(0))
209    }
210
211    /// Updates CMAC state.
212    #[inline(always)]
213    pub fn update(&mut self, b: impl AsRef<[u8]>) -> &mut Self {
214        digest::Update::update(&mut self.0, b.as_ref());
215        self
216    }
217
218    /// Computes the final MAC value.
219    #[inline(always)]
220    #[must_use]
221    pub fn finalize(self) -> u128 {
222        u128::from_be_bytes(*digest::FixedOutput::finalize_fixed(self.0).as_ref())
223    }
224
225    /// Computes the final MAC value for use as a future key and resets the
226    /// state.
227    #[inline(always)]
228    pub(super) fn finalize_key(&mut self) -> Key {
229        // Best effort to avoid leaving copies
230        let mut k = Key::new(0);
231        digest::FixedOutputReset::finalize_into_reset(&mut self.0, &mut k.0);
232        k
233    }
234}
235
236/// LE Secure Connections check value generated by [`MacKey::f6`].
237#[derive(Clone, Copy, Debug, PartialEq, Eq)]
238#[must_use]
239#[repr(transparent)]
240pub struct Check(pub u128);
241
242#[derive(Clone, Copy)]
243#[repr(transparent)]
244pub(super) struct Key(aes::cipher::Key<aes::Aes128>);
245
246impl Key {
247    /// Creates a key from a `u128` value.
248    #[inline(always)]
249    pub fn new(k: u128) -> Self {
250        Self(k.to_be_bytes().into())
251    }
252}
253
254impl From<&Key> for u128 {
255    #[inline(always)]
256    fn from(k: &Key) -> Self {
257        Self::from_be_bytes(k.0.into())
258    }
259}
260
261/// Concatenated `AuthReq`, OOB data flag, and IO capability parameters used by
262/// [`MacKey::f6`] function ([Vol 3] Part H, Section 2.2.8).
263#[repr(transparent)]
264#[derive(Clone, Copy, Debug)]
265pub struct IoCap(pub(crate) [u8; 3]);
266
267impl IoCap {
268    /// Creates new `IoCap` parameter.
269    #[inline(always)]
270    pub fn new(auth_req: u8, oob_data: bool, io_cap: u8) -> Self {
271        Self([auth_req, u8::from(oob_data), io_cap])
272    }
273}
274
275/// 128-bit key used to compute LE Secure Connections check value
276/// ([Vol 3] Part H, Section 2.2.8).
277#[derive(Clone, Copy)]
278#[must_use]
279#[repr(transparent)]
280pub struct MacKey(Key);
281
282impl core::fmt::Debug for MacKey {
283    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
284        f.debug_tuple("MacKey").field(&"***").finish()
285    }
286}
287
288#[cfg(feature = "defmt")]
289impl defmt::Format for MacKey {
290    fn format(&self, fmt: defmt::Formatter) {
291        defmt::write!(fmt, "MacKey(***)");
292    }
293}
294
295impl MacKey {
296    /// Generates LE Secure Connections check value
297    /// ([Vol 3] Part H, Section 2.2.8).
298    #[inline]
299    pub fn f6(&self, n1: Nonce, n2: Nonce, r: u128, io_cap: IoCap, a1: Address, a2: Address) -> Check {
300        let mut m = AesCmac::new(&self.0);
301        m.update(n1.0.to_be_bytes())
302            .update(n2.0.to_be_bytes())
303            .update(r.to_be_bytes())
304            .update(io_cap.0)
305            .update(a1.to_bytes())
306            .update(a2.to_bytes());
307        Check(m.finalize())
308    }
309}
310
311/// 128-bit random nonce value ([Vol 3] Part H, Section 2.3.5.6).
312#[derive(Clone, Copy, Debug, Eq, PartialEq)]
313#[cfg_attr(feature = "defmt", derive(defmt::Format))]
314#[repr(transparent)]
315pub struct Nonce(pub u128);
316
317impl Nonce {
318    /// Generates a new non-zero random nonce value from the OS CSPRNG.
319    ///
320    /// # Panics
321    ///
322    /// Panics if the OS CSPRNG is broken.
323    #[allow(clippy::new_without_default)]
324    #[inline]
325    pub fn new<T: RngCore>(rng: &mut T) -> Self {
326        let mut b = [0; core::mem::size_of::<u128>()];
327        rng.fill_bytes(b.as_mut_slice());
328        let n = u128::from_ne_bytes(b);
329        assert_ne!(n, 0);
330        Self(n)
331    }
332
333    /// Generates LE Secure Connections confirm value
334    /// ([Vol 3] Part H, Section 2.2.6).
335    #[inline]
336    pub fn f4(&self, u: &PublicKeyX, v: &PublicKeyX, z: u8) -> Confirm {
337        let mut m = AesCmac::new(&Key::new(self.0));
338        m.update(u.as_be_bytes()).update(v.as_be_bytes()).update([z]);
339        Confirm(m.finalize())
340    }
341
342    /// Generates LE Secure Connections numeric comparison value
343    /// ([Vol 3] Part H, Section 2.2.9).
344    #[inline]
345    pub fn g2(&self, pkax: &PublicKeyX, pkbx: &PublicKeyX, nb: &Self) -> NumCompare {
346        let mut m = AesCmac::new(&Key::new(self.0));
347        m.update(pkax.as_be_bytes())
348            .update(pkbx.as_be_bytes())
349            .update(nb.0.to_be_bytes());
350        #[allow(clippy::cast_possible_truncation)]
351        NumCompare(m.finalize() as u32 % 1_000_000)
352    }
353}
354
355/// LE Secure Connections confirm value generated by [`Nonce::f4`].
356#[derive(Clone, Copy, Debug, PartialEq, Eq)]
357#[cfg_attr(feature = "defmt", derive(defmt::Format))]
358#[must_use]
359#[repr(transparent)]
360pub struct Confirm(pub u128);
361
362/// 6-digit LE Secure Connections numeric comparison value generated by
363/// [`Nonce::g2`].
364#[derive(Clone, Copy, Eq, PartialEq, Debug)]
365#[cfg_attr(feature = "defmt", derive(defmt::Format))]
366#[must_use]
367#[repr(transparent)]
368pub struct NumCompare(pub u32);
369
370/// P-256 elliptic curve secret key.
371#[derive(Clone)]
372#[must_use]
373#[repr(transparent)]
374pub struct SecretKey(p256::NonZeroScalar);
375
376impl core::fmt::Debug for SecretKey {
377    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
378        f.debug_tuple("SecretKey").field(&"***").finish()
379    }
380}
381
382#[cfg(feature = "defmt")]
383impl defmt::Format for SecretKey {
384    fn format(&self, fmt: defmt::Formatter) {
385        defmt::write!(fmt, "SecretKey(***)");
386    }
387}
388
389impl SecretKey {
390    /// Generates a new random secret key.
391    #[allow(clippy::new_without_default)]
392    #[inline(always)]
393    pub fn new<T: RngCore + CryptoRng>(rng: &mut T) -> Self {
394        Self(p256::NonZeroScalar::random(rng))
395    }
396
397    /// Computes the associated public key.
398    pub fn public_key(&self) -> PublicKey {
399        use p256::elliptic_curve::sec1::Coordinates::Uncompressed;
400        use p256::elliptic_curve::sec1::ToEncodedPoint;
401        let p = p256::PublicKey::from_secret_scalar(&self.0).to_encoded_point(false);
402        match p.coordinates() {
403            Uncompressed { x, y } => PublicKey {
404                x: PublicKeyX(Coord(*x.as_ref())),
405                y: Coord(*y.as_ref()),
406            },
407            _ => unreachable!("invalid secret key"),
408        }
409    }
410
411    /// Computes a shared secret from the local secret key and remote public
412    /// key. Returns [`None`] if the public key is either invalid or derived
413    /// from the same secret key ([Vol 3] Part H, Section 2.3.5.6.1).
414    #[must_use]
415    pub fn dh_key(&self, pk: PublicKey) -> Option<DHKey> {
416        use p256::elliptic_curve::sec1::FromEncodedPoint;
417        if pk.is_debug() {
418            return None; // TODO: Compile-time option for debug-only mode
419        }
420
421        let (x, y) = (&pk.x.0 .0.into(), &pk.y.0.into());
422        let rep = p256::EncodedPoint::from_affine_coordinates(x, y, false);
423        let lpk = p256::PublicKey::from_secret_scalar(&self.0);
424        // Constant-time ops not required:
425        // https://github.com/RustCrypto/traits/issues/1227
426        let rpk = Option::from(p256::PublicKey::from_encoded_point(&rep)).unwrap_or(lpk);
427        (rpk != lpk).then(|| DHKey(ecdh::diffie_hellman(&self.0, rpk.as_affine())))
428    }
429}
430
431/// P-256 elliptic curve public key ([Vol 3] Part H, Section 3.5.6).
432#[derive(Clone, Copy, Debug, Eq, PartialEq)]
433#[cfg_attr(feature = "defmt", derive(defmt::Format))]
434#[must_use]
435pub struct PublicKey {
436    pub x: PublicKeyX,
437    pub y: Coord,
438}
439
440impl PublicKey {
441    pub fn from_bytes(bytes: &[u8]) -> Self {
442        let mut x = [0u8; 32];
443        let mut y = [0u8; 32];
444
445        x.copy_from_slice(&bytes[..32]);
446        y.copy_from_slice(&bytes[32..]);
447
448        x.reverse();
449        y.reverse();
450
451        Self {
452            x: PublicKeyX(Coord(x)),
453            y: Coord(y),
454        }
455    }
456
457    /// Returns the public key X coordinate.
458    #[inline(always)]
459    pub const fn x(&self) -> &PublicKeyX {
460        &self.x
461    }
462
463    /// Returns whether `self` is the debug public key
464    /// ([Vol 3] Part H, Section 2.3.5.6.1).
465    #[allow(clippy::unreadable_literal)]
466    #[allow(clippy::unusual_byte_groupings)]
467    fn is_debug(&self) -> bool {
468        let (x, y) = (&self.x.0 .0, &self.y.0);
469        x[..16] == u128::to_be_bytes(0x20b003d2_f297be2c_5e2c83a7_e9f9a5b9)
470            && x[16..] == u128::to_be_bytes(0xeff49111_acf4fddb_cc030148_0e359de6)
471            && y[..16] == u128::to_be_bytes(0xdc809c49_652aeb6d_63329abf_5a52155c)
472            && y[16..] == u128::to_be_bytes(0x766345c2_8fed3024_741c8ed0_1589d28b)
473    }
474}
475
476/// 256-bit elliptic curve coordinate in big-endian byte order.
477#[derive(Clone, Copy, Debug, Eq, PartialEq)]
478#[cfg_attr(feature = "defmt", derive(defmt::Format))]
479#[repr(transparent)]
480pub struct Coord([u8; 256 / u8::BITS as usize]);
481
482impl Coord {
483    /// Returns the coordinate in big-endian byte order.
484    #[inline(always)]
485    pub(super) const fn as_be_bytes(&self) -> &[u8; core::mem::size_of::<Self>()] {
486        &self.0
487    }
488}
489
490/// P-256 elliptic curve public key affine X coordinate.
491#[derive(Clone, Copy, Debug, Eq, PartialEq)]
492#[cfg_attr(feature = "defmt", derive(defmt::Format))]
493#[must_use]
494#[repr(transparent)]
495pub struct PublicKeyX(Coord);
496
497impl PublicKeyX {
498    /// Creates the coordinate from a big-endian encoded byte array.
499    #[cfg(test)]
500    #[inline]
501    pub(super) const fn from_be_bytes(x: [u8; core::mem::size_of::<Self>()]) -> Self {
502        Self(Coord(x))
503    }
504
505    /// Returns the coordinate in big-endian byte order.
506    #[inline(always)]
507    pub(super) const fn as_be_bytes(&self) -> &[u8; core::mem::size_of::<Self>()] {
508        &self.0 .0
509    }
510}
511
512/// P-256 elliptic curve shared secret ([Vol 3] Part H, Section 2.3.5.6.1).
513#[must_use]
514#[repr(transparent)]
515pub struct DHKey(ecdh::SharedSecret);
516
517impl Clone for DHKey {
518    fn clone(&self) -> Self {
519        Self(ecdh::SharedSecret::from(*self.0.raw_secret_bytes()))
520    }
521}
522
523impl core::fmt::Debug for DHKey {
524    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
525        f.debug_tuple("DHKey").field(&"***").finish()
526    }
527}
528
529#[cfg(feature = "defmt")]
530impl defmt::Format for DHKey {
531    fn format(&self, fmt: defmt::Formatter) {
532        defmt::write!(fmt, "DHKey(***)");
533    }
534}
535
536impl DHKey {
537    /// Generates LE Secure Connections `MacKey` and `LTK`
538    /// ([Vol 3] Part H, Section 2.2.7).
539    #[inline]
540    pub fn f5(&self, n1: Nonce, n2: Nonce, a1: Address, a2: Address) -> (MacKey, LongTermKey) {
541        let n1 = n1.0.to_be_bytes();
542        let n2 = n2.0.to_be_bytes();
543        let half = |m: &mut AesCmac, counter: u8| {
544            m.update([counter])
545                .update(b"btle")
546                .update(n1)
547                .update(n2)
548                .update(a1.to_bytes())
549                .update(a2.to_bytes())
550                .update(256_u16.to_be_bytes())
551                .finalize_key()
552        };
553        let mut m = AesCmac::new(&Key::new(0x6C88_8391_AAF5_A538_6037_0BDB_5A60_83BE));
554        m.update(self.0.raw_secret_bytes());
555        let mut m = AesCmac::new(&m.finalize_key());
556        (MacKey(half(&mut m, 0)), LongTermKey(u128::from(&half(&mut m, 1))))
557    }
558}
559
560#[cfg(feature = "legacy-pairing")]
561#[allow(clippy::too_many_arguments)]
562/// Confirm value generation function `c1` for LE Legacy Pairing
563/// ([Vol 3] Part H, Section 2.2.3).
564///
565/// Uses two rounds of AES-128 with XOR combining:
566///   c1(k, r, preq, pres, iat, ia, rat, ra) = e(k, e(k, r XOR p1) XOR p2)
567/// where:
568///   p1 = pres || preq || rat || iat
569///   p2 = padding || ia || ra
570///
571/// - `preq`/`pres`: 7 bytes each in wire order (command code at index 0)
572/// - `iat`/`rat`: address type (0=public, 1=random)
573/// - `ia`/`ra`: 6-byte address in MSO order (reversed from BdAddr raw)
574pub(super) fn c1(
575    k: u128,
576    r: u128,
577    preq: &[u8; 7],
578    pres: &[u8; 7],
579    iat: u8,
580    ia: &[u8; 6],
581    rat: u8,
582    ra: &[u8; 6],
583) -> u128 {
584    // p1 = pres || preq || rat || iat (MSO to LSO, 16 bytes)
585    // preq/pres are treated as LE integers in the concatenation, so the wire-order
586    // bytes must be reversed to place the most significant byte at the MSO position.
587    let mut pres_rev = *pres;
588    pres_rev.reverse();
589    let mut preq_rev = *preq;
590    preq_rev.reverse();
591
592    let mut p1 = [0u8; 16];
593    p1[0..7].copy_from_slice(&pres_rev);
594    p1[7..14].copy_from_slice(&preq_rev);
595    p1[14] = rat;
596    p1[15] = iat;
597
598    // p2 = padding(4) || ia(6) || ra(6) (MSO to LSO)
599    let mut p2 = [0u8; 16];
600    p2[4..10].copy_from_slice(ia);
601    p2[10..16].copy_from_slice(ra);
602
603    let cipher = Aes128::new_from_slice(&k.to_be_bytes()).unwrap();
604
605    // e(k, r XOR p1)
606    let r_bytes = r.to_be_bytes();
607    let mut block = [0u8; 16];
608    for i in 0..16 {
609        block[i] = r_bytes[i] ^ p1[i];
610    }
611    cipher.encrypt_block((&mut block).into());
612
613    // e(k, result XOR p2)
614    for i in 0..16 {
615        block[i] ^= p2[i];
616    }
617    cipher.encrypt_block((&mut block).into());
618
619    u128::from_be_bytes(block)
620}
621
622#[cfg(feature = "legacy-pairing")]
623/// Short Term Key (STK) generation function `s1` for LE Legacy Pairing
624/// ([Vol 3] Part H, Section 2.2.4).
625///
626///   s1(k, r1, r2) = e(k, r1' || r2')
627/// where r1' and r2' are the least significant 64 bits of r1 and r2.
628pub(super) fn s1(k: u128, r1: u128, r2: u128) -> u128 {
629    let r1_bytes = r1.to_be_bytes();
630    let r2_bytes = r2.to_be_bytes();
631
632    // r1' = r1[63:0] = least significant 8 bytes (bytes [8..16] in big-endian)
633    // r2' = r2[63:0] = least significant 8 bytes
634    let mut r_prime = [0u8; 16];
635    r_prime[0..8].copy_from_slice(&r1_bytes[8..16]);
636    r_prime[8..16].copy_from_slice(&r2_bytes[8..16]);
637
638    let cipher = Aes128::new_from_slice(&k.to_be_bytes()).unwrap();
639    cipher.encrypt_block((&mut r_prime).into());
640
641    u128::from_be_bytes(r_prime)
642}
643
644/// Diversifying function `d1` ([Vol 3] Part H, Section B.2.1).
645///
646///   d1(k, d, r) = e(k, d')
647/// where d' = padding(96) || r || d, with the least significant octet of `d`
648/// becoming the least significant octet of `d'`.
649pub(super) fn d1(k: u128, d: u16, r: u16) -> u128 {
650    let mut d_prime = [0u8; 16];
651    d_prime[12..14].copy_from_slice(&r.to_be_bytes());
652    d_prime[14..16].copy_from_slice(&d.to_be_bytes());
653
654    let cipher = Aes128::new_from_slice(&k.to_be_bytes()).unwrap();
655    cipher.encrypt_block((&mut d_prime).into());
656
657    u128::from_be_bytes(d_prime)
658}
659
660/// Combines `hi` and `lo` values into a big-endian byte array.
661#[allow(clippy::redundant_pub_crate)]
662#[cfg(test)]
663pub(super) fn u256<T: From<[u8; 32]>>(hi: u128, lo: u128) -> T {
664    let mut b = [0; 32];
665    b[..16].copy_from_slice(&hi.to_be_bytes());
666    b[16..].copy_from_slice(&lo.to_be_bytes());
667    T::from(b)
668}
669
670#[allow(clippy::unreadable_literal)]
671#[allow(clippy::unusual_byte_groupings)]
672#[cfg(test)]
673mod tests {
674    use p256::elliptic_curve::rand_core::OsRng;
675
676    use super::*;
677    extern crate std;
678    use bt_hci::param::{AddrKind, BdAddr};
679
680    #[test]
681    fn sizes() {
682        assert_eq!(core::mem::size_of::<Coord>(), 32);
683        assert_eq!(core::mem::size_of::<PublicKey>(), 64);
684        assert_eq!(core::mem::size_of::<SecretKey>(), 32);
685        assert_eq!(core::mem::size_of::<DHKey>(), 32);
686    }
687
688    /// Debug mode key ([Vol 3] Part H, Section 2.3.5.6.1).
689    #[test]
690    fn debug_key() {
691        let sk = secret_key(
692            0x3f49f6d4_a3c55f38_74c9b3e3_d2103f50,
693            0x4aff607b_eb40b799_5899b8a6_cd3c1abd,
694        );
695        let pk = PublicKey {
696            x: PublicKeyX(Coord(u256(
697                0x20b003d2_f297be2c_5e2c83a7_e9f9a5b9,
698                0xeff49111_acf4fddb_cc030148_0e359de6,
699            ))),
700            y: Coord(u256(
701                0xdc809c49_652aeb6d_63329abf_5a52155c,
702                0x766345c2_8fed3024_741c8ed0_1589d28b,
703            )),
704        };
705        assert_eq!(sk.public_key(), pk);
706        assert!(pk.is_debug());
707    }
708
709    /// P-256 data set 1 ([Vol 2] Part G, Section 7.1.2.1).
710    #[test]
711    fn p256_1() {
712        let (ska, skb) = (
713            secret_key(
714                0x3f49f6d4_a3c55f38_74c9b3e3_d2103f50,
715                0x4aff607b_eb40b799_5899b8a6_cd3c1abd,
716            ),
717            secret_key(
718                0x55188b3d_32f6bb9a_900afcfb_eed4e72a,
719                0x59cb9ac2_f19d7cfb_6b4fdd49_f47fc5fd,
720            ),
721        );
722        let (pka, pkb) = (
723            PublicKey {
724                x: PublicKeyX(Coord(u256(
725                    0x20b003d2_f297be2c_5e2c83a7_e9f9a5b9,
726                    0xeff49111_acf4fddb_cc030148_0e359de6,
727                ))),
728                y: Coord(u256(
729                    0xdc809c49_652aeb6d_63329abf_5a52155c,
730                    0x766345c2_8fed3024_741c8ed0_1589d28b,
731                )),
732            },
733            PublicKey {
734                x: PublicKeyX(Coord(u256(
735                    0x1ea1f0f0_1faf1d96_09592284_f19e4c00,
736                    0x47b58afd_8615a69f_559077b2_2faaa190,
737                ))),
738                y: Coord(u256(
739                    0x4c55f33e_429dad37_7356703a_9ab85160,
740                    0x472d1130_e28e3676_5f89aff9_15b1214a,
741                )),
742            },
743        );
744        let dh_key = shared_secret(
745            0xec0234a3_57c8ad05_341010a6_0a397d9b,
746            0x99796b13_b4f866f1_868d34f3_73bfa698,
747        );
748        assert_eq!(ska.public_key(), pka);
749        assert_eq!(skb.public_key(), pkb);
750        assert_eq!(
751            ska.dh_key(pkb).unwrap().0.raw_secret_bytes(),
752            dh_key.0.raw_secret_bytes()
753        );
754
755        assert!(!pkb.is_debug());
756        assert!(skb.dh_key(pkb).is_none());
757    }
758
759    /// P-256 data set 2 ([Vol 2] Part G, Section 7.1.2.2).
760    #[test]
761    fn p256_2() {
762        let (ska, skb) = (
763            secret_key(
764                0x06a51669_3c9aa31a_6084545d_0c5db641,
765                0xb48572b9_7203ddff_b7ac73f7_d0457663,
766            ),
767            secret_key(
768                0x529aa067_0d72cd64_97502ed4_73502b03,
769                0x7e8803b5_c60829a5_a3caa219_505530ba,
770            ),
771        );
772        let (pka, pkb) = (
773            PublicKey {
774                x: PublicKeyX(Coord(u256(
775                    0x2c31a47b_5779809e_f44cb5ea_af5c3e43,
776                    0xd5f8faad_4a8794cb_987e9b03_745c78dd,
777                ))),
778                y: Coord(u256(
779                    0x91951218_3898dfbe_cd52e240_8e43871f,
780                    0xd0211091_17bd3ed4_eaf84377_43715d4f,
781                )),
782            },
783            PublicKey {
784                x: PublicKeyX(Coord(u256(
785                    0xf465e43f_f23d3f1b_9dc7dfc0_4da87581,
786                    0x84dbc966_204796ec_cf0d6cf5_e16500cc,
787                ))),
788                y: Coord(u256(
789                    0x0201d048_bcbbd899_eeefc424_164e33c2,
790                    0x01c2b010_ca6b4d43_a8a155ca_d8ecb279,
791                )),
792            },
793        );
794        let dh_key = shared_secret(
795            0xab85843a_2f6d883f_62e5684b_38e30733,
796            0x5fe6e194_5ecd1960_4105c6f2_3221eb69,
797        );
798        assert_eq!(ska.public_key(), pka);
799        assert_eq!(skb.public_key(), pkb);
800        assert_eq!(
801            ska.dh_key(pkb).unwrap().0.raw_secret_bytes(),
802            dh_key.0.raw_secret_bytes()
803        );
804    }
805
806    /// Key generation function ([Vol 3] Part H, Section D.3).
807    #[test]
808    fn dh_key_f5() {
809        let w = shared_secret(
810            0xec0234a3_57c8ad05_341010a6_0a397d9b,
811            0x99796b13_b4f866f1_868d34f3_73bfa698,
812        );
813        let n1 = Nonce(0xd5cb8454_d177733e_ffffb2ec_712baeab);
814        let n2 = Nonce(0xa6e8e7cc_25a75f6e_216583f7_ff3dc4cf);
815        let a1 = Address::new(AddrKind::PUBLIC, BdAddr::new([0xce, 0xbf, 0x37, 0x37, 0x12, 0x56]));
816        let a2 = Address::new(AddrKind::PUBLIC, BdAddr::new([0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7]));
817        let (mk, ltk) = w.f5(n1, n2, a1, a2);
818        assert_eq!(ltk.0, 0x69867911_69d7cd23_980522b5_94750a38);
819        assert_eq!(u128::from(&mk.0), 0x2965f176_a1084a02_fd3f6a20_ce636e20);
820    }
821
822    #[inline]
823    fn secret_key(hi: u128, lo: u128) -> SecretKey {
824        SecretKey(p256::NonZeroScalar::from_repr(u256(hi, lo)).unwrap())
825    }
826
827    #[inline]
828    fn shared_secret(hi: u128, lo: u128) -> DHKey {
829        DHKey(ecdh::SharedSecret::from(u256::<p256::FieldBytes>(hi, lo)))
830    }
831
832    #[test]
833    fn testtest() {
834        let skb = SecretKey::new(&mut OsRng::default());
835        let _pkb = skb.public_key();
836
837        let ska = SecretKey::new(&mut OsRng::default());
838        let pka = ska.public_key();
839
840        let _dh_key = skb.dh_key(pka).unwrap();
841    }
842
843    #[test]
844    fn testtest2() {
845        let bytes = [
846            0x1eu8, 0x3b, 0x26, 0x40, 0x0e, 0xba, 0x72, 0x51, 0x81, 0xf9, 0x3d, 0x16, 0xb3, 0xc4, 0x11, 0x55, 0x3f,
847            0xa8, 0x88, 0x47, 0x08, 0x1c, 0x4a, 0x42, 0x88, 0xbb, 0x68, 0x1d, 0x93, 0xe5, 0xab, 0xb3, 0x72, 0xfa, 0x93,
848            0xb4, 0xa0, 0xfe, 0x3f, 0x83, 0x9c, 0x85, 0x5b, 0x5f, 0xb6, 0x30, 0x09, 0x85, 0x47, 0xfd, 0xa8, 0xfa, 0x11,
849            0x71, 0xe4, 0x95, 0x17, 0x71, 0x98, 0x82, 0x8f, 0xf8, 0x79, 0x94,
850        ];
851
852        let skb = SecretKey::new(&mut OsRng::default());
853        let _pkb = skb.public_key();
854
855        let pka = PublicKey::from_bytes(&bytes);
856
857        let _dh_key = skb.dh_key(pka).unwrap();
858    }
859
860    #[test]
861    fn nonce() {
862        // No fair dice rolls for us!
863        assert_ne!(Nonce::new(&mut OsRng::default()), Nonce::new(&mut OsRng::default()));
864    }
865
866    /// Confirm value generation function ([Vol 3] Part H, Section D.2).
867    #[test]
868    fn nonce_f4() {
869        let u = PublicKeyX::from_be_bytes(u256(
870            0x20b003d2_f297be2c_5e2c83a7_e9f9a5b9,
871            0xeff49111_acf4fddb_cc030148_0e359de6,
872        ));
873        let v = PublicKeyX::from_be_bytes(u256(
874            0x55188b3d_32f6bb9a_900afcfb_eed4e72a,
875            0x59cb9ac2_f19d7cfb_6b4fdd49_f47fc5fd,
876        ));
877        let x = Nonce(0xd5cb8454_d177733e_ffffb2ec_712baeab);
878        assert_eq!(x.f4(&u, &v, 0).0, 0xf2c916f1_07a9bd1c_f1eda1be_a974872d);
879    }
880
881    /// Numeric comparison generation function ([Vol 3] Part H, Section D.5).
882    #[allow(clippy::unreadable_literal)]
883    #[test]
884    fn nonce_g2() {
885        let u = PublicKeyX::from_be_bytes(u256(
886            0x20b003d2_f297be2c_5e2c83a7_e9f9a5b9,
887            0xeff49111_acf4fddb_cc030148_0e359de6,
888        ));
889        let v = PublicKeyX::from_be_bytes(u256(
890            0x55188b3d_32f6bb9a_900afcfb_eed4e72a,
891            0x59cb9ac2_f19d7cfb_6b4fdd49_f47fc5fd,
892        ));
893        let x = Nonce(0xd5cb8454_d177733e_ffffb2ec_712baeab);
894        let y = Nonce(0xa6e8e7cc_25a75f6e_216583f7_ff3dc4cf);
895        assert_eq!(x.g2(&u, &v, &y), NumCompare(0x2f9ed5ba % 1_000_000));
896    }
897
898    /// Check value generation function ([Vol 3] Part H, Section D.4).
899    #[test]
900    fn mac_key_f6() {
901        let k = MacKey(Key::new(0x2965f176_a1084a02_fd3f6a20_ce636e20));
902        let n1 = Nonce(0xd5cb8454_d177733e_ffffb2ec_712baeab);
903        let n2 = Nonce(0xa6e8e7cc_25a75f6e_216583f7_ff3dc4cf);
904        let r = 0x12a3343b_b453bb54_08da42d2_0c2d0fc8;
905        let io_cap = IoCap([0x01, 0x01, 0x02]);
906        let a1 = Address::new(AddrKind::PUBLIC, BdAddr::new([0xce, 0xbf, 0x37, 0x37, 0x12, 0x56]));
907        let a2 = Address::new(AddrKind::PUBLIC, BdAddr::new([0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7]));
908        let c = k.f6(n1, n2, r, io_cap, a1, a2);
909        assert_eq!(c.0, 0xe3c47398_9cd0e8c5_d26c0b09_da958f61);
910    }
911
912    #[test]
913    fn nonce_f4_test() {
914        let ra = [
915            0x11u8, 0x3a, 0x7a, 0x69, 0x11, 0xcd, 0x44, 0x15, 0x52, 0xf7, 0x47, 0xe8, 0x26, 0x67, 0x72, 0xca,
916        ];
917
918        let rb = [
919            0xa5u8, 0x9e, 0x9a, 0x32, 0xc0, 0x97, 0x1c, 0xf7, 0x72, 0x1c, 0x29, 0xa7, 0x8c, 0x1e, 0xfd, 0x18,
920        ];
921
922        let pkb = [
923            0xd, 0x80, 0x33, 0x93, 0xad, 0x1f, 0x7e, 0x9a, 0x30, 0xc9, 0x6e, 0x1, 0x78, 0xf3, 0x43, 0x14, 0xa0, 0x57,
924            0xae, 0xa5, 0xa8, 0xee, 0x75, 0x51, 0x3f, 0xaa, 0xb1, 0x80, 0x75, 0xc7, 0x14, 0x50, 0x73, 0x9a, 0x98, 0x95,
925            0x36, 0x2e, 0xe6, 0x81, 0x5f, 0xbf, 0x16, 0xa2, 0x8c, 0xf6, 0x9d, 0xdc, 0x1f, 0xb8, 0x84, 0x8c, 0x7d, 0x37,
926            0x36, 0xe4, 0x36, 0x3c, 0xb3, 0xe8, 0xfe, 0x4a, 0x73, 0xc6,
927        ];
928
929        let pka = [
930            0x97, 0x20, 0x0f, 0xfe, 0xf0, 0xec, 0xdd, 0x11, 0xda, 0xa8, 0xa8, 0x07, 0x3e, 0xd7, 0xc6, 0xf2, 0x68, 0x5d,
931            0xc2, 0x58, 0x71, 0x1e, 0x34, 0x4f, 0xa1, 0xc4, 0x44, 0xa9, 0x7c, 0x71, 0xee, 0x54, 0x0d, 0xad, 0xb7, 0x69,
932            0x89, 0x9d, 0x4f, 0x83, 0x37, 0xcd, 0x43, 0xd3, 0x9f, 0x05, 0x13, 0x99, 0x6f, 0xbc, 0x1a, 0x89, 0xed, 0xb4,
933            0x7f, 0x80, 0x98, 0xcf, 0xad, 0x7c, 0x4c, 0x57, 0xbf, 0xe1,
934        ];
935
936        let mut pkb_x = [0u8; 32];
937        pkb_x.copy_from_slice(&pkb[..32]);
938        pkb_x.reverse();
939        let mut pka_x = [0u8; 32];
940        pka_x.copy_from_slice(&pka[..32]);
941        pka_x.reverse();
942
943        let pkbx = PublicKeyX::from_be_bytes(pkb_x);
944        let pkax = PublicKeyX::from_be_bytes(pka_x);
945        extern crate std;
946
947        let x = Nonce(u128::from_le_bytes(ra));
948        let y = Nonce(u128::from_le_bytes(rb));
949
950        assert_eq!(x.g2(&pkax, &pkbx, &y).0, 991180);
951    }
952
953    #[test]
954    pub fn irk_test() {
955        let irk = IdentityResolvingKey::new(0xec0234a3_57c8ad05_341010a6_0a397d9b).unwrap();
956        let prand = [0x70, 0x81, 0x94];
957
958        let hash = irk.ah(prand);
959        assert_eq!(hash, [0x0d, 0xfb, 0xaa]);
960    }
961
962    #[test]
963    pub fn rpa_test() {
964        let irk = IdentityResolvingKey::new(0x8b3958c158ed64467bd27bc90d3cf54d).unwrap();
965        let address = BdAddr::new([0x92, 0xF2, 0x8F, 0x84, 0x72, 0x4F]);
966        let re = irk.resolve_address(&address);
967        assert_eq!(re, true);
968    }
969
970    /// LE Legacy Pairing c1 test vector ([Vol 3] Part H, Appendix D.1).
971    /// preq/pres in wire order (command code at index 0).
972    #[cfg(feature = "legacy-pairing")]
973    #[allow(clippy::unreadable_literal)]
974    #[test]
975    fn legacy_c1() {
976        let k: u128 = 0;
977        let r: u128 = 0x5783D52156AD6F0E6388274EC6702EE0;
978        // Wire order: [Code, IO, OOB, Auth, MaxKey, InitDist, RespDist]
979        let preq: [u8; 7] = [0x01, 0x01, 0x00, 0x00, 0x10, 0x07, 0x07];
980        let pres: [u8; 7] = [0x02, 0x03, 0x00, 0x00, 0x08, 0x00, 0x05];
981        let iat: u8 = 0x01;
982        let rat: u8 = 0x00;
983        let ia: [u8; 6] = [0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6];
984        let ra: [u8; 6] = [0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6];
985
986        let result = c1(k, r, &preq, &pres, iat, &ia, rat, &ra);
987        assert_eq!(result, 0x1E1E3FEF878988EAD2A74DC5BEF13B86);
988    }
989
990    /// LE Legacy Pairing s1 test vector ([Vol 3] Part H, Appendix D.2).
991    #[cfg(feature = "legacy-pairing")]
992    #[allow(clippy::unreadable_literal)]
993    #[test]
994    fn legacy_s1() {
995        let k: u128 = 0;
996        let r1: u128 = 0x000F0E0D0C0B0A091122334455667788;
997        let r2: u128 = 0x010203040506070899AABBCCDDEEFF00;
998
999        let result = s1(k, r1, r2);
1000        assert_eq!(result, 0x9a1fe1f0e8b0f49b5b4216ae796da062);
1001    }
1002
1003    /// Diversifying function d1 ([Vol 3] Part H, Section B.2.1).
1004    /// Spec example: d=0x1234, r=0xABCD => d' = 0x000000000000000000000000ABCD1234.
1005    #[allow(clippy::unreadable_literal)]
1006    #[test]
1007    fn diversify_d1() {
1008        let k: u128 = 0x000102030405060708090a0b0c0d0e0f;
1009        let d: u16 = 0x1234;
1010        let r: u16 = 0xABCD;
1011        assert_eq!(d1(k, d, r), 0xb66854fa3dd35aadf83a6c59e22b52fd);
1012    }
1013}