3.3.7
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Usage example for the HEXBuilder class.
|
||||
|
||||
This example shows how to convert a HEX string to a binary buffer and vice versa.
|
||||
*/
|
||||
|
||||
#include <HEXBuilder.h>
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println("\n\n\nStart.");
|
||||
|
||||
// Convert a HEX string like 6c6c6f20576f726c64 to a binary buffer
|
||||
{
|
||||
const char *out = "Hello World";
|
||||
const char *hexin = "48656c6c6f20576f726c6400"; // As the string above is \0 terminated too
|
||||
|
||||
unsigned char buff[256];
|
||||
size_t len = HEXBuilder::hex2bytes(buff, sizeof(buff), hexin);
|
||||
|
||||
if (len != 1 + strlen(out)) {
|
||||
Serial.println("Odd - length 1 is wrong");
|
||||
}
|
||||
|
||||
if (memcmp(buff, out, len) != 0) {
|
||||
Serial.println("Odd - decode 1 went wrong");
|
||||
}
|
||||
|
||||
// Safe to print this binary buffer -- as we've included a \0 in the hex sequence.
|
||||
Serial.printf("IN: <%s>\nOUT <%s\\0>\n", hexin, buff);
|
||||
};
|
||||
|
||||
{
|
||||
String helloHEX = "48656c6c6f20576f726c64";
|
||||
const char hello[] = "Hello World";
|
||||
|
||||
unsigned char buff[256];
|
||||
size_t len = HEXBuilder::hex2bytes(buff, sizeof(buff), helloHEX);
|
||||
|
||||
if (len != strlen(hello)) {
|
||||
Serial.println("Odd - length 2 is wrong");
|
||||
}
|
||||
|
||||
if (strcmp((char *)buff, hello) != 0) {
|
||||
Serial.println("Odd - decode 2 went wrong");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const unsigned char helloBytes[] = {0x48, 0x56, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64};
|
||||
String helloHEX = "48566c6c6f20576f726c64";
|
||||
|
||||
String out = HEXBuilder::bytes2hex(helloBytes, sizeof(helloBytes));
|
||||
if (out.length() != 2 * sizeof(helloBytes)) {
|
||||
Serial.println("Odd - length 3 is wrong");
|
||||
}
|
||||
|
||||
// we need to ignore case - as a hex string can be spelled in uppercase and lowercase
|
||||
if (!out.equalsIgnoreCase(helloHEX)) {
|
||||
Serial.println("Odd - decode 3 went wrong");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const unsigned char helloBytes[] = {0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64};
|
||||
const char helloHex[] = "6c6c6f20576f726c64";
|
||||
|
||||
char buff[256];
|
||||
size_t len = HEXBuilder::bytes2hex(buff, sizeof(buff), helloBytes, sizeof(helloBytes));
|
||||
if (len != 1 + 2 * sizeof(helloBytes)) {
|
||||
Serial.println("Odd - length 4 is wrong");
|
||||
}
|
||||
|
||||
// we need to ignore case - as a hex string can be spelled in uppercase and lowercase
|
||||
if (strcasecmp(buff, helloHex)) {
|
||||
Serial.println("Odd - decode 4 went wrong");
|
||||
}
|
||||
}
|
||||
Serial.println("Done.");
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
@@ -0,0 +1,95 @@
|
||||
#include <MD5Builder.h>
|
||||
|
||||
// Occasionally it is useful to compare a password that the user
|
||||
// has entered to a build in string. However this means that the
|
||||
// password ends up `in the clear' in the firmware and in your
|
||||
// source code.
|
||||
//
|
||||
// MD5Builder helps you obfuscate this (it is not terribly secure, MD5
|
||||
// has been phased out as insecure eons ago) by letting you create an
|
||||
// MD5 of the data the user entered; and then compare this to an MD5
|
||||
// string that you have put in your code.
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println("\n\n\nStart.");
|
||||
|
||||
// Check if a password obfuscated in an MD5 actually
|
||||
// matches the original string.
|
||||
//
|
||||
// echo -n "Hello World" | openssl md5
|
||||
{
|
||||
String md5 = "b10a8db164e0754105b7a99be72e3fe5";
|
||||
String password = "Hello World";
|
||||
|
||||
MD5Builder md;
|
||||
|
||||
md.begin();
|
||||
md.add(password);
|
||||
md.calculate();
|
||||
|
||||
String result = md.toString();
|
||||
|
||||
if (!md5.equalsIgnoreCase(result)) {
|
||||
Serial.println("Odd - failing MD5 on String");
|
||||
} else {
|
||||
Serial.println("OK!");
|
||||
}
|
||||
}
|
||||
|
||||
// Check that this also work if we add the password not as
|
||||
// a normal string - but as a string with the HEX values.
|
||||
{
|
||||
String passwordAsHex = "48656c6c6f20576f726c64";
|
||||
String md5 = "b10a8db164e0754105b7a99be72e3fe5";
|
||||
|
||||
MD5Builder md;
|
||||
|
||||
md.begin();
|
||||
md.addHexString(passwordAsHex);
|
||||
md.calculate();
|
||||
|
||||
String result = md.toString();
|
||||
|
||||
if (!md5.equalsIgnoreCase(result)) {
|
||||
Serial.println("Odd - failing MD5 on hex string");
|
||||
Serial.println(md5);
|
||||
Serial.println(result);
|
||||
} else {
|
||||
Serial.println("OK!");
|
||||
}
|
||||
}
|
||||
|
||||
// Check that this also work if we add the password as
|
||||
// an unsigned byte array.
|
||||
{
|
||||
uint8_t password[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64};
|
||||
String md5 = "b10a8db164e0754105b7a99be72e3fe5";
|
||||
MD5Builder md;
|
||||
|
||||
md.begin();
|
||||
md.add(password, sizeof(password));
|
||||
md.calculate();
|
||||
|
||||
String result = md.toString();
|
||||
|
||||
if (!md5.equalsIgnoreCase(result)) {
|
||||
Serial.println("Odd - failing MD5 on byte array");
|
||||
} else {
|
||||
Serial.println("OK!");
|
||||
}
|
||||
|
||||
// And also check that we can compare this as pure, raw, bytes
|
||||
uint8_t raw[16] = {0xb1, 0x0a, 0x8d, 0xb1, 0x64, 0xe0, 0x75, 0x41, 0x05, 0xb7, 0xa9, 0x9b, 0xe7, 0x2e, 0x3f, 0xe5};
|
||||
uint8_t res[16];
|
||||
md.getBytes(res);
|
||||
if (memcmp(raw, res, 16)) {
|
||||
Serial.println("Odd - failing MD5 on byte array when compared as bytes");
|
||||
} else {
|
||||
Serial.println("OK!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
Usage example for the PBKDF2_HMACBuilder class.
|
||||
|
||||
This example shows how to use the Hash library to hash data using the PBKDF2_HMACBuilder class.
|
||||
PBKDF2_HMAC (Password-Based Key Derivation Function 2) is a key derivation function that uses a password and a salt to derive a key.
|
||||
|
||||
The PBKDF2_HMACBuilder class takes for arguments:
|
||||
- A HashBuilder object to use for the HMAC (SHA1Builder, SHA2Builder, SHA3Builder, etc.)
|
||||
- A password string (default: empty)
|
||||
- A salt string (default: empty)
|
||||
- The number of iterations (default: 1000)
|
||||
*/
|
||||
|
||||
#include <SHA1Builder.h>
|
||||
#include <SHA2Builder.h>
|
||||
#include <PBKDF2_HMACBuilder.h>
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("\n\nPBKDF2-HMAC Example");
|
||||
Serial.println("===================");
|
||||
|
||||
// Test 1: Basic PBKDF2-HMAC-SHA1
|
||||
Serial.println("\n1. PBKDF2-HMAC-SHA1 Test (1 iteration)");
|
||||
{
|
||||
SHA1Builder sha1;
|
||||
PBKDF2_HMACBuilder pbkdf2(&sha1, "password", "salt", 1);
|
||||
|
||||
pbkdf2.begin();
|
||||
pbkdf2.calculate();
|
||||
|
||||
Serial.print("Password: ");
|
||||
Serial.println("password");
|
||||
Serial.print("Salt: ");
|
||||
Serial.println("salt");
|
||||
Serial.print("Iterations: ");
|
||||
Serial.println(1);
|
||||
Serial.print("Output (hex): ");
|
||||
Serial.println(pbkdf2.toString());
|
||||
|
||||
// Expected: 0c60c80f961f0e71f3a9b524af6012062fe037a6
|
||||
String expected = "0c60c80f961f0e71f3a9b524af6012062fe037a6";
|
||||
String result = pbkdf2.toString();
|
||||
|
||||
if (result.equalsIgnoreCase(expected)) {
|
||||
Serial.println("✓ PASS: Output matches expected value");
|
||||
} else {
|
||||
Serial.println("✗ FAIL: Output does not match expected value");
|
||||
Serial.print("Expected: ");
|
||||
Serial.println(expected);
|
||||
Serial.print("Got: ");
|
||||
Serial.println(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 2: PBKDF2-HMAC-SHA1 with more iterations
|
||||
Serial.println("\n2. PBKDF2-HMAC-SHA1 Test (1000 iterations)");
|
||||
{
|
||||
SHA1Builder sha1;
|
||||
PBKDF2_HMACBuilder pbkdf2(&sha1);
|
||||
|
||||
const char *password = "password";
|
||||
const char *salt = "salt";
|
||||
|
||||
pbkdf2.begin();
|
||||
pbkdf2.setPassword(password);
|
||||
pbkdf2.setSalt(salt);
|
||||
pbkdf2.setIterations(1000);
|
||||
pbkdf2.calculate();
|
||||
|
||||
Serial.print("Password: ");
|
||||
Serial.println(password);
|
||||
Serial.print("Salt: ");
|
||||
Serial.println(salt);
|
||||
Serial.print("Iterations: ");
|
||||
Serial.println(1000);
|
||||
Serial.print("Output (hex): ");
|
||||
Serial.println(pbkdf2.toString());
|
||||
|
||||
// Expected: 6e88be8bad7eae9d9e10aa061224034fed48d03f
|
||||
String expected = "6e88be8bad7eae9d9e10aa061224034fed48d03f";
|
||||
String result = pbkdf2.toString();
|
||||
|
||||
if (result.equalsIgnoreCase(expected)) {
|
||||
Serial.println("✓ PASS: Output matches expected value");
|
||||
} else {
|
||||
Serial.println("✗ FAIL: Output does not match expected value");
|
||||
Serial.print("Expected: ");
|
||||
Serial.println(expected);
|
||||
Serial.print("Got: ");
|
||||
Serial.println(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 3: PBKDF2-HMAC-SHA256 with different password and salt
|
||||
Serial.println("\n3. PBKDF2-HMAC-SHA256 Test");
|
||||
{
|
||||
SHA256Builder sha256;
|
||||
PBKDF2_HMACBuilder pbkdf2(&sha256, "mySecretPassword", "randomSalt123", 100);
|
||||
|
||||
pbkdf2.begin();
|
||||
pbkdf2.calculate();
|
||||
|
||||
Serial.print("Password: ");
|
||||
Serial.println("mySecretPassword");
|
||||
Serial.print("Salt: ");
|
||||
Serial.println("randomSalt123");
|
||||
Serial.print("Iterations: ");
|
||||
Serial.println(100);
|
||||
Serial.print("Output (hex): ");
|
||||
Serial.println(pbkdf2.toString());
|
||||
|
||||
// Expected: 4ce309e56a37e0a4b9b84b98ed4a94e6c5cd5926cfd3baca3a6dea8c5d7903e8
|
||||
String expected = "4ce309e56a37e0a4b9b84b98ed4a94e6c5cd5926cfd3baca3a6dea8c5d7903e8";
|
||||
String result = pbkdf2.toString();
|
||||
|
||||
if (result.equalsIgnoreCase(expected)) {
|
||||
Serial.println("✓ PASS: Output matches expected value");
|
||||
} else {
|
||||
Serial.println("✗ FAIL: Output does not match expected value");
|
||||
Serial.print("Expected: ");
|
||||
Serial.println(expected);
|
||||
Serial.print("Got: ");
|
||||
Serial.println(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 4: PBKDF2-HMAC-SHA1 with byte arrays
|
||||
Serial.println("\n4. PBKDF2-HMAC-SHA1 Test (byte arrays)");
|
||||
{
|
||||
SHA1Builder sha1; // or any other hash algorithm based on HashBuilder
|
||||
PBKDF2_HMACBuilder pbkdf2(&sha1);
|
||||
|
||||
uint8_t password[] = {0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64}; // "password" in bytes
|
||||
uint8_t salt[] = {0x73, 0x61, 0x6c, 0x74}; // "salt" in bytes
|
||||
|
||||
pbkdf2.begin();
|
||||
pbkdf2.setPassword(password, sizeof(password));
|
||||
pbkdf2.setSalt(salt, sizeof(salt));
|
||||
pbkdf2.setIterations(1);
|
||||
pbkdf2.calculate();
|
||||
|
||||
Serial.print("Password (bytes): ");
|
||||
for (int i = 0; i < sizeof(password); i++) {
|
||||
Serial.print((char)password[i]);
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("Salt (bytes): ");
|
||||
for (int i = 0; i < sizeof(salt); i++) {
|
||||
Serial.print((char)salt[i]);
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("Iterations: ");
|
||||
Serial.println(1);
|
||||
Serial.print("Output (hex): ");
|
||||
Serial.println(pbkdf2.toString());
|
||||
|
||||
// Expected: 0c60c80f961f0e71f3a9b524af6012062fe037a6 (same as test 1)
|
||||
String expected = "0c60c80f961f0e71f3a9b524af6012062fe037a6";
|
||||
String result = pbkdf2.toString();
|
||||
|
||||
if (result.equalsIgnoreCase(expected)) {
|
||||
Serial.println("✓ PASS: Output matches expected value");
|
||||
} else {
|
||||
Serial.println("✗ FAIL: Output does not match expected value");
|
||||
Serial.print("Expected: ");
|
||||
Serial.println(expected);
|
||||
Serial.print("Got: ");
|
||||
Serial.println(result);
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println("\nPBKDF2-HMAC tests completed!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Nothing to do in loop
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#include <SHA1Builder.h>
|
||||
|
||||
// Occasionally it is useful to compare a password that the user
|
||||
// has entered to a build in string. However this means that the
|
||||
// password ends up `in the clear' in the firmware and in your
|
||||
// source code.
|
||||
//
|
||||
// SHA1Builder helps you obfuscate this (This is not much more secure.
|
||||
// SHA1 is past its retirement age and long obsolete/insecure, but it helps
|
||||
// a little) by letting you create an (unsalted!) SHA1 of the data the
|
||||
// user entered; and then compare this to an SHA1 string that you have put
|
||||
// in your code.
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println("\n\n\nStart.");
|
||||
|
||||
// Check if a password obfuscated in an SHA1 actually
|
||||
// matches the original string.
|
||||
//
|
||||
// echo -n "Hello World" | openssl sha1
|
||||
{
|
||||
String sha1_str = "0a4d55a8d778e5022fab701977c5d840bbc486d0";
|
||||
String password = "Hello World";
|
||||
|
||||
SHA1Builder sha;
|
||||
|
||||
sha.begin();
|
||||
sha.add(password);
|
||||
sha.calculate();
|
||||
|
||||
String result = sha.toString();
|
||||
|
||||
if (!sha1_str.equalsIgnoreCase(result)) {
|
||||
Serial.println("Odd - failing SHA1 on String");
|
||||
} else {
|
||||
Serial.println("OK!");
|
||||
}
|
||||
}
|
||||
|
||||
// Check that this also work if we add the password not as
|
||||
// a normal string - but as a string with the HEX values.
|
||||
{
|
||||
String passwordAsHex = "48656c6c6f20576f726c64";
|
||||
String sha1_str = "0a4d55a8d778e5022fab701977c5d840bbc486d0";
|
||||
|
||||
SHA1Builder sha;
|
||||
|
||||
sha.begin();
|
||||
sha.addHexString(passwordAsHex);
|
||||
sha.calculate();
|
||||
|
||||
String result = sha.toString();
|
||||
|
||||
if (!sha1_str.equalsIgnoreCase(result)) {
|
||||
Serial.println("Odd - failing SHA1 on hex string");
|
||||
Serial.println(sha1_str);
|
||||
Serial.println(result);
|
||||
} else {
|
||||
Serial.println("OK!");
|
||||
}
|
||||
}
|
||||
|
||||
// Check that this also work if we add the password as
|
||||
// an unsigned byte array.
|
||||
{
|
||||
uint8_t password[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64};
|
||||
String sha1_str = "0a4d55a8d778e5022fab701977c5d840bbc486d0";
|
||||
SHA1Builder sha;
|
||||
|
||||
sha.begin();
|
||||
sha.add(password, sizeof(password));
|
||||
sha.calculate();
|
||||
|
||||
String result = sha.toString();
|
||||
|
||||
if (!sha1_str.equalsIgnoreCase(result)) {
|
||||
Serial.println("Odd - failing SHA1 on byte array");
|
||||
} else {
|
||||
Serial.println("OK!");
|
||||
}
|
||||
|
||||
// And also check that we can compare this as pure, raw, bytes
|
||||
uint8_t raw[20] = {0x0a, 0x4d, 0x55, 0xa8, 0xd7, 0x78, 0xe5, 0x02, 0x2f, 0xab, 0x70, 0x19, 0x77, 0xc5, 0xd8, 0x40, 0xbb, 0xc4, 0x86, 0xd0};
|
||||
uint8_t res[20];
|
||||
sha.getBytes(res);
|
||||
if (memcmp(raw, res, 20)) {
|
||||
Serial.println("Odd - failing SHA1 on byte array when compared as bytes");
|
||||
} else {
|
||||
Serial.println("OK!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Usage example for the SHA2Builder class.
|
||||
|
||||
This example shows how to use the SHA2 library to hash data using the SHA2Builder class.
|
||||
SHA2 (Secure Hash Algorithm 2) provides different output sizes: SHA-224, SHA-256, SHA-384, and SHA-512.
|
||||
|
||||
Available constructors:
|
||||
- SHA224Builder(): 224-bit hash output
|
||||
- SHA256Builder(): 256-bit hash output
|
||||
- SHA384Builder(): 384-bit hash output
|
||||
- SHA512Builder(): 512-bit hash output
|
||||
- SHA2Builder(size_t hash_size): Generic class that can be used to create any SHA2 variant implemented
|
||||
*/
|
||||
|
||||
#include <SHA2Builder.h>
|
||||
|
||||
// Expected hash values for validation
|
||||
const char *EXPECTED_HELLO_WORLD_SHA256 = "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e";
|
||||
const char *EXPECTED_HELLO_WORLD_SHA512 =
|
||||
"2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b";
|
||||
const char *EXPECTED_TEST_MESSAGE_SHA224 = "155b033d801d4dd59b783d76ac3059053c00b2c28340a5a36a427a76";
|
||||
const char *EXPECTED_TEST_MESSAGE_SHA384 = "efd336618cbc96551936e5897e6af391d2480513ff8d4fc744e34462edb3111477d2b889c4d5e80e23b5f9d1b636fbd7";
|
||||
|
||||
// Validation function
|
||||
bool validateHash(const String &calculated, const char *expected, const String &test_name) {
|
||||
bool passed = (calculated == expected);
|
||||
Serial.print(test_name);
|
||||
Serial.print(": ");
|
||||
Serial.println(passed ? "PASS" : "FAIL");
|
||||
Serial.print(" Expected: ");
|
||||
Serial.println(expected);
|
||||
Serial.print(" Got: ");
|
||||
Serial.println(calculated);
|
||||
return passed;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println("\n\n\nStart.");
|
||||
|
||||
// Using SHA2Builder class directly with different hash sizes
|
||||
{
|
||||
String test_data = "Hello World";
|
||||
Serial.println("Test data: " + test_data);
|
||||
|
||||
// Create SHA-256 (default hash size)
|
||||
SHA2Builder sha2_256;
|
||||
sha2_256.begin();
|
||||
sha2_256.add(test_data);
|
||||
sha2_256.calculate();
|
||||
String hash_256 = sha2_256.toString();
|
||||
validateHash(hash_256, EXPECTED_HELLO_WORLD_SHA256, "SHA-256 validation");
|
||||
|
||||
// Create SHA-512
|
||||
SHA2Builder sha2_512(SHA2_512_HASH_SIZE);
|
||||
sha2_512.begin();
|
||||
sha2_512.add(test_data);
|
||||
sha2_512.calculate();
|
||||
String hash_512 = sha2_512.toString();
|
||||
validateHash(hash_512, EXPECTED_HELLO_WORLD_SHA512, "SHA-512 validation");
|
||||
}
|
||||
|
||||
// Example using SHA224Builder and SHA384Builder
|
||||
// There are other constructors for other hash sizes available:
|
||||
// - SHA224Builder()
|
||||
// - SHA256Builder()
|
||||
// - SHA384Builder()
|
||||
// - SHA512Builder()
|
||||
// - SHA2Builder(size_t hash_size)
|
||||
{
|
||||
String test_data = "Test message";
|
||||
Serial.println("Test data: " + test_data);
|
||||
|
||||
// Create SHA-224 using specific constructor
|
||||
SHA224Builder sha2_224;
|
||||
sha2_224.begin();
|
||||
sha2_224.add(test_data);
|
||||
sha2_224.calculate();
|
||||
String hash_224 = sha2_224.toString();
|
||||
validateHash(hash_224, EXPECTED_TEST_MESSAGE_SHA224, "SHA224Builder validation");
|
||||
|
||||
// Create SHA-384 using specific constructor
|
||||
SHA384Builder sha2_384;
|
||||
sha2_384.begin();
|
||||
sha2_384.add(test_data);
|
||||
sha2_384.calculate();
|
||||
String hash_384 = sha2_384.toString();
|
||||
validateHash(hash_384, EXPECTED_TEST_MESSAGE_SHA384, "SHA384Builder validation");
|
||||
}
|
||||
|
||||
Serial.println("Done.");
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Usage example for the SHA3Builder class.
|
||||
|
||||
This example shows how to use the SHA3 library to hash data using the SHA3Builder class.
|
||||
SHA3 (Secure Hash Algorithm 3) provides different output sizes: SHA3-224, SHA3-256, SHA3-384, and SHA3-512.
|
||||
|
||||
Available constructors:
|
||||
- SHA3_224Builder(): 224-bit hash output
|
||||
- SHA3_256Builder(): 256-bit hash output
|
||||
- SHA3_384Builder(): 384-bit hash output
|
||||
- SHA3_512Builder(): 512-bit hash output
|
||||
- SHA3Builder(size_t hash_size): Generic class that can be used to create any SHA3 variant implemented
|
||||
*/
|
||||
|
||||
#include <SHA3Builder.h>
|
||||
|
||||
// Expected hash values for validation
|
||||
const char *EXPECTED_HELLO_WORLD_SHA3_256 = "e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51";
|
||||
const char *EXPECTED_HELLO_WORLD_SHA3_512 =
|
||||
"3d58a719c6866b0214f96b0a67b37e51a91e233ce0be126a08f35fdf4c043c6126f40139bfbc338d44eb2a03de9f7bb8eff0ac260b3629811e389a5fbee8a894";
|
||||
const char *EXPECTED_TEST_MESSAGE_SHA3_224 = "27af391bcb3b86f21b73c42c4abbde4791c395dc650243eede85de0c";
|
||||
const char *EXPECTED_TEST_MESSAGE_SHA3_384 = "adb18f6b164672c566950bfefa48c5a851d48ee184f249a19e723d753b7536fcd048c3443aff7ebe433fce63c81726ea";
|
||||
|
||||
// Validation function
|
||||
bool validateHash(const String &calculated, const char *expected, const String &test_name) {
|
||||
bool passed = (calculated == expected);
|
||||
Serial.print(test_name);
|
||||
Serial.print(": ");
|
||||
Serial.println(passed ? "PASS" : "FAIL");
|
||||
Serial.print(" Expected: ");
|
||||
Serial.println(expected);
|
||||
Serial.print(" Got: ");
|
||||
Serial.println(calculated);
|
||||
return passed;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println("\n\n\nStart.");
|
||||
|
||||
// Using SHA3Builder class directly with different hash sizes
|
||||
{
|
||||
String test_data = "Hello World";
|
||||
Serial.println("Test data: " + test_data);
|
||||
|
||||
// Create SHA3-256 (default hash size)
|
||||
SHA3Builder sha3_256;
|
||||
sha3_256.begin();
|
||||
sha3_256.add(test_data);
|
||||
sha3_256.calculate();
|
||||
String hash_256 = sha3_256.toString();
|
||||
validateHash(hash_256, EXPECTED_HELLO_WORLD_SHA3_256, "SHA3-256 validation");
|
||||
|
||||
// Create SHA3-512
|
||||
SHA3Builder sha3_512(SHA3_512_HASH_SIZE);
|
||||
sha3_512.begin();
|
||||
sha3_512.add(test_data);
|
||||
sha3_512.calculate();
|
||||
String hash_512 = sha3_512.toString();
|
||||
validateHash(hash_512, EXPECTED_HELLO_WORLD_SHA3_512, "SHA3-512 validation");
|
||||
}
|
||||
|
||||
// Example using SHA3_224Builder and SHA3_384Builder
|
||||
// There are other constructors for other hash sizes available:
|
||||
// - SHA3_224Builder()
|
||||
// - SHA3_256Builder()
|
||||
// - SHA3_384Builder()
|
||||
// - SHA3_512Builder()
|
||||
// - SHA3Builder(size_t hash_size)
|
||||
{
|
||||
String test_data = "Test message";
|
||||
Serial.println("Test data: " + test_data);
|
||||
|
||||
// Create SHA3-224 using specific constructor
|
||||
SHA3_224Builder sha3_224;
|
||||
sha3_224.begin();
|
||||
sha3_224.add(test_data);
|
||||
sha3_224.calculate();
|
||||
String hash_224 = sha3_224.toString();
|
||||
validateHash(hash_224, EXPECTED_TEST_MESSAGE_SHA3_224, "SHA3_224Builder validation");
|
||||
|
||||
// Create SHA3-384 using specific constructor
|
||||
SHA3_384Builder sha3_384;
|
||||
sha3_384.begin();
|
||||
sha3_384.add(test_data);
|
||||
sha3_384.calculate();
|
||||
String hash_384 = sha3_384.toString();
|
||||
validateHash(hash_384, EXPECTED_TEST_MESSAGE_SHA3_384, "SHA3_384Builder validation");
|
||||
}
|
||||
|
||||
Serial.println("Done.");
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
Usage example for the SHA3Builder class with streams.
|
||||
|
||||
This example shows how to use the SHA3 library to hash data from streams using the addStream method.
|
||||
This is useful for hashing large files or data that comes from various stream sources like:
|
||||
- File streams
|
||||
- Network streams
|
||||
- Memory streams
|
||||
- Custom stream implementations
|
||||
|
||||
Available constructors:
|
||||
- SHA3_224Builder(): 224-bit hash output
|
||||
- SHA3_256Builder(): 256-bit hash output
|
||||
- SHA3_384Builder(): 384-bit hash output
|
||||
- SHA3_512Builder(): 512-bit hash output
|
||||
- SHA3Builder(size_t hash_size): Generic class that can be used to create any SHA3 variant implemented
|
||||
*/
|
||||
|
||||
#include <SHA3Builder.h>
|
||||
#include <Stream.h>
|
||||
|
||||
// Expected hash values for validation
|
||||
const char *EXPECTED_STREAM_TEST_SHA3_256 = "7094efc774885c7a785b408c5da86636cb8adc79156c0f162c6fd7e49f4c505e";
|
||||
const char *EXPECTED_MAX_SHA3_224_FULL = "ad0e69e04a7258d7cab4272a08ac69f8b43f4e45f9c49c9abb0628af";
|
||||
const char *EXPECTED_MAX_SHA3_224_10 = "9b55096e998cda6b96d3f2828c4ccda8c9964a1ad98989fb8b0fcd26";
|
||||
const char *EXPECTED_COMBINED_SHA3_256 = "4a32307fe03bf9f600c5d124419985fd4d42c1639e6a23ab044f107c3b95a189";
|
||||
|
||||
// Validation function
|
||||
bool validateHash(const String &calculated, const char *expected, const String &test_name) {
|
||||
bool passed = (calculated == expected);
|
||||
Serial.print(test_name);
|
||||
Serial.print(": ");
|
||||
Serial.println(passed ? "PASS" : "FAIL");
|
||||
Serial.print(" Expected: ");
|
||||
Serial.println(expected);
|
||||
Serial.print(" Got: ");
|
||||
Serial.println(calculated);
|
||||
return passed;
|
||||
}
|
||||
|
||||
// Custom stream class for demonstration
|
||||
class TestStream : public Stream {
|
||||
private:
|
||||
String data;
|
||||
size_t position;
|
||||
|
||||
public:
|
||||
TestStream(String input_data) : data(input_data), position(0) {}
|
||||
|
||||
virtual int available() override {
|
||||
return data.length() - position;
|
||||
}
|
||||
|
||||
virtual int read() override {
|
||||
if (position < data.length()) {
|
||||
return data.charAt(position++);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual int peek() override {
|
||||
if (position < data.length()) {
|
||||
return data.charAt(position);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual size_t write(uint8_t) override {
|
||||
return 0; // Read-only stream
|
||||
}
|
||||
|
||||
size_t length() {
|
||||
return data.length();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
position = 0;
|
||||
}
|
||||
};
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial) {
|
||||
delay(10);
|
||||
}
|
||||
|
||||
Serial.println("\n\nSHA3 Stream Example");
|
||||
Serial.println("===================");
|
||||
|
||||
// Example 1: Using addStream with a custom stream
|
||||
{
|
||||
Serial.println("\n1. Hashing data from a custom stream:");
|
||||
|
||||
const char *test_data = "This is a test message for streaming hash calculation. "
|
||||
"It contains multiple sentences to demonstrate how the "
|
||||
"addStream method processes data in chunks.";
|
||||
|
||||
TestStream stream(test_data);
|
||||
|
||||
SHA3_256Builder sha3_256;
|
||||
sha3_256.begin();
|
||||
|
||||
// Hash the entire stream
|
||||
// First argument is the stream, second argument is the maximum length to be read from the stream
|
||||
sha3_256.addStream(stream, stream.length()); // Reading the entire stream
|
||||
sha3_256.calculate();
|
||||
String hash_256 = sha3_256.toString();
|
||||
validateHash(hash_256, EXPECTED_STREAM_TEST_SHA3_256, "Stream test validation");
|
||||
}
|
||||
|
||||
// Example 2: Using addStream with different maximum lengths
|
||||
{
|
||||
Serial.println("\n2. Comparing different maximum lengths with streams:");
|
||||
|
||||
const char *test_data = "Streaming hash test with different maximum lengths";
|
||||
TestStream stream(test_data);
|
||||
|
||||
// SHA3-224 with a hardcoded maximum length
|
||||
stream.reset();
|
||||
SHA3_224Builder sha3_224_10;
|
||||
sha3_224_10.begin();
|
||||
sha3_224_10.addStream(stream, 10); // Passing a hardcoded maximum length to be read from the stream
|
||||
sha3_224_10.calculate();
|
||||
String hash_224_10 = sha3_224_10.toString();
|
||||
validateHash(hash_224_10, EXPECTED_MAX_SHA3_224_10, "SHA3-224 with 10 bytes");
|
||||
|
||||
// SHA3-224 with the full stream
|
||||
stream.reset();
|
||||
SHA3_224Builder sha3_224_full;
|
||||
sha3_224_full.begin();
|
||||
sha3_224_full.addStream(stream, stream.length()); // Reading the entire stream
|
||||
sha3_224_full.calculate();
|
||||
String hash_224_full = sha3_224_full.toString();
|
||||
validateHash(hash_224_full, EXPECTED_MAX_SHA3_224_FULL, "SHA3-224 with full stream");
|
||||
}
|
||||
|
||||
// Example 3: Combining add() and addStream()
|
||||
{
|
||||
Serial.println("\n3. Combining add() and addStream():");
|
||||
|
||||
const char *stream_data = "Additional data from stream";
|
||||
TestStream stream(stream_data);
|
||||
|
||||
SHA3_256Builder sha3_256;
|
||||
sha3_256.begin();
|
||||
|
||||
// Add some data directly
|
||||
sha3_256.add("Initial data: ");
|
||||
|
||||
// Add data from stream
|
||||
sha3_256.addStream(stream, stream.length());
|
||||
|
||||
// Add more data directly
|
||||
sha3_256.add(" : Final data");
|
||||
|
||||
sha3_256.calculate();
|
||||
String hash_256 = sha3_256.toString();
|
||||
validateHash(hash_256, EXPECTED_COMBINED_SHA3_256, "Combined data validation");
|
||||
}
|
||||
|
||||
Serial.println("\nStream example completed!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Nothing to do in loop
|
||||
}
|
||||
Reference in New Issue
Block a user