diff --git a/esphome/components/noise/noise.cpp b/esphome/components/noise/noise.cpp index 7434cb6489..f1cce31eea 100644 --- a/esphome/components/noise/noise.cpp +++ b/esphome/components/noise/noise.cpp @@ -27,9 +27,8 @@ void NoiseContext::load_psk(psk_t &out) const { } #ifdef USE_NOISE_SPARE_EPHEMERAL -static constexpr size_t PRIVATE_KEY_SIZE = 32; -static constexpr size_t PUBLIC_KEY_SIZE = 32; -static_assert(PRIVATE_KEY_SIZE + PUBLIC_KEY_SIZE == SPARE_EPHEMERAL_SIZE); +static constexpr size_t PRIVATE_KEY_SIZE = SPARE_EPHEMERAL_KEY_SIZE; +static constexpr size_t PUBLIC_KEY_SIZE = SPARE_EPHEMERAL_KEY_SIZE; uint8_t spare_ephemeral[SPARE_EPHEMERAL_SIZE]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) void prepare_spare_ephemeral() { diff --git a/esphome/components/noise/noise.h b/esphome/components/noise/noise.h index 5797402a7b..6090440e92 100644 --- a/esphome/components/noise/noise.h +++ b/esphome/components/noise/noise.h @@ -45,13 +45,14 @@ const LogString *noise_err_to_logstr(int err); // One responder ephemeral key pair generated ahead of time (about 60 ms on // ESP8266), refilled by the api server while idle and consumed by the next // handshake of any noise transport; an empty slot means the handshake -// generates its own key. +// generates its own key. The private key stays in RAM until consumed. // Private key then public key; zero when empty -static constexpr size_t SPARE_EPHEMERAL_SIZE = 64; +static constexpr size_t SPARE_EPHEMERAL_KEY_SIZE = 32; +static constexpr size_t SPARE_EPHEMERAL_SIZE = 2 * SPARE_EPHEMERAL_KEY_SIZE; extern uint8_t spare_ephemeral[SPARE_EPHEMERAL_SIZE]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) // Polled every api loop tick, so it must inline. A clamped X25519 private key // always has bit 254 set, so that byte doubles as the ready flag. -inline bool has_spare_ephemeral() { return (spare_ephemeral[31] & 0x40) != 0; } +inline bool has_spare_ephemeral() { return (spare_ephemeral[SPARE_EPHEMERAL_KEY_SIZE - 1] & 0x40) != 0; } /// Fill the slot; blocks for the base point multiply void prepare_spare_ephemeral(); /// Hand the slot's key pair to a handshake that has not started and wipe the diff --git a/tests/components/noise/test_noise_handshake.cpp b/tests/components/noise/test_noise_handshake.cpp index 7e07b18cc3..6621aae23b 100644 --- a/tests/components/noise/test_noise_handshake.cpp +++ b/tests/components/noise/test_noise_handshake.cpp @@ -161,7 +161,7 @@ TEST(NoiseResponderHandshakeTest, FullHandshakeAndTransportRoundTrip) { // responder_e receives the ephemeral public key the responder put on the // wire (the clear text start of its message, taken before the initiator // consumes the buffer in place) -static void run_handshake(NoiseResponderHandshake &responder, uint8_t responder_e[32]) { +static void run_handshake(NoiseResponderHandshake &responder, uint8_t responder_e[SPARE_EPHEMERAL_KEY_SIZE]) { const psk_t psk = make_psk(7); ASSERT_EQ(responder.init(ctx_for(psk), PROLOGUE, sizeof(PROLOGUE)), 0); Initiator initiator(psk, PROLOGUE, sizeof(PROLOGUE)); @@ -170,8 +170,8 @@ static void run_handshake(NoiseResponderHandshake &responder, uint8_t responder_ ASSERT_EQ(responder.read_message(msg, msg_len), 0); size_t reply_len = 0; ASSERT_EQ(responder.write_message(msg, sizeof(msg), reply_len), 0); - ASSERT_GE(reply_len, 32u); - std::memcpy(responder_e, msg, 32); + ASSERT_GE(reply_len, SPARE_EPHEMERAL_KEY_SIZE); + std::memcpy(responder_e, msg, SPARE_EPHEMERAL_KEY_SIZE); ASSERT_EQ(initiator.read_message(msg, reply_len), 0); ASSERT_EQ(responder.action(), Action::ACTION_SPLIT); } @@ -179,7 +179,7 @@ static void run_handshake(NoiseResponderHandshake &responder, uint8_t responder_ TEST(SpareEphemeralTest, EmptySlotLeavesHandshakeToGenerate) { ASSERT_FALSE(has_spare_ephemeral()); NoiseResponderHandshake responder; - uint8_t responder_e[32]; + uint8_t responder_e[SPARE_EPHEMERAL_KEY_SIZE]; run_handshake(responder, responder_e); EXPECT_FALSE(has_spare_ephemeral()); } @@ -209,11 +209,11 @@ TEST(SpareEphemeralTest, ConsumeHandsTheKeyToANewState) { TEST(SpareEphemeralTest, SlotKeyIsOnTheWireAndConsumedOnce) { prepare_spare_ephemeral(); ASSERT_TRUE(has_spare_ephemeral()); - uint8_t expected_pub[32]; - std::memcpy(expected_pub, spare_ephemeral + 32, sizeof(expected_pub)); + uint8_t expected_pub[SPARE_EPHEMERAL_KEY_SIZE]; + std::memcpy(expected_pub, spare_ephemeral + SPARE_EPHEMERAL_KEY_SIZE, sizeof(expected_pub)); NoiseResponderHandshake first; - uint8_t responder_e[32]; + uint8_t responder_e[SPARE_EPHEMERAL_KEY_SIZE]; run_handshake(first, responder_e); // The spare, not a generated key, went out; and it went out once EXPECT_EQ(std::memcmp(responder_e, expected_pub, sizeof(expected_pub)), 0);