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:
eddy 2026-07-26 08:18:52 +02:00
commit 7f68e9ad70
2 changed files with 621 additions and 46 deletions

View file

@ -6,6 +6,16 @@
android:gravity="center"
android:padding="32dp">
<ImageButton
android:id="@+id/settingsButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="end"
android:src="@drawable/ic_settings"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="Instellingen"
android:layout_marginBottom="16dp" />
<TextView
android:id="@+id/statusText"
android:layout_width="wrap_content"

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="HMAC Sleutel"
android:textSize="20sp"
android:textStyle="bold"
android:layout_marginBottom="8dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Voer de 64-teken hex sleutel in die de ESP op serial print na opstarten."
android:textSize="14sp"
android:layout_marginBottom="16dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<EditText
android:id="@+id/keyInput"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="C3F17B61..."
android:inputType="textPassword"
android:fontFamily="monospace"
android:textSize="16sp"
android:maxLength="64"
android:letterSpacing="0.05"
android:autofillHints=""
android:layout_marginEnd="8dp" />
<ImageButton
android:id="@+id/toggleVisibility"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_eye_closed"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="Toon/verberg sleutel" />
</LinearLayout>
<TextView
android:id="@+id/keyError"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/holo_red_dark"
android:textSize="14sp"
android:visibility="gone"
android:layout_marginTop="8dp" />
<Button
android:id="@+id/saveButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Opslaan"
android:layout_marginTop="24dp" />
<Button
android:id="@+id/backButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Terug"
android:background="@android:color/transparent"
android:layout_marginTop="8dp" />
</LinearLayout>