Clean up code, add examples

This commit is contained in:
h5p9sl 2020-12-31 22:24:10 -07:00
parent 76ac6669de
commit 79a57d2a85
7 changed files with 149 additions and 55 deletions

View File

@ -1,54 +1,48 @@
# [hmac_sha256](https://github.com/h5p9sl/hmac_sha256) # [hmac_sha256](https://github.com/h5p9sl/hmac_sha256)
A SHA256 HMAC implementation in C/C++ *A SHA256 HMAC implementation in C/C++*
## Usage Example (C++) ## Usage Example (C++)
```cpp ```cpp
#include "hmac_sha256.h" #include "../hmac_sha256.h"
#include <vector> #include <vector>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <iomanip>
#include <cassert>
#define SHA256_HASHLEN 32 #define SHA256_HASH_SIZE 32
int main() { int main() {
// This is what the hmac_sha256 value should output const std::string str_data = "Hello World!";
const std::string testvector = "b0344c61d8db38535ca8afceafbf12b881dc20c9833da726e9376c2e32cff7"; const std::string str_key = "super-secret-key";
const std::string str_data = "Hi There"; std::stringstream ss_result;
std::vector<uint8_t> key, data, out; // Allocate memory for the HMAC
std::stringstream result; std::vector<uint8_t> out(SHA256_HASH_SIZE);
// Allocate memory using C++ std::vector
key.resize(20, 0x0b);
data.resize(str_data.length(), 0);
out.resize(SHA256_HASHLEN, 0);
// Fill `data` with `str_data`'s bytes
data.assign(str_data.cbegin(), str_data.cend());
// Call hmac-sha256 function // Call hmac-sha256 function
hmac_sha256( hmac_sha256(
key.data(), key.size(), str_key.data(), str_key.size(),
data.data(), data.size(), str_data.data(), str_data.size(),
out.data(), out.size() out.data(), out.size()
); );
// Convert `out` to string with std::hex // Convert `out` to string with std::hex
for (size_t i = 0; i < out.size(); i++) { for (uint8_t x : out) {
result << std::hex << (int)out[i]; ss_result << std::hex << std::setfill('0') << std::setw(2) << (int)x;
}
std::cout << result.str() << std::endl;
std::cout << testvector << std::endl;
// Compare result
if (testvector.compare(result.str()) == 0) {
std::cout << "Test passed!" << std::endl;
} else {
std::cout << "Test failed." << std::endl;
} }
// Print out the result
std::cout << "Message: " << str_data << std::endl;
std::cout << "HMAC: " << ss_result.str() << std::endl;
// This assertion fails if something went wrong
assert(
ss_result.str() ==
"4b393abced1c497f8048860ba1ede46a23f1ff5209b18e9c428bddfbb690aad8"
);
return 0; return 0;
} }
``` ```

View File

@ -0,0 +1,42 @@
#include "../hmac_sha256.h"
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cassert>
#define SHA256_HASH_SIZE 32
int main() {
const std::string str_data = "Hello World!";
const std::string str_key = "super-secret-key";
std::stringstream ss_result;
// Allocate memory for the HMAC
std::vector<uint8_t> out(SHA256_HASH_SIZE);
// Call hmac-sha256 function
hmac_sha256(
str_key.data(), str_key.size(),
str_data.data(), str_data.size(),
out.data(), out.size()
);
// Convert `out` to string with std::hex
for (uint8_t x : out) {
ss_result << std::hex << std::setfill('0') << std::setw(2) << (int)x;
}
// Print out the result
std::cout << "Message: " << str_data << std::endl;
std::cout << "HMAC: " << ss_result.str() << std::endl;
// This assertion fails if something went wrong
assert(
ss_result.str() ==
"4b393abced1c497f8048860ba1ede46a23f1ff5209b18e9c428bddfbb690aad8"
);
return 0;
}

58
examples/tests.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "../hmac_sha256.h"
#include <cassert>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
#define SHA256_HASH_SIZE 32
typedef std::vector<std::tuple<std::string, std::string, std::string>> TestData_t;
void do_tests(const TestData_t& test_vectors) {
// Perform tests
for (auto tvec : test_vectors) {
std::stringstream ss_result;
std::vector<uint8_t> out(SHA256_HASH_SIZE);
hmac_sha256(
std::get<0>(tvec).data(), std::get<0>(tvec).size(),
std::get<1>(tvec).data(), std::get<1>(tvec).size(),
out.data(), out.size()
);
for (uint8_t i : out) { ss_result << std::hex << std::setfill('0') << std::setw(2) << (int)i; }
if (std::get<2>(tvec) != ss_result.str()) {
std::cout << "TEST FAILED: \n\t" << ss_result.str() << " != \n\t" << std::get<2>(tvec) << std::endl;
} else {
std::cout << "Test successful" << std::endl;
}
}
}
int main() {
const TestData_t test_vectors = {
// Key Data HMAC
{
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
"Hi There",
"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
}, {
"Jefe",
"what do ya want for nothing?",
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
}, {
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
}, {
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
"\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
},
};
do_tests(test_vectors);
return 0;
}

View File

@ -4,24 +4,25 @@
*/ */
#include "hmac_sha256.h" #include "hmac_sha256.h"
#include "WjCryptLib_Sha256.h" #include "sha256.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define SIZEOFARRAY(x) sizeof(x) / sizeof(x[0]) #define SIZEOFARRAY(x) sizeof(x) / sizeof(x[0])
#define SHA256_BLOCK_SIZE 64
/* LOCAL FUNCTIONS */ /* LOCAL FUNCTIONS */
void sha256(const uint8_t* data, const unsigned datalen, uint8_t* out);
void appendAndHash(const uint8_t* dest, const unsigned destlen, const uint8_t* src, const unsigned srclen, uint8_t* out, const unsigned outlen // wrapper for sha256 digest functions
); void sha256(const void *data, const unsigned datalen, void *out);
// concatonate src & dest then sha2 digest them
void concat_and_hash(const void *dest, const unsigned destlen, const void *src,
const unsigned srclen, void *out, const unsigned outlen);
// Declared in hmac_sha256.h // Declared in hmac_sha256.h
void hmac_sha256( void hmac_sha256(const void *key, const unsigned keylen, const void *data,
const uint8_t* key, const unsigned keylen, const unsigned datalen, void *out, const unsigned outlen) {
const uint8_t* data, const unsigned datalen,
uint8_t* out, const unsigned outlen)
{
uint8_t k[SHA256_BLOCK_SIZE]; // block-sized key derived from 'key' parameter uint8_t k[SHA256_BLOCK_SIZE]; // block-sized key derived from 'key' parameter
uint8_t k_ipad[SHA256_BLOCK_SIZE]; uint8_t k_ipad[SHA256_BLOCK_SIZE];
uint8_t k_opad[SHA256_BLOCK_SIZE]; uint8_t k_opad[SHA256_BLOCK_SIZE];
@ -32,7 +33,8 @@ void hmac_sha256(
// Fill 'k' with zero bytes // Fill 'k' with zero bytes
memset(k, 0, SIZEOFARRAY(k)); memset(k, 0, SIZEOFARRAY(k));
if (keylen > SHA256_BLOCK_SIZE) { if (keylen > SHA256_BLOCK_SIZE) {
// If the key is larger than the hash algorithm's block size, we must digest it first. // If the key is larger than the hash algorithm's block size, we must
// digest it first.
sha256(key, keylen, k); sha256(key, keylen, k);
} else { } else {
memcpy(k, key, keylen); memcpy(k, key, keylen);
@ -48,8 +50,10 @@ void hmac_sha256(
// Perform HMAC algorithm H(K XOR opad, H(K XOR ipad, text)) // Perform HMAC algorithm H(K XOR opad, H(K XOR ipad, text))
// https://tools.ietf.org/html/rfc2104 // https://tools.ietf.org/html/rfc2104
appendAndHash(k_ipad, SIZEOFARRAY(k_ipad), data, datalen, hash0, SIZEOFARRAY(hash0)); concat_and_hash(k_ipad, SIZEOFARRAY(k_ipad), data, datalen, hash0,
appendAndHash(k_opad, SIZEOFARRAY(k_opad), hash0, SIZEOFARRAY(hash0), hash1, SIZEOFARRAY(hash1)); SIZEOFARRAY(hash0));
concat_and_hash(k_opad, SIZEOFARRAY(k_opad), hash0, SIZEOFARRAY(hash0), hash1,
SIZEOFARRAY(hash1));
// Copy the resulting hash the output buffer // Copy the resulting hash the output buffer
// Trunacate sha256 hash if needed // Trunacate sha256 hash if needed
@ -57,11 +61,8 @@ void hmac_sha256(
memcpy(out, hash1, sz); memcpy(out, hash1, sz);
} }
void appendAndHash( void concat_and_hash(const void *dest, const unsigned destlen, const void *src,
const uint8_t* dest, const unsigned destlen, const unsigned srclen, void *out, const unsigned outlen) {
const uint8_t* src, const unsigned srclen,
uint8_t* out, const unsigned outlen)
{
uint8_t buf[destlen + srclen]; uint8_t buf[destlen + srclen];
uint8_t hash[SHA256_HASH_SIZE]; uint8_t hash[SHA256_HASH_SIZE];
@ -77,7 +78,7 @@ void appendAndHash(
memcpy(out, hash, SHA256_HASH_SIZE); memcpy(out, hash, SHA256_HASH_SIZE);
} }
void sha256(const uint8_t* data, const unsigned datalen, uint8_t* out) { void sha256(const void *data, const unsigned datalen, void *out) {
Sha256Context ctx; Sha256Context ctx;
SHA256_HASH hash; SHA256_HASH hash;

View File

@ -14,11 +14,11 @@ extern "C" {
void hmac_sha256( void hmac_sha256(
// [in]: The key and it's length. Should be at least 32 bytes long for optimal security. // [in]: The key and it's length. Should be at least 32 bytes long for optimal security.
const uint8_t* key, const unsigned keylen, const void* key, const unsigned keylen,
// [in]: The data to hash along with the key. // [in]: The data to hash along with the key.
const uint8_t* data, const unsigned datalen, const void* data, const unsigned datalen,
// [out]: The output hash. Should be 32 bytes long, but if it's less than 32 bytes, the function will truncate the resulting hash. // [out]: The output hash. Should be 32 bytes long, but if it's less than 32 bytes, the function will truncate the resulting hash.
uint8_t* out, const unsigned outlen void* out, const unsigned outlen
); );
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -12,7 +12,7 @@
// IMPORTS // IMPORTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "WjCryptLib_Sha256.h" #include "sha256.h"
#include <memory.h> #include <memory.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -26,7 +26,6 @@ typedef struct
} Sha256Context; } Sha256Context;
#define SHA256_HASH_SIZE ( 256 / 8 ) #define SHA256_HASH_SIZE ( 256 / 8 )
#define SHA256_BLOCK_SIZE ( 512 / 8 )
typedef struct typedef struct
{ {