You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
47 lines
1.6 KiB
47 lines
1.6 KiB
import struct
|
|
|
|
from Crypto.Hash import CMAC
|
|
from Crypto.Cipher import AES
|
|
|
|
def add_mac(key, trip_cnt, reset_cnt, msg_cnt, msg):
|
|
# TODO: clean up conversion to and from hex
|
|
|
|
addr, payload, bus = msg
|
|
reset_flag = reset_cnt & 0b11
|
|
msg_cnt_flag = msg_cnt & 0b11
|
|
payload = payload[:4]
|
|
|
|
# Step 1: Build Freshness Value (48 bits)
|
|
# [Trip Counter (16 bit)][[Reset Counter (20 bit)][Message Counter (8 bit)][Reset Flag (2 bit)][Padding (2 bit)]
|
|
freshness_value = struct.pack('>HI', trip_cnt, (reset_cnt << 12) | ((msg_cnt & 0xff) << 4) | (reset_flag << 2))
|
|
|
|
# Step 2: Build data to authenticate (96 bits)
|
|
# [Message ID (16 bits)][Payload (32 bits)][Freshness Value (48 bits)]
|
|
to_auth = struct.pack('>H', addr) + payload + freshness_value
|
|
|
|
# Step 3: Calculate CMAC (28 bit)
|
|
cmac = CMAC.new(key, ciphermod=AES)
|
|
cmac.update(to_auth)
|
|
mac = cmac.digest().hex()[:7] # truncated MAC
|
|
|
|
# Step 4: Build message
|
|
# [Payload (32 bit)][Message Counter Flag (2 bit)][Reset Flag (2 bit)][Authenticator (28 bit)]
|
|
msg_cnt_rst_flag = struct.pack('>B', (msg_cnt_flag << 2) | reset_flag).hex()[1]
|
|
msg = payload.hex() + msg_cnt_rst_flag + mac
|
|
payload = bytes.fromhex(msg)
|
|
|
|
return (addr, payload, bus)
|
|
|
|
def build_sync_mac(key, trip_cnt, reset_cnt, id_=0xf):
|
|
id_ = struct.pack('>H', id_) # 16
|
|
trip_cnt = struct.pack('>H', trip_cnt) # 16
|
|
reset_cnt = struct.pack('>I', reset_cnt << 12)[:-1] # 20 + 4 padding
|
|
|
|
to_auth = id_ + trip_cnt + reset_cnt # SecOC 11.4.1.1 page 138
|
|
|
|
cmac = CMAC.new(key, ciphermod=AES)
|
|
cmac.update(to_auth)
|
|
|
|
msg = "0" + cmac.digest().hex()[:7]
|
|
msg = bytes.fromhex(msg)
|
|
return struct.unpack('>I', msg)[0]
|
|
|