Skip to content

Commit

Permalink
Merge pull request #10 from D7EAD/D7EAD-pmajor-1
Browse files Browse the repository at this point in the history
HMAC implementation update
  • Loading branch information
D7EAD authored Dec 8, 2022
2 parents aa531e5 + c3b4525 commit 239ca5e
Show file tree
Hide file tree
Showing 23 changed files with 2,667 additions and 397 deletions.
63 changes: 14 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@
Hash++ is a C++17 header-only library that allows a user to retrieve multiple types of hashes from data, files, and files in nested directories. The original purpose behind this library was to create a header-file only implementation of multiple different hash algorithms. You can find a list of the <i>currently</i> supported hash algorithms below.
<br>
<h1><i>Supported Algorithms</i></h1>
<ul>
<li>MD5</li>
<li>MD4</li>
<li>MD2</li>
<li>SHA-1</li>
<li>SHA2-224</li>
<li>SHA2-256</li>
<li>SHA2-384</li>
<li>SHA2-512</li>
<li>SHA2-512/224</li>
<li>SHA2-512/256</li>
</ul>

| Algorithm | HMAC Support? |
| :-------------: | :-----------------: |
| MD5 | :heavy_check_mark: |
| MD4 | :heavy_check_mark: |
| MD2 | :heavy_check_mark: |
| SHA1 | :heavy_check_mark: |
| SHA2-224 | :heavy_check_mark: |
| SHA2-256 | :heavy_check_mark: |
| SHA2-384 | :heavy_check_mark: |
| SHA2-512 | :heavy_check_mark: |
| SHA2-512/224 | :heavy_check_mark: |
| SHA2-512/256 | :heavy_check_mark: |

Hash++ also aims to be a suitable alternative to heavier, statically and dynamically-linked libraries such as OpenSSL and Crypto++. I created it keeping in mind the mindset of a programmer who simply wants a header-only file that lets them easily and comfortably <i>"just hash sh*t."</i> Does it really have to be that difficult?

Expand Down Expand Up @@ -93,40 +94,4 @@ No, it doesn't.
```

<h1><i>Using Hash++</i></h1>
My original design idea behind Hash++ was for it to be <b>simple</b>. This has remained unchanged.
<br><br>
Below you can find the signatures of the <i>only</i> functions necessary to accomplish retrieving hashes from both single or multiple sets of data, files, and files in nested directories. All functions are located in the <code>hashpp</code> namespace under class <code>get</code> (<code>hashpp::get</code>).
<br><br>
You can find examples of Hash++ in use in the <a href="/examples">/examples</a> and <a href="/tests">/tests</a> directories.
<br>
<h3><code>getHash</code></h3>
Retrieve a single hash from a single piece of data.

```cpp
// function to return a resulting hash from selected ALGORITHM and passed data
static hashpp::hash getHash(hashpp::ALGORITHMS algorithm, const std::string& data)
```
<h3><code>getHashes</code></h3>
Retrieve a collection of hashes from multiple pieces of data.
```cpp
// function to return a collection of resulting hashes from selected ALGORITHMS and passed data
static hashpp::hashCollection getHashes(const std::vector<std::pair<hashpp::ALGORITHMS, std::vector<std::string>>>& algorithmDataPairs)
```

<h3><code>getFileHash</code></h3>
Retrieve a single hash from a single file.

```cpp
// function to return a resulting hash from selected ALGORITHM and passed file
static hashpp::hash getFileHash(hashpp::ALGORITHMS algorithm, const std::string& path)
```
<h3><code>getFilesHashes</code></h3>
Retrieve a collection of hashes from multiple files or files in nested directories.
```cpp
// function to return a collection of resulting hashes from selected ALGORITHMS and passed files (with recursive directory support)
static hashpp::hashCollection getFilesHashes(const std::vector<std::pair<hashpp::ALGORITHMS, std::vector<std::string>>>& algorithmPathPairs)
```
You can find detailed documentation in the <a href="/documentation">/documentation</a> directory.
39 changes: 39 additions & 0 deletions documentation/HMACs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<h1>Keyed-Hash Message Authentication Codes (HMACs)</h1>
<p>While they may sound considerably more complicated, HMACs aren't too different from cryptographic hashes at the end of the day. HMACs are keyed hashes of data meaning, simply, that an HMAC is used to generate a unique hash digest of data when that data is paired with another specific piece of data--a key.</p>

<p>Take, for instance, the simple example hash function of <code>H(x) = y</code> where <code>H</code> is our hash function, <code>x</code> is our input data, and <code>y</code> is our output hash digest. The output digest depends on two things:</p>

- The hash function in use.
- The input supplied to said function.

<p>Now, take, for instance, the following naive keyed hash algorithm *<code>H(x + k) = y</code> where <code>H</code> is our hash function, <code>x</code> is our input data, <code>k</code> is our key data, and <code>y</code> is our output hash digest. The output digest <b>now</b> depends on three things:</p>

- The hash function in use.
- The input supplied to said function.
- The key data.

<p>Hash functions provide collision-resistance whereas an HMAC provides both collision-resistance and <i>unforgeability</i>. Due to this provided element of unforgeability, HMACs are used in combination with hash algorithms to prove not only that data is unmodified, but that whoever calculated the hash for said data did so with the correct key--otherwise the incorrect HMAC would result.</p>

<p>Simply put, a hash allows for <b>verification of the authenticity of data</b> whereas an HMAC allows for <b>verification of both the authenticity of data and the originator of said data</b>.</p>

<p><i>*Keep in mind that HMACs do not simply operate as a hash function <code>H</code> applied on a key <code>k</code> appended to data <code>x</code>. How HMACs are calculated is a bit more nuanced. Hash algorithms are not HMACs and vice-versa--the HMAC mechanism works atop existing hash algorithms. You can read more about the RFC specification <a href="https://www.rfc-editor.org/rfc/rfc2104">here</a>.</i></p>

<br>
<h1>Using Hash++</h1>
Hash++ offers a simple set of methods to generate one or multiple HMACs given data and an associated key. You can find the signatures for the functions below.

```
static hashpp::hash getHMAC(hashpp::ALGORITHMS algorithm, const std::string& key, const std::string& data;
static hashpp::hashCollection getHMACs(const HMAC_DataContainer& keyDataSet);
static hashpp::hashCollection getHMACs(const std::vector<HMAC_DataContainer>& keyDataSets);
static hashpp::hashCollection getHMACs(const std::initializer_list<HMAC_DataContainer>& keyDataSets);
template <class... _Ts, ...> static hashpp::hashCollection getHMACs(hashpp::ALGORITHMS algorithm, const std::string& key, const _Ts&... data);
```

<br>
You can easily generate an HMAC for a single piece of data using Hash++. See below for an example.
https://github.com/D7EAD/HashPlusPlus/blob/0ac434933e4d54b584b810d863a9f1a4a4f5f7b4/documentation/HMACs/getHMAC/getHMAC_usage.cpp#L10-L29

<br>
In order to generate several HMACs for several pieces of data, we can use a <code>Container</code> alias <code>HMAC_DataContainer</code> (if you have not read about the Container class used by Hash++, please see the documentation for <b>Hashing</b>). See below for an example.
https://github.com/D7EAD/HashPlusPlus/blob/fc5edb76cd829794a3fb34c416df7431653044e0/documentation/HMACs/getHMACs/getHMACs_usage.cpp#L14-L42
29 changes: 29 additions & 0 deletions documentation/HMACs/getHMAC/getHMAC_usage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
Basic usage of Hash++ getHMAC method.
This file shows basic usage of the above described method
and its overloads, as well as how data can be extracted
from its returned object.
*/

#include "hashpp.h"

using namespace hashpp;

int main() {
// data we want to get HMAC of
std::string dataToHash = "Hello World!";

// key to use for HMAC
std::string key = "secret";

// get HMAC of dataToHash using SHA-256
auto hmac = get::getHMAC(ALGORITHMS::SHA2_256, key, dataToHash);

// print out the hash
std::cout << "HMAC: " << hmac << std::endl;

// output:
// 6fa7b4dea28ee348df10f9bb595ad985ff150a4adfd6131cca677d9acee07dc6
}
42 changes: 42 additions & 0 deletions documentation/HMACs/getHMACs/getHMACs_usage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
Basic usage of Hash++ getHMACs method.
This file shows basic usage of the above described method
and its overloads, as well as how data can be extracted
from its returned object.
*/

#include "hashpp.h"

using namespace hashpp;

int main() {
// create HMAC_DataContainer object
// to store algorithm to use, key,
// and data to HMAC
HMAC_DataContainer hmac_container;

// set algorithm to use
hmac_container.setAlgorithm(ALGORITHMS::SHA2_256);

// set key to use
hmac_container.setKey("secretKey");

// set data to HMAC
hmac_container.setData("dataToHMAC1", "dataToHMAC2", "dataToHMAC3");

// calculate the HMACs for all data in container
// using key and algorithm specified
hashCollection hmacs = get::getHMACs(hmac_container);

// parse and print each HMAC
for (auto& hmac : hmacs["SHA2-256"]) {
std::cout << hmac << std::endl;
}

// output:
// f0dfad2b51176704f8fff07e2c6063417b1d361465b4f9eaacf9b756037bb815
// bf912338f4c9d21eff351d085a26b9723eb0da6582039d18a003046c3ae3fbef
// abba2bd3400c1b03322fac45539462241ca6ae14a81d58e1db017a9bcb3947b2
}
11 changes: 11 additions & 0 deletions documentation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<h1>Documentation</h1>
<b>Hash++</b> is a modern C++17 header-only library that provides developers simple means of retrieving cryptographic hashes and keyed-hashed message authentication codes (HMACs) from the algorithm(s) of their choice. The library was developed with the goal of appealing to one particular type of developer--one who does not want to use larger, heavier, or more confusing libraries with unnecessary features to simply hash data.
<br><br>
In the directories listed below, you can find explanations of concepts found within the implementations of the library and example usage of features found within <b~>Hash++</b>.

- <a href="/hashing">Hashing Documentation</a>
- Covers basic hashing concepts and how to generate them using the library.
- <a href="/HMACs">HMAC Documentation</a>
- Covers basic HMAC concepts and how to generate them using the library.
- <a href="/file_hashing">File-hashing Documentation</a>
- Covers how to hash files using the library.
17 changes: 17 additions & 0 deletions documentation/file_hashing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<h1>Using Hash++ to Generate File Hashes</h1>
Much like how hashes can be generated using generic data, Hash++ provides functions for developers to find hashes for files and files in nested directories. The signatures for the methods can be found below.

```
static hashpp::hash getFileHash(hashpp::ALGORITHMS algorithm, const std::string& path);
static hashpp::hashCollection getFilesHashes(const FilePathsContainer& filePathSet);
static hashpp::hashCollection getFilesHashes(const std::vector<FilePathsContainer>& filePathSets);
static hashpp::hashCollection getFilesHashes(const std::initializer_list<FilePathsContainer>& filePathSets);
```

<br>
Some file hashing functions, much like some other components of the library, make use of their own <code>Container</code> alias <code>FilePathsContainer</code> (if you have not read about the <code>Container</code> class used by Hash++, please see the documentation for <b>Hashing</b>). You can find an example of a single file being hashed below.
https://github.com/D7EAD/HashPlusPlus/blob/ba418167da59826cda2a18990a90cf332d75308e/documentation/file_hashing/getFileHash/getFileHash_usage.cpp#L10-L29

<br>
If you're in the business of hashing multiple files at once, you can find an example of such a use below.
https://github.com/D7EAD/HashPlusPlus/blob/c007af7d81bdf054a389314ad1d7bbb6d0757262/documentation/file_hashing/getFilesHashes/getFilesHashes_usage.cpp#L14-L35
29 changes: 29 additions & 0 deletions documentation/file_hashing/getFileHash/getFileHash_usage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
Basic usage of Hash++ getFileHash method.
This file shows basic usage of the above described method
and its overloads, as well as how data can be extracted
from its returned object.
*/

#include "hashpp.h"

using namespace hashpp;

int main() {
// path to file we want to hash (test.txt)
std::string pathToFile = "N:/source/test.txt";

// store the resulting hash object of the file using SHA-256
auto hash = get::getFileHash(ALGORITHMS::SHA2_256, pathToFile);

// print the hash digest
std::cout << hash << std::endl;

// or we can be more specific...
std::cout << hash.getString() << std::endl;

// output:
// 4de0d727216e14760010efdb0cccf577853d7da4e122a507b422148940f4aa34
}
1 change: 1 addition & 0 deletions documentation/file_hashing/getFileHash/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A hash a day keeps the doctor away.
35 changes: 35 additions & 0 deletions documentation/file_hashing/getFilesHashes/getFilesHashes_usage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
Basic usage of Hash++ getFileHashes method.
This file shows basic usage of the above described method
and its overloads, as well as how data can be extracted
from its returned object.
*/

#include "hashpp.h"

using namespace hashpp;

int main() {
// create a FilePathsContainer object
FilePathsContainer path_cont1;

// set its algorithm and some paths
path_cont1.setAlgorithm(ALGORITHMS::SHA2_256);
path_cont1.setData("N:/source/test.txt", "N:/source/test2.txt", "N:/source/test3.txt");

// get the hashes of each file via get::getFilesHashes
// and store them in a hashCollection object
hashCollection hashes = get::getFilesHashes(path_cont1);

// parse and print the hashes
for (auto& hash : hashes["SHA2-256"]) {
std::cout << hash << std::endl;
}

// output:
// 4de0d727216e14760010efdb0cccf577853d7da4e122a507b422148940f4aa34
// 7c88d6bc28e9bd6660b96cfa3b69cdbaaaf0187047267106842841357ac03bd8
// 44d25e664ce6d6e82beb7a14fe312d7c09c5dc107668a6d40449bc24938e5c73
}
1 change: 1 addition & 0 deletions documentation/file_hashing/getFilesHashes/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A hash a day keeps the doctor away.
1 change: 1 addition & 0 deletions documentation/file_hashing/getFilesHashes/test2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Too many hashes may lead to gastrointestinal issues.
1 change: 1 addition & 0 deletions documentation/file_hashing/getFilesHashes/test3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Passwords should not be stored in plaintext.
47 changes: 47 additions & 0 deletions documentation/hashing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<h1>Hashing</h1>
Hashing, in simple terms, is the cryptographic process of assigning a unique fingerprint to data such that no other data will produce the same fingerprint as another piece of data.
<br><br>
In mathematical terms, hashing is the functional process of mapping any arbitrary data <code>X</code> to a fixed-size, unique, and seemingly nonsensical value <code>D</code>. Hashing algorithms are one-way functions such that, given an input <code>x</code> to some hash function <code>H</code>, it is facile to compute the output hash digest <code>D</code>; however, given only some hash function <code>H</code> and an associated output digest <code>D</code>, it is infeasible to compute the original input data <code>x</code>.
<br><br>
Simply, a one-way function <code>H(x) = D</code> is one such function that satisfies all constraints such that...

- <code>D</code> is easily computed given <code>x</code>.
- <code>H</code>'s output range is known.
- Given only output <code>D</code> and function <code>H</code>, <code>x</code> is infeasibly computed such that <code>H(x) = D</code>.

Given this inherent infeasibility of recovering initial input data to a given hash function, they are useful for a number of security purposes such as:

- Message and file integrity verification.
- Password verification.
- Signature/identifier generation and verification.
- Key Derivation Functions (KDFs).
- Proof-of-Work.
- Blockchain Technology.
- Public-Key Cryptography.
- CSPRNGs.

<h1>Using Hash++</h1>
Hash++ offers a simple set of methods to take advantage of the cryptographic-magic described above. You can generate simple hashes using the functions described below.

```
static hashpp::hash getHash(hashpp::ALGORITHMS algorithm, const std::string& data);
static hashpp::hashCollection getHashes(const DataContainer& dataSet)
static hashpp::hashCollection getHashes(const std::vector<DataContainer>& dataSets);
static hashpp::hashCollection getHashes(const std::initializer_list<DataContainer>& dataSets);
template <class... _Ts, ...> static hashpp::hashCollection getHashes(hashpp::ALGORITHMS algorithm, const _Ts&... data);
```
<br>
Some function overloads found in Hash++ make use of a container class <code>Container</code> with aliases <code>DataContainer</code>, <code>HMAC_DataContainer</code>, and <code>FilePathsContainer</code>. This class allows developers to contain all data associated with a particular hash algorithm in one name, making it easier to pass several of them, if desired, and, in turn, several sets of data to hash. You can find the detailed implementation of the class below.
https://github.com/D7EAD/HashPlusPlus/blob/8bf4d2971f5fab4ad0df75ea6f71a012841c504e/documentation/hashing/container/container.cpp#L1-L100

<br>
While the class may seem daunting at first, below you can find examples of its use and instantiation, as well as how it can be passed to certain function overloads.
https://github.com/D7EAD/HashPlusPlus/blob/8bf4d2971f5fab4ad0df75ea6f71a012841c504e/documentation/hashing/container/container_use.cpp#L14-L37

<br>
As you can see above, when given a properly created <code>Container</code>, the library function <code>getHashes(...)</code> can easily calculate and retrieve the hash digests of the passed data contained in the container(s). The function <code>getHashes(...)</code> itself, though, returns a <code>hashCollection</code> object. This object can be parsed quite easily:
https://github.com/D7EAD/HashPlusPlus/blob/b7fbc10fc627ab21c39a51698882641e1073c78e/documentation/hashing/getHashes/getHashes_usage.cpp#L14-L29

<br>
Parsing <code>hashCollection</code> objects is great and all when you want to get the hashes of several pieces of data. However, what if you want to get the hash of a single piece of data? To do this, we make use of the library function <code>getHash</code> which returns a <code>hash</code> object.
https://github.com/D7EAD/HashPlusPlus/blob/ffca4d776939f950dbce37d3477bd3e164cc7ba9/documentation/hashing/getHash/getHash_usage.cpp#L14-L26
Loading

0 comments on commit 239ca5e

Please sign in to comment.