Add BLE security: Just Works pairing + HMAC-SHA256 authentication
Two-layer security for the BLE relay: 1. BLE Just Works pairing (link-layer encryption) - ESP32 requires bonding before accepting writes - Characteristic permissions set to ESP_GATT_PERM_WRITE_ENCRYPTED - IO capability NO_INPUT_NO_OUTPUT (no passkey needed) - LE Secure Connections with bonding (ESP_LE_AUTH_REQ_SC_BOND) 2. HMAC-SHA256 authentication (application-level) - 32-byte shared secret in src/hmac_key.h (generated, gitignored) - Each command signed: HMAC-SHA256(key, command || sequence) - 37-byte packet format: [cmd:1][seq:4][hmac:32] - Sequence counter prevents replay (strictly increasing, starts at 1) - mbedtls on ESP, javax.crypto.Mac on Android Key management: - tools/generate_hmac_key.py generates random key + writes src/hmac_key.h - ESP prints hex key to serial 5 seconds after boot - Android app: SettingsActivity with eye-toggle password field - Key stored in SharedPreferences, supports multiple ESP modules Other changes: - Android app: bonding flow (createBond -> BOND_BONDED -> discover) - Android app: MTU negotiation (request 256) - Android app: settings button (gear icon) in main screen - Fix: sequence counter starts at 1 to prevent first-packet rejection - Updated README with full security documentation
This commit is contained in:
parent
7c9dde172a
commit
7f68e9ad70
13 changed files with 621 additions and 46 deletions
53
tools/generate_hmac_key.py
Normal file
53
tools/generate_hmac_key.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generate src/hmac_key.h with a random 32-byte HMAC-SHA256 key.
|
||||
|
||||
Usage:
|
||||
python3 tools/generate_hmac_key.py
|
||||
|
||||
This creates src/hmac_key.h (gitignored) and prints the hex key to stdout.
|
||||
The hex key should be entered in the Android app's Settings screen.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import binascii
|
||||
|
||||
KEY_LENGTH = 32
|
||||
OUTPUT_FILE = os.path.join("src", "hmac_key.h")
|
||||
|
||||
|
||||
def generate():
|
||||
key = os.urandom(KEY_LENGTH)
|
||||
hex_key = binascii.hexlify(key).decode().upper()
|
||||
|
||||
header = f"""#ifndef HMAC_KEY_H
|
||||
#define HMAC_KEY_H
|
||||
|
||||
// AUTO-GENERATED by tools/generate_hmac_key.py
|
||||
// Do NOT commit this file. Do NOT edit by hand.
|
||||
// To regenerate: python3 tools/generate_hmac_key.py
|
||||
|
||||
const uint8_t HMAC_KEY[{KEY_LENGTH}] = {{
|
||||
{', '.join(f'0x{b:02x}' for b in key)}
|
||||
}};
|
||||
|
||||
#endif // HMAC_KEY_H
|
||||
"""
|
||||
|
||||
os.makedirs("src", exist_ok=True)
|
||||
with open(OUTPUT_FILE, "w") as f:
|
||||
f.write(header)
|
||||
|
||||
print(f"HMAC key written to {OUTPUT_FILE}")
|
||||
print(f"Enter this key in the Android app Settings:")
|
||||
print(f" {hex_key}")
|
||||
print()
|
||||
print(f"ESP serial output after boot will show the same key.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if os.path.exists(OUTPUT_FILE):
|
||||
overwrite = input(f"{OUTPUT_FILE} already exists. Overwrite? [y/N] ")
|
||||
if overwrite.lower() != 'y':
|
||||
print("Aborted.")
|
||||
sys.exit(0)
|
||||
generate()
|
||||
Loading…
Reference in a new issue