ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
noise.cpp
Go to the documentation of this file.
1#include "noise.h"
2#ifdef USE_NOISE
3#include "esphome/core/hal.h"
5#include "esphome/core/log.h"
7
8#include <algorithm>
9#include <cstring>
10
11#include <noise/protocol.h>
12#include <sodium.h>
13
14namespace esphome::noise {
15
16ESPHOME_LOG_TAG(TAG, "noise");
17
19 if (this->psk_ == nullptr) {
20 out.fill(0);
21 return;
22 }
23 progmem_memcpy(out.data(), this->psk_, out.size());
24}
25
26#ifdef USE_NOISE_SPARE_EPHEMERAL
27static constexpr size_t PRIVATE_KEY_SIZE = SPARE_EPHEMERAL_KEY_SIZE;
28static constexpr size_t PUBLIC_KEY_SIZE = SPARE_EPHEMERAL_KEY_SIZE;
29uint8_t spare_ephemeral[SPARE_EPHEMERAL_SIZE]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
30
32 uint8_t *private_key = spare_ephemeral;
33 uint8_t *public_key = spare_ephemeral + PRIVATE_KEY_SIZE;
34 // Same steps as noise-c's keygen; the clamp sets the ready bit
35 if (!random_bytes(private_key, PRIVATE_KEY_SIZE)) {
36 sodium_memzero(spare_ephemeral, sizeof(spare_ephemeral));
37 return;
38 }
39 private_key[0] &= 0xF8;
40 private_key[PRIVATE_KEY_SIZE - 1] = (private_key[PRIVATE_KEY_SIZE - 1] & 0x7F) | 0x40;
41 if (crypto_scalarmult_curve25519_base(public_key, private_key) != 0) {
42 sodium_memzero(spare_ephemeral, sizeof(spare_ephemeral));
43 }
44}
45
47 if (!has_spare_ephemeral()) {
48 return 0;
49 }
50 // noise-c keeps its own copy, so the slot is wiped either way
51 int err = noise_handshakestate_set_local_ephemeral(state, spare_ephemeral, PRIVATE_KEY_SIZE,
52 spare_ephemeral + PRIVATE_KEY_SIZE, PUBLIC_KEY_SIZE);
53 sodium_memzero(spare_ephemeral, sizeof(spare_ephemeral));
54 return err;
55}
56#endif // USE_NOISE_SPARE_EPHEMERAL
57
58const LogString *noise_err_to_logstr(int err) {
59 if (err == NOISE_ERROR_NO_MEMORY)
60 return LOG_STR("NO_MEMORY");
61 if (err == NOISE_ERROR_UNKNOWN_ID)
62 return LOG_STR("UNKNOWN_ID");
63 if (err == NOISE_ERROR_UNKNOWN_NAME)
64 return LOG_STR("UNKNOWN_NAME");
65 if (err == NOISE_ERROR_MAC_FAILURE)
66 return LOG_STR("MAC_FAILURE");
67 if (err == NOISE_ERROR_NOT_APPLICABLE)
68 return LOG_STR("NOT_APPLICABLE");
69 if (err == NOISE_ERROR_SYSTEM)
70 return LOG_STR("SYSTEM");
71 if (err == NOISE_ERROR_REMOTE_KEY_REQUIRED)
72 return LOG_STR("REMOTE_KEY_REQUIRED");
73 if (err == NOISE_ERROR_LOCAL_KEY_REQUIRED)
74 return LOG_STR("LOCAL_KEY_REQUIRED");
75 if (err == NOISE_ERROR_PSK_REQUIRED)
76 return LOG_STR("PSK_REQUIRED");
77 if (err == NOISE_ERROR_INVALID_LENGTH)
78 return LOG_STR("INVALID_LENGTH");
79 if (err == NOISE_ERROR_INVALID_PARAM)
80 return LOG_STR("INVALID_PARAM");
81 if (err == NOISE_ERROR_INVALID_STATE)
82 return LOG_STR("INVALID_STATE");
83 if (err == NOISE_ERROR_INVALID_NONCE)
84 return LOG_STR("INVALID_NONCE");
85 if (err == NOISE_ERROR_INVALID_PRIVATE_KEY)
86 return LOG_STR("INVALID_PRIVATE_KEY");
87 if (err == NOISE_ERROR_INVALID_PUBLIC_KEY)
88 return LOG_STR("INVALID_PUBLIC_KEY");
89 if (err == NOISE_ERROR_INVALID_FORMAT)
90 return LOG_STR("INVALID_FORMAT");
91 if (err == NOISE_ERROR_INVALID_SIGNATURE)
92 return LOG_STR("INVALID_SIGNATURE");
93 return LOG_STR("UNKNOWN");
94}
95
96const LogString *reject_reason_for(int err) {
97 return err == NOISE_ERROR_MAC_FAILURE ? LOG_STR("Handshake MAC failure") : LOG_STR("Handshake error");
98}
99
100size_t format_reject_payload(uint8_t *buf, size_t capacity, const LogString *reason) {
101 if (capacity == 0) {
102 // A caller bug; the MAC_FAILURE_PAYLOAD_SIZE static_asserts at the call
103 // sites make this unreachable, kept as cheap memory safety
104 ESP_LOGVV(TAG, "Reject buffer has no capacity");
105 return 0;
106 }
107 buf[0] = HANDSHAKE_STATUS_REJECT;
108 // The reason may live in PROGMEM on ESP8266; the progmem helpers read RAM and flash alike
109 const char *reason_str = LOG_STR_ARG(reason);
110 size_t reason_len = std::min(ESPHOME_strlen_P(reason_str), capacity - 1);
111 if (reason_len > 0) {
112 // NOLINTNEXTLINE(bugprone-not-null-terminated-result) - binary protocol, not a C string
113 progmem_memcpy(buf + 1, reason_str, reason_len);
114 }
115 return reason_len + 1;
116}
117
118} // namespace esphome::noise
119#endif // USE_NOISE
void load_psk(psk_t &out) const
Copy the key out (flash-aware on ESP8266); all zeros when none is set.
Definition noise.cpp:18
const uint8_t * psk_
Definition noise.h:38
bool state
Definition fan.h:2
std::vector< uint8_t > & out
Definition gif.cpp:49
ESPHOME_LOG_TAG(TAG, "noise")
std::array< uint8_t, 32 > psk_t
Definition noise.h:14
uint8_t spare_ephemeral[SPARE_EPHEMERAL_SIZE]
Definition noise.cpp:29
const LogString * noise_err_to_logstr(int err)
Convert a noise error code to a readable error.
Definition noise.cpp:58
size_t format_reject_payload(uint8_t *buf, size_t capacity, const LogString *reason)
Fill buf with a handshake reject payload (status byte plus the reason text, PROGMEM aware); returns t...
Definition noise.cpp:100
int consume_spare_ephemeral(NoiseHandshakeState *state)
Move the key pair into a handshake that has not started and wipe the slot; 0 unless noise-c rejects i...
Definition noise.cpp:46
bool has_spare_ephemeral()
Definition noise.h:52
const LogString * reject_reason_for(int err)
Reject reason for a failed handshake read.
Definition noise.cpp:96
void prepare_spare_ephemeral()
Fill the slot; blocks for the base point multiply.
Definition noise.cpp:31
bool random_bytes(uint8_t *data, size_t len)
Generate len random bytes using the platform's secure RNG (hardware RNG or OS CSPRNG).
Definition helpers.cpp:20
void progmem_memcpy(void *dst, const void *src, size_t len)
Definition hal.h:56
uint16_t uint16_t & capacity
Definition helpers.cpp:34
struct NoiseHandshakeState_s NoiseHandshakeState
Definition noise.h:10