btstack/test/mesh/mesh_crypto.py

74 lines
2.0 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# BlueKitchen GmbH (c) 2019
# pip3 install pycryptodomex
# implementation of the Bluetooth SIG Mesh crypto functions using pycryptodomex
from Cryptodome.Cipher import AES
from Cryptodome.Hash import CMAC
def aes_cmac(k, n):
cobj = CMAC.new(k, ciphermod=AES)
cobj.update(n)
return cobj.digest()
def aes_ccm_encrypt(key, nonce, message, additional_data, mac_len):
cipher = AES.new(key, AES.MODE_CCM, nonce=nonce, mac_len=mac_len)
cipher.update(additional_data)
ciphertext, tag = cipher.encrypt_and_digest(message)
return ciphertext, tag
def aes_ccm_decrypt(key, nonce, message, additional_data, mac_len, mac_tag):
cipher = AES.new(key, AES.MODE_CCM, nonce=nonce, mac_len=mac_len)
cipher.update(additional_data)
try:
ciphertext = cipher.decrypt_and_verify(message, mac_tag)
return ciphertext
except ValueError:
return None
def s1(m):
# s1(M) = AES-CMACZERO (M)
zero_key = bytes(16)
return aes_cmac(zero_key, m)
def k1(n, salt, p):
# T = AES-CMACSALT (N)
t = aes_cmac(salt, n)
# k1(N, SALT, P) = AES-CMACT (P)
return aes_cmac(t, p)
def k2(n, p):
# SALT = s1(“smk2”)
salt = s1(b'smk2')
# T = AES-CMACSALT (N)
t = aes_cmac(salt, n)
# T0 = empty string (zero length)
t0 = b''
# T1 = AES-CMACT (T0 || P || 0x01)
t1 = aes_cmac(t, t0 + p + b'\x01')
# T2 = AES-CMACT (T1 || P || 0x02)
t2 = aes_cmac(t, t1 + p + b'\x02')
# T3 = AES-CMACT (T2 || P || 0x03)
t3 = aes_cmac(t, t2 + p + b'\x03')
nid = t1[15] & 0x7f
encryption_key = t2
privacy_key = t3
return (nid, encryption_key, privacy_key)
def k3(n):
# SALT = s1(“smk3”)
salt = s1(b'smk3')
# T = AES-CMACSALT (N)
t = aes_cmac(salt, n)
return aes_cmac(t, b'id64' + b'\x01')[8:]
def k4(n):
# SALT = s1(“smk4”)
salt = s1(b'smk4')
# T = AES-CMACSALT (N)
t = aes_cmac(salt, n)
return aes_cmac(t, b'id6' + b'\x01')[15] & 0x3f