xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/public/pw_bluetooth_sapphire/internal/host/sm/util.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
17 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h"
18 #include "pw_bluetooth_sapphire/internal/host/common/uint128.h"
19 #include "pw_bluetooth_sapphire/internal/host/common/uint256.h"
20 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
21 #include "pw_bluetooth_sapphire/internal/host/sm/delegate.h"
22 #include "pw_bluetooth_sapphire/internal/host/sm/error.h"
23 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h"
24 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
25 
26 namespace bt::sm::util {
27 // NOTE:
28 // All cryptographic utility functions use little-endian input/output unless
29 // explicitly noted.
30 
31 // Returns the size of the SMP Packet with the given `Payload` template
32 // parameter type.
33 template <typename Payload>
PacketSize()34 constexpr size_t PacketSize() {
35   return sizeof(Header) + sizeof(Payload);
36 }
37 
38 // Returns a string representation of a given pairing method.
39 std::string PairingMethodToString(PairingMethod method);
40 
41 // Returns a string representation of a PairingDelegate display method.
42 std::string DisplayMethodToString(Delegate::DisplayMethod method);
43 
44 // Returns a string representation of a given IOCapability.
45 std::string IOCapabilityToString(IOCapability capability);
46 
47 // Returns the HCI version of an SMP IOCapability. Returns
48 // pw::bluetooth::emboss::IoCapability::NO_INPUT_NO_OUTPUT for values not in
49 // sm::IOCapability.
50 pw::bluetooth::emboss::IoCapability IOCapabilityForHci(IOCapability capability);
51 
52 // Utility function to heap allocate a new PDU.
53 MutableByteBufferPtr NewPdu(size_t param_size);
54 
55 // Returns a std::pair<initiator_value, responder_value> based on |local_value|,
56 // |peer_value| and the local SMP Role |role|.
57 template <typename T>
MapToRoles(const T & local_value,const T & peer_value,Role role)58 std::pair<T, T> MapToRoles(const T& local_value,
59                            const T& peer_value,
60                            Role role) {
61   if (role == Role::kInitiator) {
62     return {local_value, peer_value};
63   }
64   return {peer_value, local_value};
65 }
66 
67 // inclusive-language: disable
68 // Used to select the key generation method as described in Vol 3, Part H,
69 // 2.3.5.1 based on local and peer authentication parameters:
70 //   - |secure_connections|: True if Secure Connections pairing is used. False
71 //     means Legacy Pairing.
72 //   - |local_oob|: Local OOB auth data is available.
73 //   - |peer_oob|: Peer OOB auth data is available.
74 //   - |mitm_required|: True means at least one of the devices requires MITM
75 //     protection.
76 //   - |local_ioc|, |peer_ioc|: Local and peer IO capabilities.
77 //   - |local_initiator|: True means that the local device is the initiator and
78 //     |local_ioc| represents the initiator's I/O capabilities.
79 PairingMethod SelectPairingMethod(bool secure_connections,
80                                   bool local_oob,
81                                   bool peer_oob,
82                                   bool mitm_required,
83                                   IOCapability local_ioc,
84                                   IOCapability peer_ioc,
85                                   bool local_initiator);
86 // inclusive-language: enable
87 
88 // Implements the "Security Function 'e'" defined in Vol 3, Part H, 2.2.1.
89 void Encrypt(const UInt128& key,
90              const UInt128& plaintext_data,
91              UInt128* out_encrypted_data);
92 
93 // Implements the "Confirm Value Generation" or "c1" function for LE Legacy
94 // Pairing described in Vol 3, Part H, 2.2.3.
95 //
96 //   |tk|: 128-bit TK value
97 //   |rand|: 128-bit random number
98 //   |preq|: 56-bit SMP "Pairing Request" PDU
99 //   |pres|: 56-bit SMP "Pairing Response" PDU
100 //   |initiator_addr|: Device address of the initiator used while establishing
101 //                     the connection.
102 //   |responder_addr|: Device address of the responder used while establishing
103 //                     the connection.
104 //
105 // The generated confirm value will be returned in |out_confirm_value|.
106 void C1(const UInt128& tk,
107         const UInt128& rand,
108         const ByteBuffer& preq,
109         const ByteBuffer& pres,
110         const DeviceAddress& initiator_addr,
111         const DeviceAddress& responder_addr,
112         UInt128* out_confirm_value);
113 
114 // Implements the "Key Generation Function s1" to generate the STK for LE Legacy
115 // Pairing described in Vol 3, Part H, 2.2.4.
116 //
117 //   |tk|: 128-bit TK value
118 //   |r1|: 128-bit random value generated by the responder.
119 //   |r2|: 128-bit random value generated by the initiator.
120 void S1(const UInt128& tk,
121         const UInt128& r1,
122         const UInt128& r2,
123         UInt128* out_stk);
124 
125 // Implements the "Random Address Hash Function ah" to resolve RPAs. Described
126 // in Vol 3, Part H, 222.
127 //
128 //   |k|: 128-bit IRK value
129 //   |r|: 24-bit random part of a RPA.
130 //
131 // Returns 24 bit hash value.
132 uint32_t Ah(const UInt128& k, uint32_t r);
133 
134 // Returns true if the given |irk| can resolve the given |rpa| using the method
135 // described in Vol 6, Part B, 1.3.2.3.
136 bool IrkCanResolveRpa(const UInt128& irk, const DeviceAddress& rpa);
137 
138 // Generates a RPA using the given IRK based on the method described in Vol 6,
139 // Part B, 1.3.2.2.
140 DeviceAddress GenerateRpa(const UInt128& irk);
141 
142 // Generates a static or non-resolvable private random device address.
143 DeviceAddress GenerateRandomAddress(bool is_static);
144 
145 // Implements the AES-CMAC function defined in Vol. 3, Part H, 2.2.5.
146 //
147 //   |hash_key|: Little-endian 128-bit value used as the cipher key k in the
148 //   AES-CMAC algorithm. |msg|: Variable length data to be encoded by
149 //   |hash_key|. This is a little-endian parameter.
150 //
151 // A return value of std::nullopt indicates the calculation failed.
152 std::optional<UInt128> AesCmac(const UInt128& hash_key, const ByteBuffer& msg);
153 
154 // Implements the "LE Secure Connections confirm value generation function f4"
155 // per Vol. 3, Part H, 2.2.6.
156 //
157 //   |u|: X-coordinate of the (peer/local) ECDH public key.
158 //   |v|: X-coordiante of the (local/peer) ECDH public key.
159 //   |x|: The CMAC key.
160 //   |z|: 0 for pairing methods besides Passkey Entry, in which case it is one
161 //   bit of the passkey.
162 //
163 // A return value of std::nullopt indicates the calculation failed.
164 std::optional<UInt128> F4(const UInt256& u,
165                           const UInt256& v,
166                           const UInt128& x,
167                           uint8_t z);
168 
169 // Implements the "LE Secure Connections key generation function f5" per Vol. 3,
170 // Part H, 2.2.7.
171 //
172 //   |dhkey|: Diffie-Hellman key generated by both parties in Phase 1 of SC
173 //   (ECDH key agreement). |initiator_nonce|: Nonce value generated by the
174 //   initiator to avoid replay attacks. |responder_nonce|: Nonce value generated
175 //   by the responder to avoid replay attacks. |initiator_addr|: Device address
176 //   of the pairing initiator. |responder_addr|: Device address of the pairing
177 //   responder.
178 //
179 // A return value of std::nullopt indicates the calculation failed. Returns an
180 // |F5Results| struct instead of the spec-prescribed single 256-bit value for
181 // easier client access to the MacKey/LTK.
182 struct F5Results {
183   UInt128 mac_key;
184   UInt128 ltk;
185 };
186 std::optional<F5Results> F5(const UInt256& dhkey,
187                             const UInt128& initiator_nonce,
188                             const UInt128& responder_nonce,
189                             const DeviceAddress& initiator_addr,
190                             const DeviceAddress& responder_addr);
191 
192 // Implements the "LE Secure Connections check value generation function f6" per
193 // Vol. 3, Part H, 2.2.8. The semantics of each parameter depend on the pairing
194 // method and current pairing state. See above-noted spec section for parameter
195 // descriptions. The 24-bit IOCap parameter in the spec signature is separated
196 // into |auth_req|, |oob|, and |io_cap| parameters for client convenience.
197 //
198 // A return value of std::nullopt indicates the calculation failed.
199 std::optional<UInt128> F6(const UInt128& mackey,
200                           const UInt128& n1,
201                           const UInt128& n2,
202                           const UInt128& r,
203                           AuthReqField auth_req,
204                           OOBDataFlag oob,
205                           IOCapability io_cap,
206                           const DeviceAddress& a1,
207                           const DeviceAddress& a2);
208 
209 // Implements the "LE Secure Connections numeric comparison value generation
210 // function g2" per Vol. 3, Part H, 2.2.9. The value displayed to the user
211 // should be the least significant 6 decimal digits of the result, i.e. g2 mod
212 // 10^6.
213 //
214 //   |initiator_pubkey_x|: X-coordinate of the initiator's ECDH public key
215 //   |responder_pubkey_x|: X-coordinate of the responder's ECDH public key
216 //   |initiator_nonce|: nonce value generated by the initiator to avoid replay
217 //   attacks |responder_nonce|: nonce value generated by the responder to avoid
218 //   replay attacks
219 //
220 // A return value of std::nullopt indicates the calculation failed.
221 std::optional<uint32_t> G2(const UInt256& initiator_pubkey_x,
222                            const UInt256& responder_pubkey_x,
223                            const UInt128& initiator_nonce,
224                            const UInt128& responder_nonce);
225 
226 // Implements the "Link key conversion function h6" per Vol. 3, Part H, 2.2.10.
227 // `w` is the encryption key for AES-CMAC, and `key_id` is used as the input
228 // value.
229 //
230 // A return value of std::nullopt indicates the calculation failed.
231 std::optional<UInt128> H6(const UInt128& w, uint32_t key_id);
232 
233 // Implements the "Link key conversion function h7" per Vol. 3, Part H, 2.2.11.
234 // `salt` is the encryption key for AES-CMAC, and `w` is the input value.
235 //
236 // A return value of std::nullopt indicates the calculation failed.
237 std::optional<UInt128> H7(const UInt128& salt, const UInt128& w);
238 
239 // Converts an LE LTK to a BR/EDR link key for Cross Transport Key Derivation as
240 // defined in v5.2 Vol. 3 Part H 2.4.2.4.
241 //
242 // A return value of std::nullopt indicates the conversion failed.
243 std::optional<UInt128> LeLtkToBrEdrLinkKey(const UInt128& le_ltk,
244                                            CrossTransportKeyAlgo hash_function);
245 
246 }  // namespace bt::sm::util
247