ESPHome 2026.1.3
Loading...
Searching...
No Matches
sha256.cpp
Go to the documentation of this file.
1#include "sha256.h"
2
3// Only compile SHA256 implementation on platforms that support it
4#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_HOST)
5
7#include <cstring>
8
9namespace esphome::sha256 {
10
11#if defined(USE_ESP32) || defined(USE_LIBRETINY)
12
13// CRITICAL ESP32 HARDWARE SHA ACCELERATION REQUIREMENTS (IDF 5.5.x):
14//
15// ESP32 variants (except original ESP32) use DMA-based hardware SHA acceleration that requires
16// 32-byte aligned digest buffers. This is handled automatically via HashBase::digest_ which has
17// alignas(32) on these platforms. Two additional constraints apply:
18//
19// 1. NO VARIABLE LENGTH ARRAYS (VLAs): VLAs corrupt the stack layout, causing the DMA engine to
20// write to incorrect memory locations. This results in null pointer dereferences and crashes.
21// ALWAYS use fixed-size arrays (e.g., char buf[65], not char buf[size+1]).
22//
23// 2. SAME STACK FRAME ONLY: The SHA256 object must be created and used entirely within the same
24// function. NEVER pass the SHA256 object or HashBase pointer to another function. When the stack
25// frame changes (function call/return), the DMA references become invalid and will produce
26// truncated hash output (20 bytes instead of 32) or corrupt memory.
27//
28// CORRECT USAGE:
29// void my_function() {
30// sha256::SHA256 hasher;
31// hasher.init();
32// hasher.add(data, len); // Any size, no chunking needed
33// hasher.calculate();
34// bool ok = hasher.equals_hex(expected);
35// // hasher destroyed when function returns
36// }
37//
38// INCORRECT USAGE (WILL FAIL):
39// void my_function() {
40// sha256::SHA256 hasher;
41// helper(&hasher); // WRONG: Passed to different stack frame
42// }
43// void helper(HashBase *h) {
44// h->init(); // WRONG: Will produce truncated/corrupted output
45// }
46
47SHA256::~SHA256() { mbedtls_sha256_free(&this->ctx_); }
48
50 mbedtls_sha256_init(&this->ctx_);
51 mbedtls_sha256_starts(&this->ctx_, 0); // 0 = SHA256, not SHA224
52}
53
54void SHA256::add(const uint8_t *data, size_t len) { mbedtls_sha256_update(&this->ctx_, data, len); }
55
56void SHA256::calculate() { mbedtls_sha256_finish(&this->ctx_, this->digest_); }
57
58#elif defined(USE_ESP8266) || defined(USE_RP2040)
59
60SHA256::~SHA256() = default;
61
62void SHA256::init() {
63 br_sha256_init(&this->ctx_);
64 this->calculated_ = false;
65}
66
67void SHA256::add(const uint8_t *data, size_t len) { br_sha256_update(&this->ctx_, data, len); }
68
69void SHA256::calculate() {
70 if (!this->calculated_) {
71 br_sha256_out(&this->ctx_, this->digest_);
72 this->calculated_ = true;
73 }
74}
75
76#elif defined(USE_HOST)
77
79 if (this->ctx_) {
80 EVP_MD_CTX_free(this->ctx_);
81 }
82}
83
84void SHA256::init() {
85 if (this->ctx_) {
86 EVP_MD_CTX_free(this->ctx_);
87 }
88 this->ctx_ = EVP_MD_CTX_new();
89 EVP_DigestInit_ex(this->ctx_, EVP_sha256(), nullptr);
90 this->calculated_ = false;
91}
92
93void SHA256::add(const uint8_t *data, size_t len) {
94 if (!this->ctx_) {
95 this->init();
96 }
97 EVP_DigestUpdate(this->ctx_, data, len);
98}
99
100void SHA256::calculate() {
101 if (!this->ctx_) {
102 this->init();
103 }
104 if (!this->calculated_) {
105 unsigned int len = 32;
106 EVP_DigestFinal_ex(this->ctx_, this->digest_, &len);
107 this->calculated_ = true;
108 }
109}
110
111#else
112#error "SHA256 not supported on this platform"
113#endif
114
115} // namespace esphome::sha256
116
117#endif // Platform check
uint8_t digest_[32]
Definition hash_base.h:52
void calculate() override
Definition sha256.cpp:56
void add(const uint8_t *data, size_t len) override
Definition sha256.cpp:54
mbedtls_sha256_context ctx_
Definition sha256.h:57
void init() override
Definition sha256.cpp:49
std::string size_t len
Definition helpers.h:595