Skip to content

Commit

Permalink
Add HMAC support to all of the hash algorithms
Browse files Browse the repository at this point in the history
  • Loading branch information
rweather committed Mar 24, 2015
1 parent e0803c0 commit fd38b7e
Show file tree
Hide file tree
Showing 25 changed files with 845 additions and 13 deletions.
2 changes: 1 addition & 1 deletion doc/crypto.dox
Expand Up @@ -29,7 +29,7 @@
\li Block ciphers: AES128, AES192, AES256
\li Block cipher modes: CTR, CFB, CBC, OFB
\li Stream ciphers: ChaCha
\li Hash algorithms: SHA1, SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b
\li Hash algorithms: SHA1, SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b (regular and HMAC modes)
\li Public key algorithms: Curve25519
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource, RingOscillatorNoiseSource

Expand Down
2 changes: 1 addition & 1 deletion doc/mainpage.dox
Expand Up @@ -93,7 +93,7 @@ realtime clock and the LCD library to implement an alarm clock.
\li Block ciphers: AES128, AES192, AES256
\li Block cipher modes: CTR, CFB, CBC, OFB
\li Stream ciphers: ChaCha
\li Hash algorithms: SHA1, SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b
\li Hash algorithms: SHA1, SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b (regular and HMAC modes)
\li Public key algorithms: Curve25519
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource, RingOscillatorNoiseSource

Expand Down
19 changes: 19 additions & 0 deletions libraries/Crypto/BLAKE2b.cpp
Expand Up @@ -162,6 +162,25 @@ void BLAKE2b::clear()
reset();
}

void BLAKE2b::resetHMAC(const void *key, size_t keyLen)
{
formatHMACKey(state.m, key, keyLen, 0x36);
state.lengthLow += 128;
processChunk(0);
}

void BLAKE2b::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
uint8_t temp[64];
finalize(temp, sizeof(temp));
formatHMACKey(state.m, key, keyLen, 0x5C);
state.lengthLow += 128;
processChunk(0);
update(temp, sizeof(temp));
finalize(hash, hashLen);
clean(temp);
}

// Permutation on the message input state for BLAKE2b.
static const uint8_t sigma[12][16] PROGMEM = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
Expand Down
3 changes: 3 additions & 0 deletions libraries/Crypto/BLAKE2b.h
Expand Up @@ -41,6 +41,9 @@ class BLAKE2b : public Hash

void clear();

void resetHMAC(const void *key, size_t keyLen);
void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);

private:
struct {
uint64_t h[8];
Expand Down
19 changes: 19 additions & 0 deletions libraries/Crypto/BLAKE2s.cpp
Expand Up @@ -157,6 +157,25 @@ void BLAKE2s::clear()
reset();
}

void BLAKE2s::resetHMAC(const void *key, size_t keyLen)
{
formatHMACKey(state.m, key, keyLen, 0x36);
state.length += 64;
processChunk(0);
}

void BLAKE2s::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
uint8_t temp[32];
finalize(temp, sizeof(temp));
formatHMACKey(state.m, key, keyLen, 0x5C);
state.length += 64;
processChunk(0);
update(temp, sizeof(temp));
finalize(hash, hashLen);
clean(temp);
}

// Permutation on the message input state for BLAKE2s.
static const uint8_t sigma[10][16] PROGMEM = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
Expand Down
3 changes: 3 additions & 0 deletions libraries/Crypto/BLAKE2s.h
Expand Up @@ -41,6 +41,9 @@ class BLAKE2s : public Hash

void clear();

void resetHMAC(const void *key, size_t keyLen);
void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);

private:
struct {
uint32_t h[8];
Expand Down
76 changes: 74 additions & 2 deletions libraries/Crypto/Hash.cpp
Expand Up @@ -21,6 +21,7 @@
*/

#include "Hash.h"
#include <string.h>

/**
* \class Hash Hash.h <Hash.h>
Expand Down Expand Up @@ -66,7 +67,7 @@ Hash::~Hash()
* \fn void Hash::reset()
* \brief Resets the hash ready for a new hashing process.
*
* \sa update(), finalize()
* \sa update(), finalize(), resetHMAC()
*/

/**
Expand Down Expand Up @@ -96,7 +97,7 @@ Hash::~Hash()
* If finalize() is called again, then the returned \a hash value is
* undefined. Call reset() first to start a new hashing process.
*
* \sa reset(), update()
* \sa reset(), update(), finalizeHMAC()
*/

/**
Expand All @@ -106,3 +107,74 @@ Hash::~Hash()
*
* \sa reset()
*/

/**
* \fn void Hash::resetHMAC(const void *key, size_t keyLen)
* \brief Resets the hash ready for a new HMAC hashing process.
*
* \param key Points to the HMAC key for the hashing process.
* \param keyLen Size of the HMAC \a key in bytes.
*
* The following example computes a HMAC over a series of data blocks
* with a specific key:
*
* \code
* hash.resetHMAC(key, sizeof(key));
* hash.update(data1, sizeof(data1));
* hash.update(data2, sizeof(data2));
* ...
* hash.update(dataN, sizeof(dataN));
* hash.finalizeHMAC(key, sizeof(key), hmac, sizeof(hmac));
* \endcode
*
* The same key must be passed to both resetHMAC() and finalizeHMAC().
*
* \sa finalizeHMAC(), reset()
*/

/**
* \fn void Hash::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
* \brief Finalizes the HMAC hashing process and returns the hash.
*
* \param key Points to the HMAC key for the hashing process. The contents
* of this array must be identical to the value passed to resetHMAC().
* \param keyLen Size of the HMAC \a key in bytes.
* \param hash The buffer to return the hash value in.
* \param hashLen The length of the \a hash buffer, normally hashSize().
*
* \sa resetHMAC(), finalize()
*/

/**
* \brief Formats a HMAC key into a block.
*
* \param block The block to format the key into. Must be at least
* blockSize() bytes in length.
* \param key Points to the HMAC key for the hashing process.
* \param len Length of the HMAC \a key in bytes.
* \param pad Inner (0x36) or outer (0x5C) padding value to XOR with
* the formatted HMAC key.
*
* This function is intended to help subclasses implement resetHMAC() and
* finalizeHMAC() by directly formatting the HMAC key into the subclass's
* internal block buffer and resetting the hash.
*/
void Hash::formatHMACKey(void *block, const void *key, size_t len, uint8_t pad)
{
size_t size = blockSize();
reset();
if (len <= size) {
memcpy(block, key, len);
} else {
update(key, len);
len = hashSize();
finalize(block, len);
reset();
}
memset(block + len, pad, size - len);
uint8_t *b = (uint8_t *)block;
while (len > 0) {
*b++ ^= pad;
--len;
}
}
6 changes: 6 additions & 0 deletions libraries/Crypto/Hash.h
Expand Up @@ -40,6 +40,12 @@ class Hash
virtual void finalize(void *hash, size_t len) = 0;

virtual void clear() = 0;

virtual void resetHMAC(const void *key, size_t keyLen) = 0;
virtual void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen) = 0;

protected:
void formatHMACKey(void *block, const void *key, size_t len, uint8_t pad);
};

#endif
35 changes: 35 additions & 0 deletions libraries/Crypto/KeccakCore.cpp
Expand Up @@ -247,6 +247,41 @@ void KeccakCore::clear()
clean(state);
}

/**
* \brief Sets a HMAC key for a Keccak-based hash algorithm.
*
* \param key Points to the HMAC key for the hashing process.
* \param len Length of the HMAC \a key in bytes.
* \param pad Inner (0x36) or outer (0x5C) padding value to XOR with
* the formatted HMAC key.
* \param hashSize The size of the output from the hash algorithm.
*
* This function is intended to help classes implement Hash::resetHMAC() and
* Hash::finalizeHMAC() by directly formatting the HMAC key into the
* internal block buffer and resetting the hash.
*/
void KeccakCore::setHMACKey(const void *key, size_t len, uint8_t pad, size_t hashSize)
{
uint8_t *b = (uint8_t *)state.B;
size_t size = blockSize();
reset();
if (len <= size) {
memcpy(b, key, len);
} else {
update(key, len);
this->pad(0x06);
extract(b, hashSize);
len = hashSize;
reset();
}
memset(b + len, pad, size - len);
while (len > 0) {
*b++ ^= pad;
--len;
}
update(state.B, size);
}

/**
* \brief Transform the state with the KECCAK-p sponge function with b = 1600.
*/
Expand Down
2 changes: 2 additions & 0 deletions libraries/Crypto/KeccakCore.h
Expand Up @@ -46,6 +46,8 @@ class KeccakCore

void clear();

void setHMACKey(const void *key, size_t len, uint8_t pad, size_t hashSize);

private:
struct {
uint64_t A[5][5];
Expand Down
19 changes: 19 additions & 0 deletions libraries/Crypto/SHA1.cpp
Expand Up @@ -131,6 +131,25 @@ void SHA1::clear()
reset();
}

void SHA1::resetHMAC(const void *key, size_t keyLen)
{
formatHMACKey(state.w, key, keyLen, 0x36);
state.length += 64 * 8;
processChunk();
}

void SHA1::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
uint8_t temp[20];
finalize(temp, sizeof(temp));
formatHMACKey(state.w, key, keyLen, 0x5C);
state.length += 64 * 8;
processChunk();
update(temp, sizeof(temp));
finalize(hash, hashLen);
clean(temp);
}

/**
* \brief Processes a single 512-bit chunk with the core SHA-1 algorithm.
*
Expand Down
3 changes: 3 additions & 0 deletions libraries/Crypto/SHA1.h
Expand Up @@ -40,6 +40,9 @@ class SHA1 : public Hash

void clear();

void resetHMAC(const void *key, size_t keyLen);
void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);

private:
struct {
uint32_t h[5];
Expand Down
19 changes: 19 additions & 0 deletions libraries/Crypto/SHA256.cpp
Expand Up @@ -136,6 +136,25 @@ void SHA256::clear()
reset();
}

void SHA256::resetHMAC(const void *key, size_t keyLen)
{
formatHMACKey(state.w, key, keyLen, 0x36);
state.length += 64 * 8;
processChunk();
}

void SHA256::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
uint8_t temp[32];
finalize(temp, sizeof(temp));
formatHMACKey(state.w, key, keyLen, 0x5C);
state.length += 64 * 8;
processChunk();
update(temp, sizeof(temp));
finalize(hash, hashLen);
clean(temp);
}

/**
* \brief Processes a single 512-bit chunk with the core SHA-256 algorithm.
*
Expand Down
3 changes: 3 additions & 0 deletions libraries/Crypto/SHA256.h
Expand Up @@ -40,6 +40,9 @@ class SHA256 : public Hash

void clear();

void resetHMAC(const void *key, size_t keyLen);
void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);

private:
struct {
uint32_t h[8];
Expand Down
31 changes: 31 additions & 0 deletions libraries/Crypto/SHA3.cpp
Expand Up @@ -21,6 +21,7 @@
*/

#include "SHA3.h"
#include "Crypto.h"

/**
* \class SHA3_256 SHA3.h <SHA3.h>
Expand Down Expand Up @@ -79,6 +80,21 @@ void SHA3_256::clear()
core.clear();
}

void SHA3_256::resetHMAC(const void *key, size_t keyLen)
{
core.setHMACKey(key, keyLen, 0x36, 32);
}

void SHA3_256::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
uint8_t temp[32];
finalize(temp, sizeof(temp));
core.setHMACKey(key, keyLen, 0x5C, 32);
core.update(temp, sizeof(temp));
finalize(hash, hashLen);
clean(temp);
}

/**
* \class SHA3_512 SHA3.h <SHA3.h>
* \brief SHA3-512 hash algorithm.
Expand Down Expand Up @@ -135,3 +151,18 @@ void SHA3_512::clear()
{
core.clear();
}

void SHA3_512::resetHMAC(const void *key, size_t keyLen)
{
core.setHMACKey(key, keyLen, 0x36, 64);
}

void SHA3_512::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
uint8_t temp[64];
finalize(temp, sizeof(temp));
core.setHMACKey(key, keyLen, 0x5C, 64);
core.update(temp, sizeof(temp));
finalize(hash, hashLen);
clean(temp);
}
6 changes: 6 additions & 0 deletions libraries/Crypto/SHA3.h
Expand Up @@ -41,6 +41,9 @@ class SHA3_256 : public Hash

void clear();

void resetHMAC(const void *key, size_t keyLen);
void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);

private:
KeccakCore core;
};
Expand All @@ -60,6 +63,9 @@ class SHA3_512 : public Hash

void clear();

void resetHMAC(const void *key, size_t keyLen);
void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);

private:
KeccakCore core;
};
Expand Down

0 comments on commit fd38b7e

Please sign in to comment.