Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 259c2ff

Browse files
Merge pull request #11676 from lucasssvaz/feat/hashing
feat(hash): Add hashing library and new algorithms
2 parents f9bc177 + 15440b2 commit 259c2ff

24 files changed

+1921
-73
lines changed

‎CMakeLists.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ set(CORE_SRCS
5454
cores/esp32/freertos_stats.cpp
5555
cores/esp32/FunctionalInterrupt.cpp
5656
cores/esp32/HardwareSerial.cpp
57+
cores/esp32/HashBuilder.cpp
5758
cores/esp32/HEXBuilder.cpp
5859
cores/esp32/IPAddress.cpp
5960
cores/esp32/libb64/cdecode.c
@@ -62,7 +63,6 @@ set(CORE_SRCS
6263
cores/esp32/main.cpp
6364
cores/esp32/MD5Builder.cpp
6465
cores/esp32/Print.cpp
65-
cores/esp32/SHA1Builder.cpp
6666
cores/esp32/stdlib_noniso.c
6767
cores/esp32/Stream.cpp
6868
cores/esp32/StreamString.cpp
@@ -93,6 +93,7 @@ set(ARDUINO_ALL_LIBRARIES
9393
Ethernet
9494
FFat
9595
FS
96+
Hash
9697
HTTPClient
9798
HTTPUpdate
9899
Insights
@@ -154,6 +155,13 @@ set(ARDUINO_LIBRARY_FS_SRCS
154155
libraries/FS/src/FS.cpp
155156
libraries/FS/src/vfs_api.cpp)
156157

158+
set(ARDUINO_LIBRARY_Hash_SRCS
159+
libraries/Hash/src/SHA1Builder.cpp
160+
libraries/Hash/src/SHA2Builder.cpp
161+
libraries/Hash/src/SHA3Builder.cpp
162+
libraries/Hash/src/PBKDF2_HMACBuilder.cpp
163+
)
164+
157165
set(ARDUINO_LIBRARY_HTTPClient_SRCS libraries/HTTPClient/src/HTTPClient.cpp)
158166

159167
set(ARDUINO_LIBRARY_HTTPUpdate_SRCS libraries/HTTPUpdate/src/HTTPUpdate.cpp)

‎cores/esp32/HEXBuilder.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1818
*/
1919

20-
#include <Arduino.h>
21-
#include <HEXBuilder.h>
20+
#include "HEXBuilder.h"
2221

2322
static uint8_t hex_char_to_byte(uint8_t c) {
2423
return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa))

‎cores/esp32/HEXBuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <WString.h>
2424
#include <Stream.h>
2525

26+
// Basic hex/byte conversion class to be used by hash builders
27+
2628
class HEXBuilder {
2729
public:
2830
static size_t hex2bytes(unsigned char *out, size_t maxlen, String &in);

‎cores/esp32/HashBuilder.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2025 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "HashBuilder.h"
16+
17+
void HashBuilder::add(const char *data) {
18+
add((const uint8_t *)data, strlen(data));
19+
}
20+
21+
void HashBuilder::add(String data) {
22+
add(data.c_str());
23+
}
24+
25+
void HashBuilder::addHexString(const char *data) {
26+
size_t len = strlen(data);
27+
uint8_t *tmp = (uint8_t *)malloc(len / 2);
28+
if (tmp == NULL) {
29+
return;
30+
}
31+
hex2bytes(tmp, len / 2, data);
32+
add(tmp, len / 2);
33+
free(tmp);
34+
}
35+
36+
void HashBuilder::addHexString(String data) {
37+
addHexString(data.c_str());
38+
}

‎cores/esp32/HashBuilder.h

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,44 @@
2020

2121
#include "HEXBuilder.h"
2222

23+
/* Try to prevent most compilers from optimizing out clearing of memory that
24+
* becomes unaccessible after this function is called. This is mostly the case
25+
* for clearing local stack variables at the end of a function. This is not
26+
* exactly perfect, i.e., someone could come up with a compiler that figures out
27+
* the pointer is pointing to memset and then end up optimizing the call out, so
28+
* try go a bit further by storing the first octet (now zero) to make this even
29+
* a bit more difficult to optimize out. Once memset_s() is available, that
30+
* could be used here instead. */
31+
static void *(*const volatile memset_func)(void *, int, size_t) = memset;
32+
static uint8_t forced_memzero_val;
33+
34+
static inline void forced_memzero(void *ptr, size_t len) {
35+
memset_func(ptr, 0, len);
36+
if (len) {
37+
forced_memzero_val = ((uint8_t *)ptr)[0];
38+
}
39+
}
40+
41+
// Base class for hash builders
42+
2343
class HashBuilder : public HEXBuilder {
2444
public:
2545
virtual ~HashBuilder() {}
2646
virtual void begin() = 0;
2747

2848
virtual void add(const uint8_t *data, size_t len) = 0;
29-
virtual void add(const char *data) {
30-
add((const uint8_t *)data, strlen(data));
31-
}
32-
virtual void add(String data) {
33-
add(data.c_str());
34-
}
49+
void add(const char *data);
50+
void add(String data);
3551

36-
virtual void addHexString(const char *data) = 0;
37-
virtual void addHexString(String data) {
38-
addHexString(data.c_str());
39-
}
52+
void addHexString(const char *data);
53+
void addHexString(String data);
4054

4155
virtual bool addStream(Stream &stream, const size_t maxLen) = 0;
4256
virtual void calculate() = 0;
4357
virtual void getBytes(uint8_t *output) = 0;
4458
virtual void getChars(char *output) = 0;
4559
virtual String toString() = 0;
60+
virtual size_t getHashSize() const = 0;
4661
};
4762

4863
#endif

‎cores/esp32/MD5Builder.cpp

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1818
*/
1919

20-
#include <Arduino.h>
21-
#include <HEXBuilder.h>
22-
#include <MD5Builder.h>
20+
#include "HEXBuilder.h"
21+
#include "MD5Builder.h"
2322

2423
void MD5Builder::begin(void) {
2524
memset(_buf, 0x00, ESP_ROM_MD5_DIGEST_LEN);
@@ -30,17 +29,6 @@ void MD5Builder::add(const uint8_t *data, size_t len) {
3029
esp_rom_md5_update(&_ctx, data, len);
3130
}
3231

33-
void MD5Builder::addHexString(const char *data) {
34-
size_t len = strlen(data);
35-
uint8_t *tmp = (uint8_t *)malloc(len / 2);
36-
if (tmp == NULL) {
37-
return;
38-
}
39-
hex2bytes(tmp, len / 2, data);
40-
add(tmp, len / 2);
41-
free(tmp);
42-
}
43-
4432
bool MD5Builder::addStream(Stream &stream, const size_t maxLen) {
4533
const int buf_size = 512;
4634
int maxLengthLeft = maxLen;

‎cores/esp32/MD5Builder.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,18 @@ class MD5Builder : public HashBuilder {
3535
uint8_t _buf[ESP_ROM_MD5_DIGEST_LEN];
3636

3737
public:
38-
void begin(void) override;
39-
4038
using HashBuilder::add;
41-
void add(const uint8_t *data, size_t len) override;
42-
43-
using HashBuilder::addHexString;
44-
void addHexString(const char *data) override;
4539

40+
void begin(void) override;
41+
void add(const uint8_t *data, size_t len) override;
4642
bool addStream(Stream &stream, const size_t maxLen) override;
4743
void calculate(void) override;
4844
void getBytes(uint8_t *output) override;
4945
void getChars(char *output) override;
5046
String toString(void) override;
47+
size_t getHashSize() const override {
48+
return ESP_ROM_MD5_DIGEST_LEN;
49+
}
5150
};
5251

5352
#endif

‎libraries/ESP32/examples/Utilities/HEXBuilder/HEXBuilder.ino renamed to ‎libraries/Hash/examples/HEX/HEX.ino

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/*
2+
Usage example for the HEXBuilder class.
3+
4+
This example shows how to convert a HEX string to a binary buffer and vice versa.
5+
*/
6+
17
#include <HEXBuilder.h>
28

39
void setup() {
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
Usage example for the PBKDF2_HMACBuilder class.
3+
4+
This example shows how to use the Hash library to hash data using the PBKDF2_HMACBuilder class.
5+
PBKDF2_HMAC (Password-Based Key Derivation Function 2) is a key derivation function that uses a password and a salt to derive a key.
6+
7+
The PBKDF2_HMACBuilder class takes for arguments:
8+
- A HashBuilder object to use for the HMAC (SHA1Builder, SHA2Builder, SHA3Builder, etc.)
9+
- A password string (default: empty)
10+
- A salt string (default: empty)
11+
- The number of iterations (default: 1000)
12+
*/
13+
14+
#include <SHA1Builder.h>
15+
#include <SHA2Builder.h>
16+
#include <PBKDF2_HMACBuilder.h>
17+
18+
void setup() {
19+
Serial.begin(115200);
20+
Serial.println("\n\nPBKDF2-HMAC Example");
21+
Serial.println("===================");
22+
23+
// Test 1: Basic PBKDF2-HMAC-SHA1
24+
Serial.println("\n1. PBKDF2-HMAC-SHA1 Test (1 iteration)");
25+
{
26+
SHA1Builder sha1;
27+
PBKDF2_HMACBuilder pbkdf2(&sha1, "password", "salt", 1);
28+
29+
pbkdf2.begin();
30+
pbkdf2.calculate();
31+
32+
Serial.print("Password: ");
33+
Serial.println("password");
34+
Serial.print("Salt: ");
35+
Serial.println("salt");
36+
Serial.print("Iterations: ");
37+
Serial.println(1);
38+
Serial.print("Output (hex): ");
39+
Serial.println(pbkdf2.toString());
40+
41+
// Expected: 0c60c80f961f0e71f3a9b524af6012062fe037a6
42+
String expected = "0c60c80f961f0e71f3a9b524af6012062fe037a6";
43+
String result = pbkdf2.toString();
44+
45+
if (result.equalsIgnoreCase(expected)) {
46+
Serial.println("✓ PASS: Output matches expected value");
47+
} else {
48+
Serial.println("✗ FAIL: Output does not match expected value");
49+
Serial.print("Expected: ");
50+
Serial.println(expected);
51+
Serial.print("Got: ");
52+
Serial.println(result);
53+
}
54+
}
55+
56+
// Test 2: PBKDF2-HMAC-SHA1 with more iterations
57+
Serial.println("\n2. PBKDF2-HMAC-SHA1 Test (1000 iterations)");
58+
{
59+
SHA1Builder sha1;
60+
PBKDF2_HMACBuilder pbkdf2(&sha1);
61+
62+
const char *password = "password";
63+
const char *salt = "salt";
64+
65+
pbkdf2.begin();
66+
pbkdf2.setPassword(password);
67+
pbkdf2.setSalt(salt);
68+
pbkdf2.setIterations(1000);
69+
pbkdf2.calculate();
70+
71+
Serial.print("Password: ");
72+
Serial.println(password);
73+
Serial.print("Salt: ");
74+
Serial.println(salt);
75+
Serial.print("Iterations: ");
76+
Serial.println(1000);
77+
Serial.print("Output (hex): ");
78+
Serial.println(pbkdf2.toString());
79+
80+
// Expected: 6e88be8bad7eae9d9e10aa061224034fed48d03f
81+
String expected = "6e88be8bad7eae9d9e10aa061224034fed48d03f";
82+
String result = pbkdf2.toString();
83+
84+
if (result.equalsIgnoreCase(expected)) {
85+
Serial.println("✓ PASS: Output matches expected value");
86+
} else {
87+
Serial.println("✗ FAIL: Output does not match expected value");
88+
Serial.print("Expected: ");
89+
Serial.println(expected);
90+
Serial.print("Got: ");
91+
Serial.println(result);
92+
}
93+
}
94+
95+
// Test 3: PBKDF2-HMAC-SHA256 with different password and salt
96+
Serial.println("\n3. PBKDF2-HMAC-SHA256 Test");
97+
{
98+
SHA256Builder sha256;
99+
PBKDF2_HMACBuilder pbkdf2(&sha256, "mySecretPassword", "randomSalt123", 100);
100+
101+
pbkdf2.begin();
102+
pbkdf2.calculate();
103+
104+
Serial.print("Password: ");
105+
Serial.println("mySecretPassword");
106+
Serial.print("Salt: ");
107+
Serial.println("randomSalt123");
108+
Serial.print("Iterations: ");
109+
Serial.println(100);
110+
Serial.print("Output (hex): ");
111+
Serial.println(pbkdf2.toString());
112+
113+
// Expected: 4ce309e56a37e0a4b9b84b98ed4a94e6c5cd5926cfd3baca3a6dea8c5d7903e8
114+
String expected = "4ce309e56a37e0a4b9b84b98ed4a94e6c5cd5926cfd3baca3a6dea8c5d7903e8";
115+
String result = pbkdf2.toString();
116+
117+
if (result.equalsIgnoreCase(expected)) {
118+
Serial.println("✓ PASS: Output matches expected value");
119+
} else {
120+
Serial.println("✗ FAIL: Output does not match expected value");
121+
Serial.print("Expected: ");
122+
Serial.println(expected);
123+
Serial.print("Got: ");
124+
Serial.println(result);
125+
}
126+
}
127+
128+
// Test 4: PBKDF2-HMAC-SHA1 with byte arrays
129+
Serial.println("\n4. PBKDF2-HMAC-SHA1 Test (byte arrays)");
130+
{
131+
SHA1Builder sha1; // or any other hash algorithm based on HashBuilder
132+
PBKDF2_HMACBuilder pbkdf2(&sha1);
133+
134+
uint8_t password[] = {0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64}; // "password" in bytes
135+
uint8_t salt[] = {0x73, 0x61, 0x6c, 0x74}; // "salt" in bytes
136+
137+
pbkdf2.begin();
138+
pbkdf2.setPassword(password, sizeof(password));
139+
pbkdf2.setSalt(salt, sizeof(salt));
140+
pbkdf2.setIterations(1);
141+
pbkdf2.calculate();
142+
143+
Serial.print("Password (bytes): ");
144+
for (int i = 0; i < sizeof(password); i++) {
145+
Serial.print((char)password[i]);
146+
}
147+
Serial.println();
148+
Serial.print("Salt (bytes): ");
149+
for (int i = 0; i < sizeof(salt); i++) {
150+
Serial.print((char)salt[i]);
151+
}
152+
Serial.println();
153+
Serial.print("Iterations: ");
154+
Serial.println(1);
155+
Serial.print("Output (hex): ");
156+
Serial.println(pbkdf2.toString());
157+
158+
// Expected: 0c60c80f961f0e71f3a9b524af6012062fe037a6 (same as test 1)
159+
String expected = "0c60c80f961f0e71f3a9b524af6012062fe037a6";
160+
String result = pbkdf2.toString();
161+
162+
if (result.equalsIgnoreCase(expected)) {
163+
Serial.println("✓ PASS: Output matches expected value");
164+
} else {
165+
Serial.println("✗ FAIL: Output does not match expected value");
166+
Serial.print("Expected: ");
167+
Serial.println(expected);
168+
Serial.print("Got: ");
169+
Serial.println(result);
170+
}
171+
}
172+
173+
Serial.println("\nPBKDF2-HMAC tests completed!");
174+
}
175+
176+
void loop() {
177+
// Nothing to do in loop
178+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /