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# Imports 17# ----------------------------------------------------------------------------- 18 19from bumble.crypto import EccKey, aes_cmac, ah, c1, f4, f5, f6, g2, h6, h7, s1 20 21# ----------------------------------------------------------------------------- 22# pylint: disable=invalid-name 23# ----------------------------------------------------------------------------- 24 25# ----------------------------------------------------------------------------- 26def reversed_hex(hex_str): 27 return bytes(reversed(bytes.fromhex(hex_str))) 28 29 30# ----------------------------------------------------------------------------- 31def test_ecc(): 32 key = EccKey.generate() 33 x = key.x 34 y = key.y 35 36 assert len(x) == 32 37 assert len(y) == 32 38 39 # Test DH with test vectors from the spec 40 private_A = ( 41 '3f49f6d4 a3c55f38 74c9b3e3 d2103f50 4aff607b eb40b799 5899b8a6 cd3c1abd' 42 ) 43 private_B = ( 44 '55188b3d 32f6bb9a 900afcfb eed4e72a 59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd' 45 ) 46 public_A_x = ( 47 '20b003d2 f297be2c 5e2c83a7 e9f9a5b9 eff49111 acf4fddb cc030148 0e359de6' 48 ) 49 public_A_y = ( 50 'dc809c49 652aeb6d 63329abf 5a52155c 766345c2 8fed3024 741c8ed0 1589d28b' 51 ) 52 public_B_x = ( 53 '1ea1f0f0 1faf1d96 09592284 f19e4c00 47b58afd 8615a69f 559077b2 2faaa190' 54 ) 55 public_B_y = ( 56 '4c55f33e 429dad37 7356703a 9ab85160 472d1130 e28e3676 5f89aff9 15b1214a' 57 ) 58 dhkey = 'ec0234a3 57c8ad05 341010a6 0a397d9b 99796b13 b4f866f1 868d34f3 73bfa698' 59 60 key_a = EccKey.from_private_key_bytes( 61 bytes.fromhex(private_A), bytes.fromhex(public_A_x), bytes.fromhex(public_A_y) 62 ) 63 shared_key = key_a.dh(bytes.fromhex(public_B_x), bytes.fromhex(public_B_y)) 64 assert shared_key == bytes.fromhex(dhkey) 65 66 key_b = EccKey.from_private_key_bytes( 67 bytes.fromhex(private_B), bytes.fromhex(public_B_x), bytes.fromhex(public_B_y) 68 ) 69 shared_key = key_b.dh(bytes.fromhex(public_A_x), bytes.fromhex(public_A_y)) 70 assert shared_key == bytes.fromhex(dhkey) 71 72 73# ----------------------------------------------------------------------------- 74def test_c1(): 75 k = bytes(16) 76 r = reversed_hex('5783D52156AD6F0E6388274EC6702EE0') 77 pres = reversed_hex('05000800000302') 78 preq = reversed_hex('07071000000101') 79 iat = 1 80 ia = reversed_hex('A1A2A3A4A5A6') 81 rat = 0 82 ra = reversed_hex('B1B2B3B4B5B6') 83 result = c1(k, r, preq, pres, iat, rat, ia, ra) 84 assert result == reversed_hex('1e1e3fef878988ead2a74dc5bef13b86') 85 86 87# ----------------------------------------------------------------------------- 88def test_s1(): 89 k = bytes(16) 90 r1 = reversed_hex('000F0E0D0C0B0A091122334455667788') 91 r2 = reversed_hex('010203040506070899AABBCCDDEEFF00') 92 result = s1(k, r1, r2) 93 assert result == reversed_hex('9a1fe1f0e8b0f49b5b4216ae796da062') 94 95 96# ----------------------------------------------------------------------------- 97def test_aes_cmac(): 98 m = b'' 99 k = bytes.fromhex('2b7e1516 28aed2a6 abf71588 09cf4f3c') 100 cmac = aes_cmac(m, k) 101 assert cmac == bytes.fromhex('bb1d6929 e9593728 7fa37d12 9b756746') 102 103 m = bytes.fromhex('6bc1bee2 2e409f96 e93d7e11 7393172a') 104 cmac = aes_cmac(m, k) 105 assert cmac == bytes.fromhex('070a16b4 6b4d4144 f79bdd9d d04a287c') 106 107 m = bytes.fromhex( 108 '6bc1bee2 2e409f96 e93d7e11 7393172a' 109 + 'ae2d8a57 1e03ac9c 9eb76fac 45af8e51' 110 + '30c81c46 a35ce411' 111 ) 112 cmac = aes_cmac(m, k) 113 assert cmac == bytes.fromhex('dfa66747 de9ae630 30ca3261 1497c827') 114 115 m = bytes.fromhex( 116 '6bc1bee2 2e409f96 e93d7e11 7393172a' 117 + 'ae2d8a57 1e03ac9c 9eb76fac 45af8e51' 118 + '30c81c46 a35ce411 e5fbc119 1a0a52ef' 119 + 'f69f2445 df4f9b17 ad2b417b e66c3710' 120 ) 121 cmac = aes_cmac(m, k) 122 assert cmac == bytes.fromhex('51f0bebf 7e3b9d92 fc497417 79363cfe') 123 124 125# ----------------------------------------------------------------------------- 126def test_f4(): 127 u = bytes( 128 reversed( 129 bytes.fromhex( 130 '20b003d2 f297be2c 5e2c83a7 e9f9a5b9' 131 + 'eff49111 acf4fddb cc030148 0e359de6' 132 ) 133 ) 134 ) 135 v = bytes( 136 reversed( 137 bytes.fromhex( 138 '55188b3d 32f6bb9a 900afcfb eed4e72a' 139 + '59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd' 140 ) 141 ) 142 ) 143 x = bytes(reversed(bytes.fromhex('d5cb8454 d177733e ffffb2ec 712baeab'))) 144 z = bytes([0]) 145 value = f4(u, v, x, z) 146 assert bytes(reversed(value)) == bytes.fromhex( 147 'f2c916f1 07a9bd1c f1eda1be a974872d' 148 ) 149 150 151# ----------------------------------------------------------------------------- 152def test_f5(): 153 w = bytes( 154 reversed( 155 bytes.fromhex( 156 'ec0234a3 57c8ad05 341010a6 0a397d9b' 157 + '99796b13 b4f866f1 868d34f3 73bfa698' 158 ) 159 ) 160 ) 161 n1 = bytes(reversed(bytes.fromhex('d5cb8454 d177733e ffffb2ec 712baeab'))) 162 n2 = bytes(reversed(bytes.fromhex('a6e8e7cc 25a75f6e 216583f7 ff3dc4cf'))) 163 a1 = bytes(reversed(bytes.fromhex('00561237 37bfce'))) 164 a2 = bytes(reversed(bytes.fromhex('00a71370 2dcfc1'))) 165 value = f5(w, n1, n2, a1, a2) 166 assert bytes(reversed(value[0])) == bytes.fromhex( 167 '2965f176 a1084a02 fd3f6a20 ce636e20' 168 ) 169 assert bytes(reversed(value[1])) == bytes.fromhex( 170 '69867911 69d7cd23 980522b5 94750a38' 171 ) 172 173 174# ----------------------------------------------------------------------------- 175def test_f6(): 176 n1 = bytes(reversed(bytes.fromhex('d5cb8454 d177733e ffffb2ec 712baeab'))) 177 n2 = bytes(reversed(bytes.fromhex('a6e8e7cc 25a75f6e 216583f7 ff3dc4cf'))) 178 mac_key = bytes(reversed(bytes.fromhex('2965f176 a1084a02 fd3f6a20 ce636e20'))) 179 r = bytes(reversed(bytes.fromhex('12a3343b b453bb54 08da42d2 0c2d0fc8'))) 180 io_cap = bytes(reversed(bytes.fromhex('010102'))) 181 a1 = bytes(reversed(bytes.fromhex('00561237 37bfce'))) 182 a2 = bytes(reversed(bytes.fromhex('00a71370 2dcfc1'))) 183 value = f6(mac_key, n1, n2, r, io_cap, a1, a2) 184 assert bytes(reversed(value)) == bytes.fromhex( 185 'e3c47398 9cd0e8c5 d26c0b09 da958f61' 186 ) 187 188 189# ----------------------------------------------------------------------------- 190def test_g2(): 191 u = bytes( 192 reversed( 193 bytes.fromhex( 194 '20b003d2 f297be2c 5e2c83a7 e9f9a5b9' 195 + 'eff49111 acf4fddb cc030148 0e359de6' 196 ) 197 ) 198 ) 199 v = bytes( 200 reversed( 201 bytes.fromhex( 202 '55188b3d 32f6bb9a 900afcfb eed4e72a' 203 + '59cb9ac2 f19d7cfb 6b4fdd49 f47fc5fd' 204 ) 205 ) 206 ) 207 x = bytes(reversed(bytes.fromhex('d5cb8454 d177733e ffffb2ec 712baeab'))) 208 y = bytes(reversed(bytes.fromhex('a6e8e7cc 25a75f6e 216583f7 ff3dc4cf'))) 209 value = g2(u, v, x, y) 210 assert value == 0x2F9ED5BA 211 212 213# ----------------------------------------------------------------------------- 214def test_h6(): 215 KEY = bytes.fromhex('ec0234a3 57c8ad05 341010a6 0a397d9b') 216 KEY_ID = bytes.fromhex('6c656272') 217 assert h6(KEY, KEY_ID) == bytes.fromhex('2d9ae102 e76dc91c e8d3a9e2 80b16399') 218 219 220# ----------------------------------------------------------------------------- 221def test_h7(): 222 KEY = bytes.fromhex('ec0234a3 57c8ad05 341010a6 0a397d9b') 223 SALT = bytes.fromhex('00000000 00000000 00000000 746D7031') 224 assert h7(SALT, KEY) == bytes.fromhex('fb173597 c6a3c0ec d2998c2a 75a57011') 225 226 227# ----------------------------------------------------------------------------- 228def test_ah(): 229 irk = bytes(reversed(bytes.fromhex('ec0234a3 57c8ad05 341010a6 0a397d9b'))) 230 prand = bytes(reversed(bytes.fromhex('708194'))) 231 value = ah(irk, prand) 232 expected = bytes(reversed(bytes.fromhex('0dfbaa'))) 233 assert value == expected 234 235 236# ----------------------------------------------------------------------------- 237if __name__ == '__main__': 238 test_ecc() 239 test_c1() 240 test_s1() 241 test_aes_cmac() 242 test_f4() 243 test_f5() 244 test_f6() 245 test_g2() 246 test_h6() 247 test_h7() 248 test_ah() 249