ESPHome 2026.3.0-dev
Loading...
Searching...
No Matches
api_frame_helper_noise.cpp
Go to the documentation of this file.
2#ifdef USE_API
3#ifdef USE_API_NOISE
4#include "api_connection.h" // For ClientInfo struct
7#include "esphome/core/hal.h"
9#include "esphome/core/log.h"
10#include "proto.h"
11#include <cstring>
12#include <cinttypes>
13
14#ifdef USE_ESP8266
15#include <pgmspace.h>
16#endif
17
18namespace esphome::api {
19
20static const char *const TAG = "api.noise";
21#ifdef USE_ESP8266
22static constexpr char PROLOGUE_INIT[] PROGMEM = "NoiseAPIInit";
23#else
24static const char *const PROLOGUE_INIT = "NoiseAPIInit";
25#endif
26static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit")
27
28// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
29static constexpr size_t API_MAX_LOG_BYTES = 168;
30
31#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
32#define HELPER_LOG(msg, ...) \
33 do { \
34 char peername_buf[socket::SOCKADDR_STR_LEN]; \
35 this->get_peername_to(peername_buf); \
36 ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername_buf, ##__VA_ARGS__); \
37 } while (0)
38#else
39#define HELPER_LOG(msg, ...) ((void) 0)
40#endif
41
42#ifdef HELPER_LOG_PACKETS
43#define LOG_PACKET_RECEIVED(buffer) \
44 do { \
45 char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
46 ESP_LOGVV(TAG, "Received frame: %s", \
47 format_hex_pretty_to(hex_buf_, (buffer).data(), \
48 (buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \
49 } while (0)
50#define LOG_PACKET_SENDING(data, len) \
51 do { \
52 char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
53 ESP_LOGVV(TAG, "Sending raw: %s", \
54 format_hex_pretty_to(hex_buf_, data, (len) < API_MAX_LOG_BYTES ? (len) : API_MAX_LOG_BYTES)); \
55 } while (0)
56#else
57#define LOG_PACKET_RECEIVED(buffer) ((void) 0)
58#define LOG_PACKET_SENDING(data, len) ((void) 0)
59#endif
60
62const LogString *noise_err_to_logstr(int err) {
63 if (err == NOISE_ERROR_NO_MEMORY)
64 return LOG_STR("NO_MEMORY");
65 if (err == NOISE_ERROR_UNKNOWN_ID)
66 return LOG_STR("UNKNOWN_ID");
67 if (err == NOISE_ERROR_UNKNOWN_NAME)
68 return LOG_STR("UNKNOWN_NAME");
69 if (err == NOISE_ERROR_MAC_FAILURE)
70 return LOG_STR("MAC_FAILURE");
71 if (err == NOISE_ERROR_NOT_APPLICABLE)
72 return LOG_STR("NOT_APPLICABLE");
73 if (err == NOISE_ERROR_SYSTEM)
74 return LOG_STR("SYSTEM");
75 if (err == NOISE_ERROR_REMOTE_KEY_REQUIRED)
76 return LOG_STR("REMOTE_KEY_REQUIRED");
77 if (err == NOISE_ERROR_LOCAL_KEY_REQUIRED)
78 return LOG_STR("LOCAL_KEY_REQUIRED");
79 if (err == NOISE_ERROR_PSK_REQUIRED)
80 return LOG_STR("PSK_REQUIRED");
81 if (err == NOISE_ERROR_INVALID_LENGTH)
82 return LOG_STR("INVALID_LENGTH");
83 if (err == NOISE_ERROR_INVALID_PARAM)
84 return LOG_STR("INVALID_PARAM");
85 if (err == NOISE_ERROR_INVALID_STATE)
86 return LOG_STR("INVALID_STATE");
87 if (err == NOISE_ERROR_INVALID_NONCE)
88 return LOG_STR("INVALID_NONCE");
89 if (err == NOISE_ERROR_INVALID_PRIVATE_KEY)
90 return LOG_STR("INVALID_PRIVATE_KEY");
91 if (err == NOISE_ERROR_INVALID_PUBLIC_KEY)
92 return LOG_STR("INVALID_PUBLIC_KEY");
93 if (err == NOISE_ERROR_INVALID_FORMAT)
94 return LOG_STR("INVALID_FORMAT");
95 if (err == NOISE_ERROR_INVALID_SIGNATURE)
96 return LOG_STR("INVALID_SIGNATURE");
97 return LOG_STR("UNKNOWN");
98}
99
102 APIError err = init_common_();
103 if (err != APIError::OK) {
104 return err;
105 }
106
107 // init prologue
108 size_t old_size = prologue_.size();
109 prologue_.resize(old_size + PROLOGUE_INIT_LEN);
110#ifdef USE_ESP8266
111 memcpy_P(prologue_.data() + old_size, PROLOGUE_INIT, PROLOGUE_INIT_LEN);
112#else
113 std::memcpy(prologue_.data() + old_size, PROLOGUE_INIT, PROLOGUE_INIT_LEN);
114#endif
115
117 return APIError::OK;
118}
119// Helper for handling handshake frame errors
121 if (aerr == APIError::BAD_INDICATOR) {
122 send_explicit_handshake_reject_(LOG_STR("Bad indicator byte"));
123 } else if (aerr == APIError::BAD_HANDSHAKE_PACKET_LEN) {
124 send_explicit_handshake_reject_(LOG_STR("Bad handshake packet len"));
125 }
126 return aerr;
127}
128
129// Helper for handling noise library errors
130APIError APINoiseFrameHelper::handle_noise_error_(int err, const LogString *func_name, APIError api_err) {
131 if (err != 0) {
133 HELPER_LOG("%s failed: %s", LOG_STR_ARG(func_name), LOG_STR_ARG(noise_err_to_logstr(err)));
134 return api_err;
135 }
136 return APIError::OK;
137}
138
141 // Cache ready() outside the loop. On ESP8266 LWIP raw TCP, ready() returns false once
142 // the rx buffer is consumed. Re-checking each iteration would block handshake writes
143 // that must follow reads, deadlocking the handshake. state_action() will return
144 // WOULD_BLOCK when no more data is available to read.
145 bool socket_ready = this->socket_->ready();
146 while (state_ != State::DATA && socket_ready) {
147 APIError err = state_action_();
148 if (err == APIError::WOULD_BLOCK) {
149 break;
150 }
151 if (err != APIError::OK) {
152 return err;
153 }
154 }
155
156 // Use base class implementation for buffer sending
157 return APIFrameHelper::loop();
158}
159
170 // read header
171 if (rx_header_buf_len_ < 3) {
172 // no header information yet
173 uint8_t to_read = 3 - rx_header_buf_len_;
174 ssize_t received = this->socket_->read(&rx_header_buf_[rx_header_buf_len_], to_read);
175 APIError err = handle_socket_read_result_(received);
176 if (err != APIError::OK) {
177 return err;
178 }
179 rx_header_buf_len_ += static_cast<uint8_t>(received);
180 if (static_cast<uint8_t>(received) != to_read) {
181 // not a full read
183 }
184
185 if (rx_header_buf_[0] != 0x01) {
187 HELPER_LOG("Bad indicator byte %u", rx_header_buf_[0]);
189 }
190 // header reading done
191 }
192
193 // read body
194 uint16_t msg_size = (((uint16_t) rx_header_buf_[1]) << 8) | rx_header_buf_[2];
195
196 // Check against size limits to prevent OOM: MAX_HANDSHAKE_SIZE for handshake, MAX_MESSAGE_SIZE for data
197 bool is_data = (state_ == State::DATA);
198 uint16_t limit = is_data ? MAX_MESSAGE_SIZE : MAX_HANDSHAKE_SIZE;
199 if (msg_size > limit) {
201 HELPER_LOG("Bad packet: message size %u exceeds maximum %u", msg_size, limit);
203 }
204
205 // Reserve space for body (+ null terminator in DATA state so protobuf
206 // StringRef fields can be safely null-terminated in-place after decode.
207 // During handshake, rx_buf_.size() is used in prologue construction, so
208 // the buffer must be exactly msg_size to avoid prologue mismatch.)
209 uint16_t alloc_size = msg_size + (is_data ? RX_BUF_NULL_TERMINATOR : 0);
210 if (this->rx_buf_.size() != alloc_size) {
211 this->rx_buf_.resize(alloc_size);
212 }
213
214 if (rx_buf_len_ < msg_size) {
215 // more data to read
216 uint16_t to_read = msg_size - rx_buf_len_;
217 ssize_t received = this->socket_->read(&rx_buf_[rx_buf_len_], to_read);
218 APIError err = handle_socket_read_result_(received);
219 if (err != APIError::OK) {
220 return err;
221 }
222 rx_buf_len_ += static_cast<uint16_t>(received);
223 if (static_cast<uint16_t>(received) != to_read) {
224 // not all read
226 }
227 }
228
229 LOG_PACKET_RECEIVED(this->rx_buf_);
230
231 // Clear state for next frame (rx_buf_ still contains data for caller)
232 this->rx_buf_len_ = 0;
233 this->rx_header_buf_len_ = 0;
234
235 return APIError::OK;
236}
237
248 int err;
249 APIError aerr;
250 if (state_ == State::INITIALIZE) {
251 HELPER_LOG("Bad state for method: %d", (int) state_);
252 return APIError::BAD_STATE;
253 }
255 // waiting for client hello
256 aerr = this->try_read_frame_();
257 if (aerr != APIError::OK) {
259 }
260 // ignore contents, may be used in future for flags
261 // Resize for: existing prologue + 2 size bytes + frame data
262 size_t old_size = this->prologue_.size();
263 this->prologue_.resize(old_size + 2 + this->rx_buf_.size());
264 this->prologue_[old_size] = (uint8_t) (this->rx_buf_.size() >> 8);
265 this->prologue_[old_size + 1] = (uint8_t) this->rx_buf_.size();
266 std::memcpy(this->prologue_.data() + old_size + 2, this->rx_buf_.data(), this->rx_buf_.size());
267
269 }
271 // send server hello
272 const std::string &name = App.get_name();
273 char mac[MAC_ADDRESS_BUFFER_SIZE];
275
276 // Calculate positions and sizes
277 size_t name_len = name.size() + 1; // including null terminator
278 size_t name_offset = 1;
279 size_t mac_offset = name_offset + name_len;
280 size_t total_size = 1 + name_len + MAC_ADDRESS_BUFFER_SIZE;
281
282 // 1 (proto) + name (max ESPHOME_DEVICE_NAME_MAX_LEN) + 1 (name null)
283 // + mac (MAC_ADDRESS_BUFFER_SIZE - 1) + 1 (mac null)
284 constexpr size_t max_msg_size = 1 + ESPHOME_DEVICE_NAME_MAX_LEN + 1 + MAC_ADDRESS_BUFFER_SIZE;
285 uint8_t msg[max_msg_size];
286
287 // chosen proto
288 msg[0] = 0x01;
289
290 // node name, terminated by null byte
291 std::memcpy(msg + name_offset, name.c_str(), name_len);
292 // node mac, terminated by null byte
293 std::memcpy(msg + mac_offset, mac, MAC_ADDRESS_BUFFER_SIZE);
294
295 aerr = write_frame_(msg, total_size);
296 if (aerr != APIError::OK)
297 return aerr;
298
299 // start handshake
300 aerr = init_handshake_();
301 if (aerr != APIError::OK)
302 return aerr;
303
305 }
306 if (state_ == State::HANDSHAKE) {
307 int action = noise_handshakestate_get_action(handshake_);
308 if (action == NOISE_ACTION_READ_MESSAGE) {
309 // waiting for handshake msg
310 aerr = this->try_read_frame_();
311 if (aerr != APIError::OK) {
313 }
314
315 if (this->rx_buf_.empty()) {
316 send_explicit_handshake_reject_(LOG_STR("Empty handshake message"));
318 } else if (this->rx_buf_[0] != 0x00) {
319 HELPER_LOG("Bad handshake error byte: %u", this->rx_buf_[0]);
320 send_explicit_handshake_reject_(LOG_STR("Bad handshake error byte"));
322 }
323
324 NoiseBuffer mbuf;
325 noise_buffer_init(mbuf);
326 noise_buffer_set_input(mbuf, this->rx_buf_.data() + 1, this->rx_buf_.size() - 1);
327 err = noise_handshakestate_read_message(handshake_, &mbuf, nullptr);
328 if (err != 0) {
329 // Special handling for MAC failure
330 send_explicit_handshake_reject_(err == NOISE_ERROR_MAC_FAILURE ? LOG_STR("Handshake MAC failure")
331 : LOG_STR("Handshake error"));
332 return handle_noise_error_(err, LOG_STR("noise_handshakestate_read_message"),
334 }
335
337 if (aerr != APIError::OK)
338 return aerr;
339 } else if (action == NOISE_ACTION_WRITE_MESSAGE) {
340 uint8_t buffer[65];
341 NoiseBuffer mbuf;
342 noise_buffer_init(mbuf);
343 noise_buffer_set_output(mbuf, buffer + 1, sizeof(buffer) - 1);
344
345 err = noise_handshakestate_write_message(handshake_, &mbuf, nullptr);
346 APIError aerr_write = handle_noise_error_(err, LOG_STR("noise_handshakestate_write_message"),
348 if (aerr_write != APIError::OK)
349 return aerr_write;
350 buffer[0] = 0x00; // success
351
352 aerr = write_frame_(buffer, mbuf.size + 1);
353 if (aerr != APIError::OK)
354 return aerr;
356 if (aerr != APIError::OK)
357 return aerr;
358 } else {
359 // bad state for action
361 HELPER_LOG("Bad action for handshake: %d", action);
363 }
364 }
366 return APIError::BAD_STATE;
367 }
368 return APIError::OK;
369}
371 // Max reject message: "Bad handshake packet len" (24) + 1 (failure byte) = 25 bytes
372 uint8_t data[32];
373 data[0] = 0x01; // failure
374
375#ifdef USE_STORE_LOG_STR_IN_FLASH
376 // On ESP8266 with flash strings, we need to use PROGMEM-aware functions
377 size_t reason_len = strlen_P(reinterpret_cast<PGM_P>(reason));
378 if (reason_len > 0) {
379 memcpy_P(data + 1, reinterpret_cast<PGM_P>(reason), reason_len);
380 }
381#else
382 // Normal memory access
383 const char *reason_str = LOG_STR_ARG(reason);
384 size_t reason_len = strlen(reason_str);
385 if (reason_len > 0) {
386 // NOLINTNEXTLINE(bugprone-not-null-terminated-result) - binary protocol, not a C string
387 std::memcpy(data + 1, reason_str, reason_len);
388 }
389#endif
390
391 size_t data_size = reason_len + 1;
392
393 // temporarily remove failed state
394 auto orig_state = state_;
396 write_frame_(data, data_size);
397 state_ = orig_state;
398}
400 APIError aerr = this->state_action_();
401 if (aerr != APIError::OK) {
402 return aerr;
403 }
404
405 if (this->state_ != State::DATA) {
407 }
408
409 aerr = this->try_read_frame_();
410 if (aerr != APIError::OK)
411 return aerr;
412
413 NoiseBuffer mbuf;
414 noise_buffer_init(mbuf);
415 // read_packet() must only be called in DATA state; the extra
416 // RX_BUF_NULL_TERMINATOR byte is only allocated in DATA state
417 // (see try_read_frame_), so calling this during handshake would
418 // underflow the size calculation below.
419#ifdef ESPHOME_DEBUG_API
420 assert(this->state_ == State::DATA);
421#endif
422 // rx_buf_ has RX_BUF_NULL_TERMINATOR extra byte for null termination
423 // (only added in DATA state — see try_read_frame_), so subtract it
424 // to get the actual encrypted data size for decryption.
425 size_t encrypted_size = this->rx_buf_.size() - RX_BUF_NULL_TERMINATOR;
426 noise_buffer_set_inout(mbuf, this->rx_buf_.data(), encrypted_size, encrypted_size);
427 int err = noise_cipherstate_decrypt(this->recv_cipher_, &mbuf);
428 APIError decrypt_err =
429 handle_noise_error_(err, LOG_STR("noise_cipherstate_decrypt"), APIError::CIPHERSTATE_DECRYPT_FAILED);
430 if (decrypt_err != APIError::OK) {
431 return decrypt_err;
432 }
433
434 uint16_t msg_size = mbuf.size;
435 uint8_t *msg_data = this->rx_buf_.data();
436 if (msg_size < 4) {
437 this->state_ = State::FAILED;
438 HELPER_LOG("Bad data packet: size %d too short", msg_size);
440 }
441
442 uint16_t type = (((uint16_t) msg_data[0]) << 8) | msg_data[1];
443 uint16_t data_len = (((uint16_t) msg_data[2]) << 8) | msg_data[3];
444 if (data_len > msg_size - 4) {
445 this->state_ = State::FAILED;
446 HELPER_LOG("Bad data packet: data_len %u greater than msg_size %u", data_len, msg_size);
448 }
449
450 buffer->data = msg_data + 4; // Skip 4-byte header (type + length)
451 buffer->data_len = data_len;
452 buffer->type = type;
453 return APIError::OK;
454}
456 // Resize to include MAC space (required for Noise encryption)
457 buffer.get_buffer()->resize(buffer.get_buffer()->size() + frame_footer_size_);
458 MessageInfo msg{type, 0,
459 static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_ - frame_footer_size_)};
460 return write_protobuf_messages(buffer, std::span<const MessageInfo>(&msg, 1));
461}
462
463APIError APINoiseFrameHelper::write_protobuf_messages(ProtoWriteBuffer buffer, std::span<const MessageInfo> messages) {
464 APIError aerr = state_action_();
465 if (aerr != APIError::OK) {
466 return aerr;
467 }
468
469 if (state_ != State::DATA) {
471 }
472
473 if (messages.empty()) {
474 return APIError::OK;
475 }
476
477 uint8_t *buffer_data = buffer.get_buffer()->data();
478
479 // Stack-allocated iovec array - no heap allocation
481 uint16_t total_write_len = 0;
482
483 // We need to encrypt each message in place
484 for (const auto &msg : messages) {
485 // The buffer already has padding at offset
486 uint8_t *buf_start = buffer_data + msg.offset;
487
488 // Write noise header
489 buf_start[0] = 0x01; // indicator
490 // buf_start[1], buf_start[2] to be set after encryption
491
492 // Write message header (to be encrypted)
493 constexpr uint8_t msg_offset = 3;
494 buf_start[msg_offset] = static_cast<uint8_t>(msg.message_type >> 8); // type high byte
495 buf_start[msg_offset + 1] = static_cast<uint8_t>(msg.message_type); // type low byte
496 buf_start[msg_offset + 2] = static_cast<uint8_t>(msg.payload_size >> 8); // data_len high byte
497 buf_start[msg_offset + 3] = static_cast<uint8_t>(msg.payload_size); // data_len low byte
498 // payload data is already in the buffer starting at offset + 7
499
500 // Make sure we have space for MAC
501 // The buffer should already have been sized appropriately
502
503 // Encrypt the message in place
504 NoiseBuffer mbuf;
505 noise_buffer_init(mbuf);
506 noise_buffer_set_inout(mbuf, buf_start + msg_offset, 4 + msg.payload_size,
507 4 + msg.payload_size + frame_footer_size_);
508
509 int err = noise_cipherstate_encrypt(send_cipher_, &mbuf);
510 APIError aerr =
511 handle_noise_error_(err, LOG_STR("noise_cipherstate_encrypt"), APIError::CIPHERSTATE_ENCRYPT_FAILED);
512 if (aerr != APIError::OK)
513 return aerr;
514
515 // Fill in the encrypted size
516 buf_start[1] = static_cast<uint8_t>(mbuf.size >> 8);
517 buf_start[2] = static_cast<uint8_t>(mbuf.size);
518
519 // Add iovec for this encrypted message
520 size_t msg_len = static_cast<size_t>(3 + mbuf.size); // indicator + size + encrypted data
521 iovs.push_back({buf_start, msg_len});
522 total_write_len += msg_len;
523 }
524
525 // Send all encrypted messages in one writev call
526 return this->write_raw_(iovs.data(), iovs.size(), total_write_len);
527}
528
529APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, uint16_t len) {
530 uint8_t header[3];
531 header[0] = 0x01; // indicator
532 header[1] = (uint8_t) (len >> 8);
533 header[2] = (uint8_t) len;
534
535 struct iovec iov[2];
536 iov[0].iov_base = header;
537 iov[0].iov_len = 3;
538 if (len == 0) {
539 return this->write_raw_(iov, 1, 3); // Just header
540 }
541 iov[1].iov_base = const_cast<uint8_t *>(data);
542 iov[1].iov_len = len;
543
544 return this->write_raw_(iov, 2, 3 + len); // Header + data
545}
546
552 int err;
553 memset(&nid_, 0, sizeof(nid_));
554 // const char *proto = "Noise_NNpsk0_25519_ChaChaPoly_SHA256";
555 // err = noise_protocol_name_to_id(&nid_, proto, strlen(proto));
556 nid_.pattern_id = NOISE_PATTERN_NN;
557 nid_.cipher_id = NOISE_CIPHER_CHACHAPOLY;
558 nid_.dh_id = NOISE_DH_CURVE25519;
559 nid_.prefix_id = NOISE_PREFIX_STANDARD;
560 nid_.hybrid_id = NOISE_DH_NONE;
561 nid_.hash_id = NOISE_HASH_SHA256;
562 nid_.modifier_ids[0] = NOISE_MODIFIER_PSK0;
563
564 err = noise_handshakestate_new_by_id(&handshake_, &nid_, NOISE_ROLE_RESPONDER);
565 APIError aerr =
566 handle_noise_error_(err, LOG_STR("noise_handshakestate_new_by_id"), APIError::HANDSHAKESTATE_SETUP_FAILED);
567 if (aerr != APIError::OK)
568 return aerr;
569
570 const auto &psk = this->ctx_.get_psk();
571 err = noise_handshakestate_set_pre_shared_key(handshake_, psk.data(), psk.size());
572 aerr = handle_noise_error_(err, LOG_STR("noise_handshakestate_set_pre_shared_key"),
574 if (aerr != APIError::OK)
575 return aerr;
576
577 err = noise_handshakestate_set_prologue(handshake_, prologue_.data(), prologue_.size());
578 aerr = handle_noise_error_(err, LOG_STR("noise_handshakestate_set_prologue"), APIError::HANDSHAKESTATE_SETUP_FAILED);
579 if (aerr != APIError::OK)
580 return aerr;
581 // set_prologue copies it into handshakestate, so we can get rid of it now
582 // Use swap idiom to actually release memory (= {} only clears size, not capacity)
583 std::vector<uint8_t>().swap(prologue_);
584
585 err = noise_handshakestate_start(handshake_);
586 aerr = handle_noise_error_(err, LOG_STR("noise_handshakestate_start"), APIError::HANDSHAKESTATE_SETUP_FAILED);
587 if (aerr != APIError::OK)
588 return aerr;
589 return APIError::OK;
590}
591
593#ifdef ESPHOME_DEBUG_API
594 assert(state_ == State::HANDSHAKE);
595#endif
596
597 int action = noise_handshakestate_get_action(handshake_);
598 if (action == NOISE_ACTION_READ_MESSAGE || action == NOISE_ACTION_WRITE_MESSAGE)
599 return APIError::OK;
600 if (action != NOISE_ACTION_SPLIT) {
602 HELPER_LOG("Bad action for handshake: %d", action);
604 }
605 int err = noise_handshakestate_split(handshake_, &send_cipher_, &recv_cipher_);
606 APIError aerr =
607 handle_noise_error_(err, LOG_STR("noise_handshakestate_split"), APIError::HANDSHAKESTATE_SPLIT_FAILED);
608 if (aerr != APIError::OK)
609 return aerr;
610
611 frame_footer_size_ = noise_cipherstate_get_mac_length(send_cipher_);
612
613 HELPER_LOG("Handshake complete!");
614 noise_handshakestate_free(handshake_);
615 handshake_ = nullptr;
617 return APIError::OK;
618}
619
621 if (handshake_ != nullptr) {
622 noise_handshakestate_free(handshake_);
623 handshake_ = nullptr;
624 }
625 if (send_cipher_ != nullptr) {
626 noise_cipherstate_free(send_cipher_);
627 send_cipher_ = nullptr;
628 }
629 if (recv_cipher_ != nullptr) {
630 noise_cipherstate_free(recv_cipher_);
631 recv_cipher_ = nullptr;
632 }
633}
634
635extern "C" {
636// declare how noise generates random bytes (here with a good HWRNG based on the RF system)
637void noise_rand_bytes(void *output, size_t len) {
638 if (!esphome::random_bytes(reinterpret_cast<uint8_t *>(output), len)) {
639 ESP_LOGE(TAG, "Acquiring random bytes failed; rebooting");
640 arch_restart();
641 }
642}
643}
644
645} // namespace esphome::api
646#endif // USE_API_NOISE
647#endif // USE_API
const std::string & get_name() const
Get the name of this Application set by pre_setup().
Minimal static vector - saves memory by avoiding std::vector overhead.
Definition helpers.h:209
size_t size() const
Definition helpers.h:269
void push_back(const T &value)
Definition helpers.h:242
APIError handle_socket_read_result_(ssize_t received)
std::vector< uint8_t > rx_buf_
std::unique_ptr< socket::Socket > socket_
APIError write_raw_(const struct iovec *iov, int iovcnt, uint16_t total_write_len)
const psk_t & get_psk() const
APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) override
APIError read_packet(ReadPacketBuffer *buffer) override
APIError handle_noise_error_(int err, const LogString *func_name, APIError api_err)
APIError write_protobuf_messages(ProtoWriteBuffer buffer, std::span< const MessageInfo > messages) override
APIError state_action_()
To be called from read/write methods.
APIError try_read_frame_()
Read a packet into the rx_buf_.
APIError loop() override
Run through handshake messages (if in that phase)
APIError handle_handshake_frame_error_(APIError aerr)
void send_explicit_handshake_reject_(const LogString *reason)
APIError write_frame_(const uint8_t *data, uint16_t len)
APIError init() override
Initialize the frame helper, returns OK if successful.
APIError init_handshake_()
Initiate the data structures for the handshake.
std::vector< uint8_t > * get_buffer() const
Definition proto.h:368
uint16_t type
__int64 ssize_t
Definition httplib.h:178
void noise_rand_bytes(void *output, size_t len)
const LogString * noise_err_to_logstr(int err)
Convert a noise error code to a readable error.
bool random_bytes(uint8_t *data, size_t len)
Generate len number of random bytes.
Definition helpers.cpp:18
std::string size_t len
Definition helpers.h:817
size_t size
Definition helpers.h:854
void get_mac_address_into_buffer(std::span< char, MAC_ADDRESS_BUFFER_SIZE > buf)
Get the device MAC address into the given buffer, in lowercase hex notation.
Definition helpers.cpp:811
void arch_restart()
Definition core.cpp:30
Application App
Global storage of Application pointer - only one Application can exist.
void * iov_base
Definition headers.h:101
size_t iov_len
Definition headers.h:102