Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
pairing_responder.cpp
Go to the documentation of this file.
1/// @file pairing_responder.cpp
2/// @brief Pure decision logic for the device-role key-extraction responder.
3/// @ingroup hioc_hub
4
5#include "pairing_responder.h"
6
7#include "proto_commands.h"
8
9#include <cstring>
10
11namespace esphome {
12namespace home_io_control {
14
16 switch (state) {
18 return "disarmed";
20 return "armed_idle";
22 return "sent_discover_resp";
24 return "sent_confirm_ack";
26 return "sent_challenge";
28 return "extracted";
29 }
30 return "disarmed";
31}
32
39
46
47bool on_key_init(ResponderContext &ctx, const uint8_t challenge[HMAC_SIZE], const uint8_t hub_node_id[NODE_ID_SIZE]) {
48 // Both pre-key-exchange states are accepted: a hub that insists on our 0x2D arrives here from
49 // SENT_CONFIRM_ACK, one that gives up waiting for it arrives straight from SENT_DISCOVER_RESP.
51 memcpy(ctx.challenge, challenge, HMAC_SIZE);
52 memcpy(ctx.hub_node_id, hub_node_id, NODE_ID_SIZE);
54 return true;
55 }
56 // Retry: the hub already got past this phase once — keep the previously-stored challenge and
57 // hub node ID, just resend the same 0x3C (see doxygen for why regenerating would be wrong).
59}
60
61bool on_key_transfer(ResponderContext &ctx, const uint8_t transfer_payload[AES_KEY_SIZE]) {
63 return false;
64 if (!recover_system_key_from_transfer(transfer_payload, ctx.challenge, ctx.recovered_key))
65 return false;
67 return true;
68}
69
70} // namespace pairing_responder
71} // namespace home_io_control
72} // namespace esphome
bool on_key_transfer(ResponderContext &ctx, const uint8_t transfer_payload[AES_KEY_SIZE])
Decide how to react to an inbound CMD_KEY_TRANSFER (0x32) while armed.
const char * responder_stage_name(ResponderState state)
Get a short, log/telemetry-friendly name for a responder state.
bool on_discover_confirm(ResponderContext &ctx)
Decide how to react to an inbound CMD_DISCOVER_CONFIRM (0x2C) addressed to our throwaway ID.
bool on_key_init(ResponderContext &ctx, const uint8_t challenge[HMAC_SIZE], const uint8_t hub_node_id[NODE_ID_SIZE])
Decide how to react to an inbound CMD_KEY_INIT (0x31) addressed to our throwaway ID.
ResponderState
State machine for the device-role key-extraction responder.
@ ARMED_IDLE
Armed, listening for a discovery request (0x28).
@ SENT_DISCOVER_RESP
Replied to discovery (0x29); waiting for discovery-confirm (0x2C) or key-init (0x31).
@ SENT_CONFIRM_ACK
Acknowledged discovery-confirm (0x2D); waiting for key-init (0x31).
@ DISARMED
Not armed; 0x28/0x2C/0x31/0x32 traffic is ignored.
@ SENT_CHALLENGE
Replied to key-init with our challenge (0x3C); waiting for key-transfer (0x32).
@ EXTRACTED
System key recovered from a valid 0x32; the hub disarms immediately after.
bool on_discover_request(ResponderContext &ctx)
Decide how to react to an inbound CMD_DISCOVER_REQ (0x28) while armed.
static constexpr uint8_t NODE_ID_SIZE
Device/node addresses are 3 bytes (e.g., "123ABC").
Definition proto_sizes.h:20
bool recover_system_key_from_transfer(const uint8_t transfer_payload[AES_KEY_SIZE], const uint8_t challenge[HMAC_SIZE], uint8_t out_key[AES_KEY_SIZE])
Recover the system key from a CMD_KEY_TRANSFER payload.
static constexpr uint8_t HMAC_SIZE
Authentication HMAC is 6 bytes (truncated AES output).
Definition proto_sizes.h:22
static constexpr uint8_t AES_KEY_SIZE
AES-128 key size.
Definition proto_sizes.h:23
Pure decision logic for the device-role "Accept Foreign Pairing" (system-key extraction) responder.
Command builders for the IO‑Homecontrol protocol.
uint8_t hub_node_id[NODE_ID_SIZE]
Foreign hub's real node ID, captured from the 0x31's src.
uint8_t challenge[HMAC_SIZE]
Our challenge, generated on the first 0x31 of an attempt.
uint8_t recovered_key[AES_KEY_SIZE]
Recovered system key; valid once state == EXTRACTED.