1#!/usr/bin/env python3 2# BlueKitchen GmbH (c) 2019 3 4# pip3 install pycryptodomex 5 6# implementation of the Bluetooth SIG Mesh crypto functions using pycryptodomex 7 8from Cryptodome.Cipher import AES 9from Cryptodome.Hash import CMAC 10 11def aes_cmac(k, n): 12 cobj = CMAC.new(k, ciphermod=AES) 13 cobj.update(n) 14 return cobj.digest() 15 16def aes_ccm_encrypt(key, nonce, message, additional_data, mac_len): 17 cipher = AES.new(key, AES.MODE_CCM, nonce=nonce, mac_len=mac_len) 18 cipher.update(additional_data) 19 ciphertext, tag = cipher.encrypt_and_digest(message) 20 return ciphertext, tag 21 22def aes_ccm_decrypt(key, nonce, message, additional_data, mac_len, mac_tag): 23 cipher = AES.new(key, AES.MODE_CCM, nonce=nonce, mac_len=mac_len) 24 cipher.update(additional_data) 25 try: 26 ciphertext = cipher.decrypt_and_verify(message, mac_tag) 27 return ciphertext 28 except ValueError: 29 return None 30 31def s1(m): 32 # s1(M) = AES-CMACZERO (M) 33 zero_key = bytes(16) 34 return aes_cmac(zero_key, m) 35 36def k1(n, salt, p): 37 # T = AES-CMACSALT (N) 38 t = aes_cmac(salt, n) 39 # k1(N, SALT, P) = AES-CMACT (P) 40 return aes_cmac(t, p) 41 42def k2(n, p): 43 # SALT = s1(“smk2”) 44 salt = s1(b'smk2') 45 # T = AES-CMACSALT (N) 46 t = aes_cmac(salt, n) 47 # T0 = empty string (zero length) 48 t0 = b'' 49 # T1 = AES-CMACT (T0 || P || 0x01) 50 t1 = aes_cmac(t, t0 + p + b'\x01') 51 # T2 = AES-CMACT (T1 || P || 0x02) 52 t2 = aes_cmac(t, t1 + p + b'\x02') 53 # T3 = AES-CMACT (T2 || P || 0x03) 54 t3 = aes_cmac(t, t2 + p + b'\x03') 55 nid = t1[15] & 0x7f 56 encryption_key = t2 57 privacy_key = t3 58 return (nid, encryption_key, privacy_key) 59 60def k3(n): 61 # SALT = s1(“smk3”) 62 salt = s1(b'smk3') 63 # T = AES-CMACSALT (N) 64 t = aes_cmac(salt, n) 65 return aes_cmac(t, b'id64' + b'\x01')[8:] 66 67def k4(n): 68 # SALT = s1(“smk4”) 69 salt = s1(b'smk4') 70 # T = AES-CMACSALT (N) 71 t = aes_cmac(salt, n) 72 return aes_cmac(t, b'id6' + b'\x01')[15] & 0x3f 73 74