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)
A SHA256 HMAC implementation in C/C++
*A SHA256 HMAC implementation in C/C++*
## Usage Example (C++)
```cpp
#include "hmac_sha256.h"
#include "../hmac_sha256.h"
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cassert>
#define SHA256_HASHLEN 32
#define SHA256_HASH_SIZE 32
int main() {
// This is what the hmac_sha256 value should output
const std::string testvector = "b0344c61d8db38535ca8afceafbf12b881dc20c9833da726e9376c2e32cff7";
const std::string str_data = "Hi There";
const std::string str_data = "Hello World!";
const std::string str_key = "super-secret-key";
std::stringstream ss_result;
std::vector<uint8_t> key, data, out;
std::stringstream result;
// 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());
// Allocate memory for the HMAC
std::vector<uint8_t> out(SHA256_HASH_SIZE);
// Call hmac-sha256 function
hmac_sha256(
key.data(), key.size(),
data.data(), data.size(),
str_key.data(), str_key.size(),
str_data.data(), str_data.size(),
out.data(), out.size()
);
// Convert `out` to string with std::hex
for (size_t i = 0; i < out.size(); i++) {
result << std::hex << (int)out[i];
}
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;
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;
}
```

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

@ -1,27 +1,28 @@
/*
hmac_sha256.c
Originally written by https://github.com/h5p9sl
*/
*/
#include "hmac_sha256.h"
#include "WjCryptLib_Sha256.h"
#include "sha256.h"
#include <stdlib.h>
#include <string.h>
#define SIZEOFARRAY(x) sizeof(x) / sizeof(x[0])
#define SHA256_BLOCK_SIZE 64
/* 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
void hmac_sha256(
const uint8_t* key, const unsigned keylen,
const uint8_t* data, const unsigned datalen,
uint8_t* out, const unsigned outlen)
{
void hmac_sha256(const void *key, const unsigned keylen, const void *data,
const unsigned datalen, void *out, const unsigned outlen) {
uint8_t k[SHA256_BLOCK_SIZE]; // block-sized key derived from 'key' parameter
uint8_t k_ipad[SHA256_BLOCK_SIZE];
uint8_t k_opad[SHA256_BLOCK_SIZE];
@ -32,7 +33,8 @@ void hmac_sha256(
// Fill 'k' with zero bytes
memset(k, 0, SIZEOFARRAY(k));
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);
} else {
memcpy(k, key, keylen);
@ -48,8 +50,10 @@ void hmac_sha256(
// Perform HMAC algorithm H(K XOR opad, H(K XOR ipad, text))
// https://tools.ietf.org/html/rfc2104
appendAndHash(k_ipad, SIZEOFARRAY(k_ipad), data, datalen, hash0, SIZEOFARRAY(hash0));
appendAndHash(k_opad, SIZEOFARRAY(k_opad), hash0, SIZEOFARRAY(hash0), hash1, SIZEOFARRAY(hash1));
concat_and_hash(k_ipad, SIZEOFARRAY(k_ipad), data, datalen, hash0,
SIZEOFARRAY(hash0));
concat_and_hash(k_opad, SIZEOFARRAY(k_opad), hash0, SIZEOFARRAY(hash0), hash1,
SIZEOFARRAY(hash1));
// Copy the resulting hash the output buffer
// Trunacate sha256 hash if needed
@ -57,11 +61,8 @@ void hmac_sha256(
memcpy(out, hash1, sz);
}
void appendAndHash(
const uint8_t* dest, const unsigned destlen,
const uint8_t* src, const unsigned srclen,
uint8_t* out, const unsigned outlen)
{
void concat_and_hash(const void *dest, const unsigned destlen, const void *src,
const unsigned srclen, void *out, const unsigned outlen) {
uint8_t buf[destlen + srclen];
uint8_t hash[SHA256_HASH_SIZE];
@ -77,7 +78,7 @@ void appendAndHash(
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;
SHA256_HASH hash;

View File

@ -14,11 +14,11 @@ extern "C" {
void hmac_sha256(
// [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.
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.
uint8_t* out, const unsigned outlen
void* out, const unsigned outlen
);
#ifdef __cplusplus

View File

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

View File

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