Spec with pseudocode and test vectors, APK disassembly, analysis tools, shelved reference Python and the macOS BLE probe. Findings are not yet validated against a real tag. The vendor XAPK and nested lib clone are excluded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EinWd3UT2Xw7UakFtTp6hn
25 lines
852 B
Python
25 lines
852 B
Python
from typing import Any, cast, Union
|
|
|
|
from Crypto.Cipher import AES
|
|
|
|
BM2_ENCRYPTION_KEY = b"\x6c\x65\x61\x67\x65\x6e\x64\xff\xfe\x31\x38\x38\x32\x34\x36\x36"
|
|
|
|
AesBlockSize = 16
|
|
|
|
|
|
def create_aes(key: bytes = BM2_ENCRYPTION_KEY) -> Any:
|
|
return AES.new(key, AES.MODE_CBC, bytes([0] * AesBlockSize))
|
|
|
|
|
|
def pad_to_block(x: bytes) -> bytes:
|
|
required_size = (len(x) + (AesBlockSize - 1)) // AesBlockSize * AesBlockSize
|
|
return x.ljust(required_size, b"\x00")
|
|
|
|
|
|
def encrypt(data: bytes, key: bytes = BM2_ENCRYPTION_KEY) -> bytes:
|
|
return cast(bytes, create_aes(key).encrypt(pad_to_block(data)))
|
|
|
|
|
|
def decrypt(encrypted_data: Union[bytes, bytearray], key: bytes = BM2_ENCRYPTION_KEY) -> bytes:
|
|
return cast(bytes, b''.join(create_aes(key).decrypt(bytes(encrypted_data[i:i + AesBlockSize])) for i in range(0, len(encrypted_data), AesBlockSize)))
|