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