miketsai 8fb28087c5 feat(ble): add DrawBoxEnable SET cmd; per-board handshake key; move headers
- event_recorder.c: add SET DRAWBOXENABLE 0/1 BLE command (runtime toggle,
  INI-persistent); expose g_dwDrawBoxEnable extern
- kdp2_host_stream.c: guard draw-box and seg-overlay rendering behind
  g_dwDrawBoxEnable so SET DRAWBOXENABLE 0 cleanly suppresses both
- handshake.c: derive key from runtime VMF_NNM_Get_Kn_Number() instead of
  compile-time constant; each board gets a unique handshake key
- kp_firmware.c: remove startup handshake key print (key is now per-board,
  fixed expected value is no longer meaningful)
- move base64.h / sha256.h / handshake.h from src/host_stream/ to
  include/host_stream/ (proper include path for shared headers)
2026-08-04 18:43:54 +08:00

72 lines
2.5 KiB
C

/*
* handshake.h — BLE Challenge-Response Authentication Protocol
*
* Protocol flow:
* 1. Device sends: {"response_type":"handshake_challenge","content":{"challenge":"<base64(R)>"}}
* 2. iPad computes: SHA256(R || Key) and replies with base64 of the digest
* 3. Device verifies and sends: {"response_type":"handshake_confirm","content":{"status":"success"|"failed"}}
*
* Key derivation: SHA256("29C310F5") → first 16 bytes XOR 0x5A
*/
#ifndef HANDSHAKE_H
#define HANDSHAKE_H
#include <stdint.h>
#include <stddef.h>
#define HANDSHAKE_KEY_LEN 16
#define HANDSHAKE_R_LEN 16
#define HANDSHAKE_TIMEOUT_SEC 5
typedef enum {
HS_STATE_IDLE = 0,
HS_STATE_WAIT_RESPONSE,
HS_STATE_SUCCESS,
HS_STATE_FAILED
} handshake_state_t;
typedef struct {
handshake_state_t state;
uint8_t key[HANDSHAKE_KEY_LEN];
uint8_t R[HANDSHAKE_R_LEN];
} handshake_ctx_t;
/* Derive the 16-byte handshake key: SHA256(HANDSHAKE_KN_STR)[0..15] XOR 0x5A */
void handshake_derive_key(uint8_t out_key[HANDSHAKE_KEY_LEN]);
/* Print key bytes to stdout as space-separated hex (e.g., "58 48 c8 ff ...") */
void handshake_print_key(const uint8_t key[HANDSHAKE_KEY_LEN]);
/* Initialise ctx: derive key, set state=IDLE, zero R */
void handshake_init(handshake_ctx_t *ctx);
/* Generate random R, set state=WAIT_RESPONSE, write JSON to out_json_buf.
* Returns 0 on success, -1 on error. */
int handshake_build_challenge(handshake_ctx_t *ctx,
char *out_json_buf, size_t buf_size);
/* Validate iPad response JSON (must contain "response" field with base64 value).
* Returns 1: success (state→SUCCESS)
* 0: wrong answer (state→FAILED)
* -1: malformed JSON
* -2: timeout */
int handshake_process_response(handshake_ctx_t *ctx, const char *json_str);
/* Build confirm JSON. success=1 → {"status":"success"}; success=0 → {"status":"failed","reason":"..."}
* reason_str may be NULL (defaults to "invalid_response").
* Returns 0. */
int handshake_build_confirm(handshake_ctx_t *ctx, int success,
const char *reason_str,
char *out_json_buf, size_t buf_size);
/* Reset state to IDLE, zero R (key is retained) */
void handshake_reset(handshake_ctx_t *ctx);
/* Return current state */
handshake_state_t handshake_get_state(const handshake_ctx_t *ctx);
/* Return 1 if WAIT_RESPONSE and timeout expired, else 0 */
int handshake_check_timeout(handshake_ctx_t *ctx);
#endif /* HANDSHAKE_H */