ESPHome 2026.5.0-dev
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_SHA256_PSA)
12
13// ESP-IDF 6.0 ships mbedtls 4.0 which removed the legacy mbedtls_sha256_* API.
14// Use the PSA Crypto API instead. PSA crypto is auto-initialized by ESP-IDF
15// at startup, so no psa_crypto_init() call is needed.
16
17SHA256::~SHA256() { psa_hash_abort(&this->op_); }
18
20 psa_hash_abort(&this->op_);
21 this->op_ = PSA_HASH_OPERATION_INIT;
22 psa_hash_setup(&this->op_, PSA_ALG_SHA_256);
23}
24
25void SHA256::add(const uint8_t *data, size_t len) { psa_hash_update(&this->op_, data, len); }
26
28 size_t hash_length;
29 psa_hash_finish(&this->op_, this->digest_, sizeof(this->digest_), &hash_length);
30}
31
32#elif defined(USE_SHA256_MBEDTLS)
33
34// CRITICAL ESP32 HARDWARE SHA ACCELERATION REQUIREMENTS (IDF 5.5.x):
35//
36// ESP32 variants (except original ESP32) use DMA-based hardware SHA acceleration that requires
37// 32-byte aligned digest buffers. This is handled automatically via HashBase::digest_ which has
38// alignas(32) on these platforms. Two additional constraints apply:
39//
40// 1. NO VARIABLE LENGTH ARRAYS (VLAs): VLAs corrupt the stack layout, causing the DMA engine to
41// write to incorrect memory locations. This results in null pointer dereferences and crashes.
42// ALWAYS use fixed-size arrays (e.g., char buf[65], not char buf[size+1]).
43//
44// 2. SAME STACK FRAME ONLY: The SHA256 object must be created and used entirely within the same
45// function. NEVER pass the SHA256 object or HashBase pointer to another function. When the stack
46// frame changes (function call/return), the DMA references become invalid and will produce
47// truncated hash output (20 bytes instead of 32) or corrupt memory.
48//
49// CORRECT USAGE:
50// void my_function() {
51// sha256::SHA256 hasher;
52// hasher.init();
53// hasher.add(data, len); // Any size, no chunking needed
54// hasher.calculate();
55// bool ok = hasher.equals_hex(expected);
56// // hasher destroyed when function returns
57// }
58//
59// INCORRECT USAGE (WILL FAIL):
60// void my_function() {
61// sha256::SHA256 hasher;
62// helper(&hasher); // WRONG: Passed to different stack frame
63// }
64// void helper(HashBase *h) {
65// h->init(); // WRONG: Will produce truncated/corrupted output
66// }
67
68SHA256::~SHA256() { mbedtls_sha256_free(&this->ctx_); }
69
70void SHA256::init() {
71 mbedtls_sha256_init(&this->ctx_);
72 mbedtls_sha256_starts(&this->ctx_, 0); // 0 = SHA256, not SHA224
73}
74
75void SHA256::add(const uint8_t *data, size_t len) { mbedtls_sha256_update(&this->ctx_, data, len); }
76
77void SHA256::calculate() { mbedtls_sha256_finish(&this->ctx_, this->digest_); }
78
79#elif defined(USE_ESP8266) || defined(USE_RP2040)
80
81SHA256::~SHA256() = default;
82
83void SHA256::init() {
84 br_sha256_init(&this->ctx_);
85 this->calculated_ = false;
86}
87
88void SHA256::add(const uint8_t *data, size_t len) { br_sha256_update(&this->ctx_, data, len); }
89
90void SHA256::calculate() {
91 if (!this->calculated_) {
92 br_sha256_out(&this->ctx_, this->digest_);
93 this->calculated_ = true;
94 }
95}
96
97#elif defined(USE_HOST)
98
100 if (this->ctx_) {
101 EVP_MD_CTX_free(this->ctx_);
102 }
103}
104
105void SHA256::init() {
106 if (this->ctx_) {
107 EVP_MD_CTX_free(this->ctx_);
108 }
109 this->ctx_ = EVP_MD_CTX_new();
110 EVP_DigestInit_ex(this->ctx_, EVP_sha256(), nullptr);
111 this->calculated_ = false;
112}
113
114void SHA256::add(const uint8_t *data, size_t len) {
115 if (!this->ctx_) {
116 this->init();
117 }
118 EVP_DigestUpdate(this->ctx_, data, len);
119}
120
121void SHA256::calculate() {
122 if (!this->ctx_) {
123 this->init();
124 }
125 if (!this->calculated_) {
126 unsigned int len = 32;
127 EVP_DigestFinal_ex(this->ctx_, this->digest_, &len);
128 this->calculated_ = true;
129 }
130}
131
132#else
133#error "SHA256 not supported on this platform"
134#endif
135
136} // namespace esphome::sha256
137
138#endif // Platform check
uint8_t digest_[32]
Definition hash_base.h:52
void calculate() override
Definition sha256.cpp:27
void add(const uint8_t *data, size_t len) override
Definition sha256.cpp:25
psa_hash_operation_t op_
Definition sha256.h:68
mbedtls_sha256_context ctx_
Definition sha256.h:72
void init() override
Definition sha256.cpp:19
std::string size_t len
Definition helpers.h:1045