Clean up code, add examples
This commit is contained in:
parent
76ac6669de
commit
79a57d2a85
52
README.md
52
README.md
|
@ -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;
|
||||
}
|
||||
```
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -1,27 +1,28 @@
|
|||
/*
|
||||
hmac_sha256.c
|
||||
Originally written by https://github.com/h5p9sl
|
||||
*/
|
||||
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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// IMPORTS
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "WjCryptLib_Sha256.h"
|
||||
#include "sha256.h"
|
||||
#include <memory.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -26,7 +26,6 @@ typedef struct
|
|||
} Sha256Context;
|
||||
|
||||
#define SHA256_HASH_SIZE ( 256 / 8 )
|
||||
#define SHA256_BLOCK_SIZE ( 512 / 8 )
|
||||
|
||||
typedef struct
|
||||
{
|
Loading…
Reference in New Issue