pamoja_lorawan/relay/keys.rs
1//! The keys a relay and an end device protect wake-on-radio frames with, TS011-1.0.1
2//! section 4.
3
4use crate::crypto::Cipher;
5
6/// Derives the root relay session key of an end device, TS011-1.0.1 section 4.4.
7///
8/// `RootWorSKey = aes128_encrypt(Key, 0x01 | pad16)`, where the key is the network session
9/// key: `NwkSKey` under LoRaWAN 1.0.x and `NwkSEncKey` from 1.1. An over-the-air device
10/// derives it after each join, and a network sends it to a relay in `UpdateUplinkListReq`.
11///
12/// # Arguments
13///
14/// * `network_key` - the end device's network session key.
15///
16/// # Returns
17///
18/// The root relay session key.
19///
20/// # Examples
21///
22/// ```
23/// use pamoja_lorawan::relay::root_wor_s_key;
24///
25/// // The vector The Things Stack tests its derivation with.
26/// let nwk_s_enc_key = [
27/// 0xCE, 0x07, 0xA0, 0x09, 0xA3, 0x97, 0x0A, 0xC0, 0x51, 0x9A, 0x09, 0x9E, 0xD5, 0x3E, 0x55,
28/// 0x0B,
29/// ];
30/// assert_eq!(
31/// root_wor_s_key(&nwk_s_enc_key),
32/// [
33/// 0xEE, 0x91, 0xDC, 0x1A, 0x66, 0x66, 0xC0, 0x6E, 0x82, 0x77, 0xDE, 0x6D, 0xB4, 0xDB,
34/// 0x94, 0x5F
35/// ]
36/// );
37/// ```
38#[must_use]
39pub fn root_wor_s_key(network_key: &[u8; 16]) -> [u8; 16] {
40 let mut block = [0u8; 16];
41 block[0] = 0x01;
42 Cipher::new(network_key).encrypt_block(&block)
43}
44
45/// The integrity and encryption keys of one end device's wake-on-radio frames.
46#[derive(Clone, Copy, PartialEq, Eq)]
47pub struct WorKeys {
48 integrity: [u8; 16],
49 encryption: [u8; 16],
50}
51
52impl WorKeys {
53 /// Derives an end device's keys from its root relay session key, TS011-1.0.1
54 /// section 4.5.
55 ///
56 /// `WorSIntKey = aes128_encrypt(RootWorSKey, 0x01 | DevAddr | pad16)` and
57 /// `WorSEncKey = aes128_encrypt(RootWorSKey, 0x02 | DevAddr | pad16)`.
58 ///
59 /// # Arguments
60 ///
61 /// * `root_wor_s_key` - the device's root relay session key.
62 /// * `dev_addr` - the device's address.
63 ///
64 /// # Returns
65 ///
66 /// The two keys.
67 #[must_use]
68 pub fn derive(root_wor_s_key: &[u8; 16], dev_addr: u32) -> WorKeys {
69 let cipher = Cipher::new(root_wor_s_key);
70 let mut block = [0u8; 16];
71 block[1..5].copy_from_slice(&dev_addr.to_le_bytes());
72 block[0] = 0x01;
73 let integrity = cipher.encrypt_block(&block);
74 block[0] = 0x02;
75 let encryption = cipher.encrypt_block(&block);
76 WorKeys {
77 integrity,
78 encryption,
79 }
80 }
81
82 /// Holds keys derived earlier, such as ones a relay keeps for an end device it trusts.
83 ///
84 /// # Arguments
85 ///
86 /// * `integrity` - `WorSIntKey`.
87 /// * `encryption` - `WorSEncKey`.
88 ///
89 /// # Returns
90 ///
91 /// The keys.
92 #[must_use]
93 pub const fn new(integrity: [u8; 16], encryption: [u8; 16]) -> WorKeys {
94 WorKeys {
95 integrity,
96 encryption,
97 }
98 }
99
100 /// Returns the key a WOR frame's and a WOR ACK's integrity code is computed with,
101 /// `WorSIntKey`.
102 ///
103 /// # Returns
104 ///
105 /// The key.
106 #[must_use]
107 pub const fn integrity(&self) -> &[u8; 16] {
108 &self.integrity
109 }
110
111 /// Returns the key their payloads are encrypted with, `WorSEncKey`.
112 ///
113 /// # Returns
114 ///
115 /// The key.
116 #[must_use]
117 pub const fn encryption(&self) -> &[u8; 16] {
118 &self.encryption
119 }
120}
121
122impl core::fmt::Debug for WorKeys {
123 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
124 f.write_str("WorKeys { .. }")
125 }
126}