ESPHome 2026.4.0-dev
Loading...
Searching...
No Matches
hmac_sha256.cpp
Go to the documentation of this file.
1#include <cstring>
2#include "hmac_sha256.h"
3#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_HOST)
5
7
8constexpr size_t SHA256_DIGEST_SIZE = 32;
9
10#if defined(USE_HMAC_SHA256_PSA)
11
12// ESP-IDF 6.0 ships mbedtls 4.0 which removed the legacy mbedtls_md HMAC API.
13// Use the PSA Crypto MAC API instead.
14
16 psa_mac_abort(&this->op_);
17 psa_destroy_key(this->key_id_);
18}
19
20void HmacSHA256::init(const uint8_t *key, size_t len) {
21 psa_mac_abort(&this->op_);
22 psa_destroy_key(this->key_id_);
23
24 psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
25 psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC);
26 psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
27 psa_set_key_algorithm(&attributes, PSA_ALG_HMAC(PSA_ALG_SHA_256));
28 psa_import_key(&attributes, key, len, &this->key_id_);
29
30 this->op_ = PSA_MAC_OPERATION_INIT;
31 psa_mac_sign_setup(&this->op_, this->key_id_, PSA_ALG_HMAC(PSA_ALG_SHA_256));
32}
33
34void HmacSHA256::add(const uint8_t *data, size_t len) { psa_mac_update(&this->op_, data, len); }
35
37 size_t mac_length;
38 psa_mac_sign_finish(&this->op_, this->digest_, sizeof(this->digest_), &mac_length);
39}
40
41void HmacSHA256::get_bytes(uint8_t *output) { memcpy(output, this->digest_, SHA256_DIGEST_SIZE); }
42
43void HmacSHA256::get_hex(char *output) {
44 format_hex_to(output, SHA256_DIGEST_SIZE * 2 + 1, this->digest_, SHA256_DIGEST_SIZE);
45}
46
47bool HmacSHA256::equals_bytes(const uint8_t *expected) {
48 return memcmp(this->digest_, expected, SHA256_DIGEST_SIZE) == 0;
49}
50
51bool HmacSHA256::equals_hex(const char *expected) {
52 char hex_output[SHA256_DIGEST_SIZE * 2 + 1];
53 this->get_hex(hex_output);
54 hex_output[SHA256_DIGEST_SIZE * 2] = '\0';
55 return strncmp(hex_output, expected, SHA256_DIGEST_SIZE * 2) == 0;
56}
57
58#elif defined(USE_HMAC_SHA256_MBEDTLS)
59
60HmacSHA256::~HmacSHA256() { mbedtls_md_free(&this->ctx_); }
61
62void HmacSHA256::init(const uint8_t *key, size_t len) {
63 mbedtls_md_init(&this->ctx_);
64 const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
65 mbedtls_md_setup(&this->ctx_, md_info, 1); // 1 = HMAC mode
66 mbedtls_md_hmac_starts(&this->ctx_, key, len);
67}
68
69void HmacSHA256::add(const uint8_t *data, size_t len) { mbedtls_md_hmac_update(&this->ctx_, data, len); }
70
71void HmacSHA256::calculate() { mbedtls_md_hmac_finish(&this->ctx_, this->digest_); }
72
73void HmacSHA256::get_bytes(uint8_t *output) { memcpy(output, this->digest_, SHA256_DIGEST_SIZE); }
74
75void HmacSHA256::get_hex(char *output) {
76 format_hex_to(output, SHA256_DIGEST_SIZE * 2 + 1, this->digest_, SHA256_DIGEST_SIZE);
77}
78
79bool HmacSHA256::equals_bytes(const uint8_t *expected) {
80 return memcmp(this->digest_, expected, SHA256_DIGEST_SIZE) == 0;
81}
82
83bool HmacSHA256::equals_hex(const char *expected) {
84 char hex_output[SHA256_DIGEST_SIZE * 2 + 1];
85 this->get_hex(hex_output);
86 hex_output[SHA256_DIGEST_SIZE * 2] = '\0';
87 return strncmp(hex_output, expected, SHA256_DIGEST_SIZE * 2) == 0;
88}
89
90#else
91
92HmacSHA256::~HmacSHA256() = default;
93
94// HMAC block size for SHA256 (RFC 2104)
95constexpr size_t HMAC_BLOCK_SIZE = 64;
96
97void HmacSHA256::init(const uint8_t *key, size_t len) {
98 uint8_t ipad[HMAC_BLOCK_SIZE], opad[HMAC_BLOCK_SIZE];
99
100 memset(ipad, 0, sizeof(ipad));
101 if (len > HMAC_BLOCK_SIZE) {
102 sha256::SHA256 keysha256;
103 keysha256.init();
104 keysha256.add(key, len);
105 keysha256.calculate();
106 keysha256.get_bytes(ipad);
107 } else {
108 memcpy(ipad, key, len);
109 }
110 memcpy(opad, ipad, sizeof(opad));
111
112 for (size_t i = 0; i < HMAC_BLOCK_SIZE; i++) {
113 ipad[i] ^= 0x36;
114 opad[i] ^= 0x5c;
115 }
116
117 this->ihash_.init();
118 this->ihash_.add(ipad, sizeof(ipad));
119
120 this->ohash_.init();
121 this->ohash_.add(opad, sizeof(opad));
122}
123
124void HmacSHA256::add(const uint8_t *data, size_t len) { this->ihash_.add(data, len); }
125
127 uint8_t ibytes[32];
128
129 this->ihash_.calculate();
130 this->ihash_.get_bytes(ibytes);
131
132 this->ohash_.add(ibytes, sizeof(ibytes));
133 this->ohash_.calculate();
134}
135
136void HmacSHA256::get_bytes(uint8_t *output) { this->ohash_.get_bytes(output); }
137
138void HmacSHA256::get_hex(char *output) { this->ohash_.get_hex(output); }
139
140bool HmacSHA256::equals_bytes(const uint8_t *expected) { return this->ohash_.equals_bytes(expected); }
141
142bool HmacSHA256::equals_hex(const char *expected) { return this->ohash_.equals_hex(expected); }
143
144#endif // USE_HMAC_SHA256_PSA / USE_HMAC_SHA256_MBEDTLS
145
146} // namespace esphome::hmac_sha256
147#endif
void get_hex(char *output)
Retrieve the hash as hex characters. Output buffer must hold get_size() * 2 + 1 bytes.
Definition hash_base.h:29
bool equals_hex(const char *expected)
Compare the hash against a provided hex-encoded hash.
Definition hash_base.h:35
bool equals_bytes(const uint8_t *expected)
Compare the hash against a provided byte-encoded hash.
Definition hash_base.h:32
void get_bytes(uint8_t *output)
Retrieve the hash as bytes.
Definition hash_base.h:26
bool equals_bytes(const uint8_t *expected)
Compare the digest against a provided byte-encoded digest (32 bytes).
mbedtls_md_context_t ctx_
Definition hmac_sha256.h:67
mbedtls_svc_key_id_t key_id_
Definition hmac_sha256.h:63
bool equals_hex(const char *expected)
Compare the digest against a provided hex-encoded digest (64 bytes).
void add(const uint8_t *data, size_t len)
Add bytes of data for the digest.
void get_hex(char *output)
Retrieve the HMAC-SHA256 digest as hex characters.
void get_bytes(uint8_t *output)
Retrieve the HMAC-SHA256 digest as bytes.
static constexpr size_t SHA256_DIGEST_SIZE
Definition hmac_sha256.h:61
uint8_t digest_[SHA256_DIGEST_SIZE]
Definition hmac_sha256.h:64
void calculate()
Compute the digest, based on the provided data.
void init(const uint8_t *key, size_t len)
Initialize a new HMAC-SHA256 digest computation.
SHA256 hash implementation.
Definition sha256.h:51
void calculate() override
Definition sha256.cpp:27
void add(const uint8_t *data, size_t len) override
Definition sha256.cpp:25
void init() override
Definition sha256.cpp:19
constexpr size_t SHA256_DIGEST_SIZE
constexpr size_t HMAC_BLOCK_SIZE
std::string size_t len
Definition helpers.h:1045
char * format_hex_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length)
Format byte array as lowercase hex to buffer (base implementation).
Definition helpers.cpp:367