2#ifdef USE_PACKET_INTERFACE_XXTEA
15static constexpr uint8_t CHECK_BYTES[3] = {0x58, 0x54, 0x45};
16static constexpr uint8_t ROLLING_CHECK_BYTES[3] = {0x58, 0x54, 0x52};
17static constexpr size_t CHECK_SIZE = 4;
19static constexpr size_t ROLLING_SIZE = 12;
21static constexpr size_t MIN_LENGTH = 8;
22static constexpr size_t MAX_PADDING = 4;
24static void put_uint32(uint8_t *buf,
uint32_t value) {
31static uint32_t get_uint32(
const uint8_t *buf) {
return encode_uint32(buf[3], buf[2], buf[1], buf[0]); }
33static constexpr size_t trailer_size(
bool rolling_code) {
34 return rolling_code ? ROLLING_SIZE + CHECK_SIZE : CHECK_SIZE;
41 trailer_size_(trailer_size(rolling_code)),
42 rolling_code_(rolling_code) {
47 std::copy_n(
key.begin(), std::min(
key.size(), this->key_.size()), this->key_.begin());
52 this->
mark_failed(LOG_STR(
"max_packet_size too small for the configured layers"));
59 this->
mark_failed(LOG_STR(
"Not enough memory for the packet buffers"));
74 "XXTEA Encryption on '%s':\n"
75 " Max Packet Size: %zu\n"
79 ESP_LOGCONFIG(TAG,
" Boot Number: %" PRIu32, this->
boot_);
88 ESP_LOGW(TAG,
"%s: Could not save the boot number, so a restart could reuse it", this->
name_);
97 ESP_LOGW(TAG,
"%s: Packet of %zu bytes is larger than %zu", this->
name_, size, this->
max_packet_size_);
104 auto *buf =
reinterpret_cast<uint8_t *
>(this->
tx_buffer_);
106 memset(buf +
size, 0, padding);
107 uint8_t *check = buf +
length - CHECK_SIZE;
109 put_uint32(check - ROLLING_SIZE, this->
boot_);
110 put_uint32(check - ROLLING_SIZE + 4, this->
counter_);
111 put_uint32(check - ROLLING_SIZE + 8, this->
echo_boot_);
112 memcpy(check, ROLLING_CHECK_BYTES,
sizeof(ROLLING_CHECK_BYTES));
116 memcpy(check, CHECK_BYTES,
sizeof(CHECK_BYTES));
118 check[CHECK_SIZE - 1] = padding;
128 this->peer_counter_ = counter;
133 size_t length = data.size();
136 ESP_LOGV(TAG,
"%s: Packet of %zu bytes dropped", this->
name_, length);
140 auto *buf =
reinterpret_cast<uint8_t *
>(this->
rx_buffer_);
143 const uint8_t *check = buf +
length - CHECK_SIZE;
144 const uint8_t *expected = this->
rolling_code_ ? ROLLING_CHECK_BYTES : CHECK_BYTES;
145 size_t padding = check[CHECK_SIZE - 1];
146 if (memcmp(check, expected,
sizeof(CHECK_BYTES)) != 0 || padding > MAX_PADDING ||
148 ESP_LOGV(TAG,
"%s: Packet failed authentication", this->
name_);
154 uint32_t boot = get_uint32(check - ROLLING_SIZE);
155 uint32_t counter = get_uint32(check - ROLLING_SIZE + 4);
156 uint32_t echo = get_uint32(check - ROLLING_SIZE + 8);
161 if (echo != this->
boot_) {
162 ESP_LOGV(TAG,
"%s: Packet for boot %" PRIu32
" dropped", this->
name_, echo);
170 "%s: Packets from an older boot %" PRIu32
" of the peer are dropped; if its flash was erased, "
171 "restart this device",
174 ESP_LOGV(TAG,
"%s: Old packet %" PRIu32
":%" PRIu32
" dropped", this->
name_, boot, counter);
void mark_failed()
Mark this component as failed.
An STL allocator that uses SPI or internal RAM.
A buffer class that efficiently represents a composite buffer with three sections:
size_t copy_to(uint8_t *dest, size_t count, size_t offset=0) const
Copy data from the buffer to a destination pointer.
size_t size() const
Get the total size of the buffer.
A class that will transport data to and from an abstract channel.
size_t get_max_packet_size() const
The largest packet this layer accepts; fixed when the layer is constructed.
void note_received_(bool understood)
Called by a layer for each received packet it understood, or could not make sense of.
void stack_on_(PacketInterface *lower, Capability capability)
Called by a layer's constructor to record itself as the layer above lower, adding its own capability.
virtual bool send_to_interface(const PacketBuffer &data, const PacketMetaData &meta_data)=0
Method to be implemented by child classes to send data to the interface.
void add_packet_interface_listener(F &&callback)
Add a listener that will be called when data is received.
const size_t max_packet_size_
void on_receive_from_interface_(const PacketBuffer &data, const PacketMetaData &meta_data)
This function should be called by implementing classes with received data to be passed to any listene...
const size_t trailer_size_
void dump_config() override
ESPPreferenceObject pref_
std::array< uint32_t, 8 > key_
XxteaEncryption(PacketInterface *lower, bool rolling_code)
bool accept_counter_(uint32_t boot, uint32_t counter)
bool send_to_interface(const PacketBuffer &data, const PacketMetaData &meta_data) override
void receive_(const PacketBuffer &data, const PacketMetaData &meta_data)
void set_key(std::initializer_list< uint32_t > key)
constexpr size_t remaining_packet_size(size_t size, size_t used)
The room left for a packet of size bytes after used bytes, or 0 if it is too small.
ESPHOME_LOG_TAG(TAG, "packet_interface.session")
void encrypt(uint32_t *v, size_t n, const uint32_t *k)
Encrypt a block of data in-place using XXTEA algorithm with 256-bit key.
void decrypt(uint32_t *v, size_t n, const uint32_t *k)
Decrypt a block of data in-place using XXTEA algorithm with 256-bit key.
constexpr uint32_t fnv1a_hash_extend(uint32_t hash, const char *str)
Extend a FNV-1a hash with additional string data.
ESPPreferences * global_preferences
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
constexpr uint32_t fnv1a_hash(const char *str)
Calculate a FNV-1a hash of str.
ESPPreferenceObject make_preference(size_t, uint32_t, bool)
bool sync()
Commit pending writes to flash.