1# Copyright 2021-2022 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of 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, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15# ----------------------------------------------------------------------------- 16# Crypto support 17# 18# See Bluetooth spec Vol 3, Part H - 2.2 CRYPTOGRAPHIC TOOLBOX 19# ----------------------------------------------------------------------------- 20 21# ----------------------------------------------------------------------------- 22# Imports 23# ----------------------------------------------------------------------------- 24import logging 25import operator 26import platform 27 28if platform.system() != 'Emscripten': 29 import secrets 30 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 31 from cryptography.hazmat.primitives.asymmetric.ec import ( 32 generate_private_key, 33 ECDH, 34 EllipticCurvePublicNumbers, 35 EllipticCurvePrivateNumbers, 36 SECP256R1, 37 ) 38 from cryptography.hazmat.primitives import cmac 39else: 40 # TODO: implement stubs 41 pass 42 43# ----------------------------------------------------------------------------- 44# Logging 45# ----------------------------------------------------------------------------- 46logger = logging.getLogger(__name__) 47 48 49# ----------------------------------------------------------------------------- 50# Classes 51# ----------------------------------------------------------------------------- 52class EccKey: 53 def __init__(self, private_key): 54 self.private_key = private_key 55 56 @classmethod 57 def generate(cls): 58 private_key = generate_private_key(SECP256R1()) 59 return cls(private_key) 60 61 @classmethod 62 def from_private_key_bytes(cls, d_bytes, x_bytes, y_bytes): 63 d = int.from_bytes(d_bytes, byteorder='big', signed=False) 64 x = int.from_bytes(x_bytes, byteorder='big', signed=False) 65 y = int.from_bytes(y_bytes, byteorder='big', signed=False) 66 private_key = EllipticCurvePrivateNumbers( 67 d, EllipticCurvePublicNumbers(x, y, SECP256R1()) 68 ).private_key() 69 return cls(private_key) 70 71 @property 72 def x(self): 73 return ( 74 self.private_key.public_key() 75 .public_numbers() 76 .x.to_bytes(32, byteorder='big') 77 ) 78 79 @property 80 def y(self): 81 return ( 82 self.private_key.public_key() 83 .public_numbers() 84 .y.to_bytes(32, byteorder='big') 85 ) 86 87 def dh(self, public_key_x, public_key_y): 88 x = int.from_bytes(public_key_x, byteorder='big', signed=False) 89 y = int.from_bytes(public_key_y, byteorder='big', signed=False) 90 public_key = EllipticCurvePublicNumbers(x, y, SECP256R1()).public_key() 91 shared_key = self.private_key.exchange(ECDH(), public_key) 92 93 return shared_key 94 95 96# ----------------------------------------------------------------------------- 97# Functions 98# ----------------------------------------------------------------------------- 99 100# ----------------------------------------------------------------------------- 101def xor(x, y): 102 assert len(x) == len(y) 103 return bytes(map(operator.xor, x, y)) 104 105 106# ----------------------------------------------------------------------------- 107def r(): 108 ''' 109 Generate 16 bytes of random data 110 ''' 111 return secrets.token_bytes(16) 112 113 114# ----------------------------------------------------------------------------- 115def e(key, data): 116 ''' 117 AES-128 ECB, expecting byte-swapped inputs and producing a byte-swapped output. 118 119 See Bluetooth spec Vol 3, Part H - 2.2.1 Security function e 120 ''' 121 122 cipher = Cipher(algorithms.AES(bytes(reversed(key))), modes.ECB()) 123 encryptor = cipher.encryptor() 124 return bytes(reversed(encryptor.update(bytes(reversed(data))))) 125 126 127# ----------------------------------------------------------------------------- 128def ah(k, r): # pylint: disable=redefined-outer-name 129 ''' 130 See Bluetooth spec Vol 3, Part H - 2.2.2 Random Address Hash function ah 131 ''' 132 133 padding = bytes(13) 134 r_prime = r + padding 135 return e(k, r_prime)[0:3] 136 137 138# ----------------------------------------------------------------------------- 139def c1(k, r, preq, pres, iat, rat, ia, ra): # pylint: disable=redefined-outer-name 140 ''' 141 See Bluetooth spec, Vol 3, Part H - 2.2.3 Confirm value generation function c1 for 142 LE Legacy Pairing 143 ''' 144 145 p1 = bytes([iat, rat]) + preq + pres 146 p2 = ra + ia + bytes([0, 0, 0, 0]) 147 return e(k, xor(e(k, xor(r, p1)), p2)) 148 149 150# ----------------------------------------------------------------------------- 151def s1(k, r1, r2): 152 ''' 153 See Bluetooth spec, Vol 3, Part H - 2.2.4 Key generation function s1 for LE Legacy 154 Pairing 155 ''' 156 157 return e(k, r2[0:8] + r1[0:8]) 158 159 160# ----------------------------------------------------------------------------- 161def aes_cmac(m, k): 162 ''' 163 See Bluetooth spec, Vol 3, Part H - 2.2.5 FunctionAES-CMAC 164 165 NOTE: the input and output of this internal function are in big-endian byte order 166 ''' 167 mac = cmac.CMAC(algorithms.AES(k)) 168 mac.update(m) 169 return mac.finalize() 170 171 172# ----------------------------------------------------------------------------- 173def f4(u, v, x, z): 174 ''' 175 See Bluetooth spec, Vol 3, Part H - 2.2.6 LE Secure Connections Confirm Value 176 Generation Function f4 177 ''' 178 return bytes( 179 reversed( 180 aes_cmac(bytes(reversed(u)) + bytes(reversed(v)) + z, bytes(reversed(x))) 181 ) 182 ) 183 184 185# ----------------------------------------------------------------------------- 186def f5(w, n1, n2, a1, a2): 187 ''' 188 See Bluetooth spec, Vol 3, Part H - 2.2.7 LE Secure Connections Key Generation 189 Function f5 190 191 NOTE: this returns a tuple: (MacKey, LTK) in little-endian byte order 192 ''' 193 salt = bytes.fromhex('6C888391AAF5A53860370BDB5A6083BE') 194 t = aes_cmac(bytes(reversed(w)), salt) 195 key_id = bytes([0x62, 0x74, 0x6C, 0x65]) 196 return ( 197 bytes( 198 reversed( 199 aes_cmac( 200 bytes([0]) 201 + key_id 202 + bytes(reversed(n1)) 203 + bytes(reversed(n2)) 204 + bytes(reversed(a1)) 205 + bytes(reversed(a2)) 206 + bytes([1, 0]), 207 t, 208 ) 209 ) 210 ), 211 bytes( 212 reversed( 213 aes_cmac( 214 bytes([1]) 215 + key_id 216 + bytes(reversed(n1)) 217 + bytes(reversed(n2)) 218 + bytes(reversed(a1)) 219 + bytes(reversed(a2)) 220 + bytes([1, 0]), 221 t, 222 ) 223 ) 224 ), 225 ) 226 227 228# ----------------------------------------------------------------------------- 229def f6(w, n1, n2, r, io_cap, a1, a2): # pylint: disable=redefined-outer-name 230 ''' 231 See Bluetooth spec, Vol 3, Part H - 2.2.8 LE Secure Connections Check Value 232 Generation Function f6 233 ''' 234 return bytes( 235 reversed( 236 aes_cmac( 237 bytes(reversed(n1)) 238 + bytes(reversed(n2)) 239 + bytes(reversed(r)) 240 + bytes(reversed(io_cap)) 241 + bytes(reversed(a1)) 242 + bytes(reversed(a2)), 243 bytes(reversed(w)), 244 ) 245 ) 246 ) 247 248 249# ----------------------------------------------------------------------------- 250def g2(u, v, x, y): 251 ''' 252 See Bluetooth spec, Vol 3, Part H - 2.2.9 LE Secure Connections Numeric Comparison 253 Value Generation Function g2 254 ''' 255 return int.from_bytes( 256 aes_cmac( 257 bytes(reversed(u)) + bytes(reversed(v)) + bytes(reversed(y)), 258 bytes(reversed(x)), 259 )[-4:], 260 byteorder='big', 261 ) 262 263 264# ----------------------------------------------------------------------------- 265def h6(w, key_id): 266 ''' 267 See Bluetooth spec, Vol 3, Part H - 2.2.10 Link key conversion function h6 268 ''' 269 return aes_cmac(key_id, w) 270 271 272# ----------------------------------------------------------------------------- 273def h7(salt, w): 274 ''' 275 See Bluetooth spec, Vol 3, Part H - 2.2.11 Link key conversion function h7 276 ''' 277 return aes_cmac(w, salt) 278