Skip to content

Commit

Permalink
Keyed hashing for BLAKE2 according to RFC7693
Browse files Browse the repository at this point in the history
  • Loading branch information
rweather committed Mar 23, 2016
1 parent 72715b1 commit c8d7c31
Show file tree
Hide file tree
Showing 7 changed files with 421 additions and 16 deletions.
26 changes: 16 additions & 10 deletions doc/crypto.dox
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ BLAKE2s and BLAKE2b are variations on the ChaCha stream cipher, designed for
hashing, with 256-bit and 512-bit hash outputs respectively. They are
intended as high performance replacements for SHA256 and SHA512 for when
speed is critical but exact bit-compatibility of hash values is not.
BLAKE2s and BLAKE2b support regular hashing, BLAKE2 keyed hashing,
and HMAC modes.

\section crypto_other Examples and other topics

Expand All @@ -71,7 +73,7 @@ All figures are for the Arduino Uno running at 16 MHz. Figures for the
Ardunino Mega 2560 running at 16 MHz are similar:

<table>
<tr><td>Encryption Algorithm</td><td align="right">Encryption (per byte)</td><td align="right">Decryption (per byte)</td><td>Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>Encryption Algorithm</td><td align="right">Encryption (per byte)</td><td align="right">Decryption (per byte)</td><td align="right">Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>AES128 (ECB mode)</td><td align="right">33.28us</td><td align="right">63.18us</td><td align="right">160.00us</td><td align="right">181</td></tr>
<tr><td>AES192 (ECB mode)</td><td align="right">39.94us</td><td align="right">76.48us</td><td align="right">166.54us</td><td align="right">213</td></tr>
<tr><td>AES256 (ECB mode)</td><td align="right">46.61us</td><td align="right">89.78us</td><td align="right">227.97us</td><td align="right">245</td></tr>
Expand All @@ -88,7 +90,7 @@ Ardunino Mega 2560 running at 16 MHz are similar:
<tr><td>SpeckTiny (192-bit key, ECB mode)</td><td align="right">36.56us</td><td align="right"> </td><td align="right">13.62us</td><td align="right">35</td></tr>
<tr><td>SpeckTiny (256-bit key, ECB mode)</td><td align="right">37.87us</td><td align="right"> </td><td align="right">16.89us</td><td align="right">35</td></tr>
<tr><td colspan="5"> </td></tr>
<tr><td>AEAD Algorithm</td><td align="right">Encryption (per byte)</td><td align="right">Decryption (per byte)</td><td>Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>AEAD Algorithm</td><td align="right">Encryption (per byte)</td><td align="right">Decryption (per byte)</td><td align="right">Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>ChaChaPoly</td><td align="right">41.20us</td><td align="right">41.19us</td><td align="right">902.36us</td><td align="right">221</td></tr>
<tr><td>GCM&lt;AES128&gt;</td><td align="right">109.71us</td><td align="right">109.26us</td><td align="right">1265.69us</td><td align="right">284</td></tr>
<tr><td>GCM&lt;AES192&gt;</td><td align="right">116.38us</td><td align="right">115.92us</td><td align="right">1485.56us</td><td align="right">316</td></tr>
Expand All @@ -106,11 +108,13 @@ Ardunino Mega 2560 running at 16 MHz are similar:
<tr><td>SHA3_256</td><td align="right">60.69us</td><td align="right">8180.24us</td><td align="right"> </td><td align="right">205</td></tr>
<tr><td>SHA3_512</td><td align="right">113.88us</td><td align="right">8196.34us</td><td align="right"> </td><td align="right">205</td></tr>
<tr><td>BLAKE2s</td><td align="right">20.65us</td><td align="right">1335.25us</td><td align="right"> </td><td align="right">107</td></tr>
<tr><td>BLAKE2b</td><td align="right">65.22us</td><td align="right">8375.36us</td><td align="right"> </td><td align="right">211</td></tr>
<tr><td>BLAKE2b</td><td align="right">65.22us</td><td align="right">8375.34us</td><td align="right"> </td><td align="right">211</td></tr>
<tr><td colspan="5"> </td></tr>
<tr><td>Authentication Algorithm</td><td align="right">Hashing (per byte)</td><td align="right">Finalization</td><td>Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>Authentication Algorithm</td><td align="right">Hashing (per byte)</td><td align="right">Finalization</td><td align="right">Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>SHA256 (HMAC mode)</td><td align="right">43.85us</td><td align="right">8552.61us</td><td align="right">2836.49us</td><td align="right">107</td></tr>
<tr><td>BLAKE2s (Keyed mode)</td><td align="right">20.65us</td><td align="right">1335.25us</td><td align="right">1339.51us</td><td align="right">107</td></tr>
<tr><td>BLAKE2s (HMAC mode)</td><td align="right">20.65us</td><td align="right">4055.56us</td><td align="right">1350.00us</td><td align="right">107</td></tr>
<tr><td>BLAKE2b (Keyed mode)</td><td align="right">65.22us</td><td align="right">8375.34us</td><td align="right">8357.25us</td><td align="right">211</td></tr>
<tr><td>Poly1305</td><td align="right">26.26us</td><td align="right">489.11us</td><td align="right">17.06us</td><td align="right">53</td></tr>
<tr><td>GHASH</td><td align="right">74.59us</td><td align="right">15.91us</td><td align="right">14.79us</td><td align="right">33</td></tr>
<tr><td colspan="5"> </td></tr>
Expand All @@ -136,7 +140,7 @@ maximum is shown above.
All figures are for the Arduino Due running at 84 MHz:

<table>
<tr><td>Encryption Algorithm</td><td align="right">Encryption (per byte)</td><td align="right">Decryption (per byte)</td><td>Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>Encryption Algorithm</td><td align="right">Encryption (per byte)</td><td align="right">Decryption (per byte)</td><td align="right">Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>AES128 (ECB mode)</td><td align="right">5.71us</td><td align="right">10.41us</td><td align="right">34.73us</td><td align="right">188</td></tr>
<tr><td>AES192 (ECB mode)</td><td align="right">6.87us</td><td align="right">12.57us</td><td align="right">36.51us</td><td align="right">220</td></tr>
<tr><td>AES256 (ECB mode)</td><td align="right">8.04us</td><td align="right">14.72</td><td align="right">49.96us</td><td align="right">252</td></tr>
Expand All @@ -153,7 +157,7 @@ All figures are for the Arduino Due running at 84 MHz:
<tr><td>SpeckTiny (192-bit key, ECB mode)</td><td align="right">2.81us</td><td align="right"> </td><td align="right">1.54us</td><td align="right">48</td></tr>
<tr><td>SpeckTiny (256-bit key, ECB mode)</td><td align="right">2.90us</td><td align="right"> </td><td align="right">1.83us</td><td align="right">48</td></tr>
<tr><td colspan="5"> </td></tr>
<tr><td>AEAD Algorithm</td><td align="right">Encryption (per byte)</td><td align="right">Decryption (per byte)</td><td>Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>AEAD Algorithm</td><td align="right">Encryption (per byte)</td><td align="right">Decryption (per byte)</td><td align="right">Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>ChaChaPoly</td><td align="right">1.71us</td><td align="right">1.71us</td><td align="right">45.08us</td><td align="right">240</td></tr>
<tr><td>GCM&lt;AES128&gt;</td><td align="right">10.90us</td><td align="right">10.90us</td><td align="right">248.83us</td><td align="right">312</td></tr>
<tr><td>GCM&lt;AES192&gt;</td><td align="right">12.30us</td><td align="right">12.31us</td><td align="right">296.83us</td><td align="right">344</td></tr>
Expand All @@ -170,12 +174,14 @@ All figures are for the Arduino Due running at 84 MHz:
<tr><td>SHA512</td><td align="right">2.87us</td><td align="right">370.37us</td><td align="right"> </td><td align="right">224</td></tr>
<tr><td>SHA3_256</td><td align="right">5.64us</td><td align="right">735.29us</td><td align="right"> </td><td align="right">224</td></tr>
<tr><td>SHA3_512</td><td align="right">10.42us</td><td align="right">735.49us</td><td align="right"> </td><td align="right">224</td></tr>
<tr><td>BLAKE2s</td><td align="right">0.72us</td><td align="right">48.24us</td><td align="right"> </td><td align="right">120</td></tr>
<tr><td>BLAKE2b</td><td align="right">1.29us</td><td align="right">165.28us</td><td align="right"> </td><td align="right">224</td></tr>
<tr><td>BLAKE2s</td><td align="right">0.80us</td><td align="right">53.39us</td><td align="right"> </td><td align="right">120</td></tr>
<tr><td>BLAKE2b</td><td align="right">1.28us</td><td align="right">164.66us</td><td align="right"> </td><td align="right">224</td></tr>
<tr><td colspan="5"> </td></tr>
<tr><td>Authentication Algorithm</td><td align="right">Hashing (per byte)</td><td align="right">Finalization</td><td>Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>Authentication Algorithm</td><td align="right">Hashing (per byte)</td><td align="right">Finalization</td><td align="right">Key Setup</td><td>State Size (bytes)</td></tr>
<tr><td>SHA256 (HMAC mode)</td><td align="right">1.15us</td><td align="right">238.98us</td><td align="right">80.44us</td><td align="right">120</td></tr>
<tr><td>BLAKE2s (HMAC mode)</td><td align="right">0.72us</td><td align="right">157.75us</td><td align="right">57.18us</td><td align="right">120</td></tr>
<tr><td>BLAKE2s (Keyed mode)</td><td align="right">0.80us</td><td align="right">53.39us</td><td align="right">55.10us</td><td align="right">120</td></tr>
<tr><td>BLAKE2s (HMAC mode)</td><td align="right">0.80us</td><td align="right">168.20us</td><td align="right">57.60us</td><td align="right">120</td></tr>
<tr><td>BLAKE2b (Keyed mode)</td><td align="right">1.28us</td><td align="right">164.66us</td><td align="right">166.68us</td><td align="right">224</td></tr>
<tr><td>Poly1305</td><td align="right">0.81us</td><td align="right">19.01us</td><td align="right">2.57us</td><td align="right">60</td></tr>
<tr><td>GHASH</td><td align="right">4.47us</td><td align="right">1.52us</td><td align="right">2.60us</td><td align="right">36</td></tr>
<tr><td colspan="5"> </td></tr>
Expand Down
76 changes: 75 additions & 1 deletion libraries/Crypto/BLAKE2b.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,35 @@
* replacement for SHA512 for when speed is critical but exact SHA512
* compatibility is not.
*
* Reference: https://blake2.net/
* This class supports two types of keyed hash. The BLAKE2 keyed hash and
* traditional HMAC. The BLAKE2 keyed hash is recommended unless there is
* some higher-level application need to be compatible with the HMAC
* construction. The keyed hash is computed as follows:
*
* \code
* BLAKE2b blake;
* blake.reset(key, sizeof(key), outputLength);
* blake.update(data1, sizeof(data1));
* blake.update(data2, sizeof(data2));
* ...
* blake.update(dataN, sizeof(dataN));
* blake.finalize(hash, outputLength);
* \endcode
*
* The HMAC is computed as follows (the output length is always 64):
*
* \code
* BLAKE2b blake;
* blake.resetHMAC(key, sizeof(key));
* blake.update(data1, sizeof(data1));
* blake.update(data2, sizeof(data2));
* ...
* blake.update(dataN, sizeof(dataN));
* blake.finalizeHMAC(key, sizeof(key), hash, 32);
* \endcode
*
* References: https://blake2.net/,
* <a href="http://tools.ietf.org/html/rfc7693">RFC 7693</a>
*
* \sa BLAKE2s, SHA512, SHA3_512
*/
Expand Down Expand Up @@ -102,6 +130,10 @@ void BLAKE2b::reset()
*/
void BLAKE2b::reset(uint8_t outputLength)
{
if (outputLength < 1)
outputLength = 1;
else if (outputLength > 64)
outputLength = 64;
state.h[0] = BLAKE2b_IV0 ^ 0x01010000 ^ outputLength;
state.h[1] = BLAKE2b_IV1;
state.h[2] = BLAKE2b_IV2;
Expand All @@ -115,6 +147,48 @@ void BLAKE2b::reset(uint8_t outputLength)
state.lengthHigh = 0;
}

/**
* \brief Resets the hash ready for a new hashing process with a specified
* key and output length.
*
* \param key Points to the key.
* \param keyLen The length of the key in bytes, between 0 and 64.
* \param outputLength The output length to use for the final hash in bytes,
* between 1 and 64.
*
* If \a keyLen is greater than 64, then the \a key will be truncated to
* the first 64 bytes.
*/
void BLAKE2b::reset(const void *key, size_t keyLen, uint8_t outputLength)
{
if (keyLen > 64)
keyLen = 64;
if (outputLength < 1)
outputLength = 1;
else if (outputLength > 64)
outputLength = 64;
state.h[0] = BLAKE2b_IV0 ^ 0x01010000 ^ (keyLen << 8) ^ outputLength;
state.h[1] = BLAKE2b_IV1;
state.h[2] = BLAKE2b_IV2;
state.h[3] = BLAKE2b_IV3;
state.h[4] = BLAKE2b_IV4;
state.h[5] = BLAKE2b_IV5;
state.h[6] = BLAKE2b_IV6;
state.h[7] = BLAKE2b_IV7;
if (keyLen > 0) {
// Set the first block to the key and pad with zeroes.
memcpy(state.m, key, keyLen);
memset(((uint8_t *)state.m) + keyLen, 0, 128 - keyLen);
state.chunkSize = 128;
state.lengthLow = 128;
} else {
// No key. The first data block is the first hashed block.
state.chunkSize = 0;
state.lengthLow = 0;
}
state.lengthHigh = 0;
}

void BLAKE2b::update(const void *data, size_t len)
{
// Break the input up into 1024-bit chunks and process each in turn.
Expand Down
2 changes: 2 additions & 0 deletions libraries/Crypto/BLAKE2b.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class BLAKE2b : public Hash

void reset();
void reset(uint8_t outputLength);
void reset(const void *key, size_t keyLen, uint8_t outputLength = 64);

void update(const void *data, size_t len);
void finalize(void *hash, size_t len);

Expand Down
75 changes: 74 additions & 1 deletion libraries/Crypto/BLAKE2s.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,35 @@
* replacement for SHA256 for when speed is critical but exact SHA256
* compatibility is not.
*
* Reference: https://blake2.net/
* This class supports two types of keyed hash. The BLAKE2 keyed hash and
* traditional HMAC. The BLAKE2 keyed hash is recommended unless there is
* some higher-level application need to be compatible with the HMAC
* construction. The keyed hash is computed as follows:
*
* \code
* BLAKE2s blake;
* blake.reset(key, sizeof(key), outputLength);
* blake.update(data1, sizeof(data1));
* blake.update(data2, sizeof(data2));
* ...
* blake.update(dataN, sizeof(dataN));
* blake.finalize(hash, outputLength);
* \endcode
*
* The HMAC is computed as follows (the output length is always 32):
*
* \code
* BLAKE2s blake;
* blake.resetHMAC(key, sizeof(key));
* blake.update(data1, sizeof(data1));
* blake.update(data2, sizeof(data2));
* ...
* blake.update(dataN, sizeof(dataN));
* blake.finalizeHMAC(key, sizeof(key), hash, 32);
* \endcode
*
* References: https://blake2.net/,
* <a href="http://tools.ietf.org/html/rfc7693">RFC 7693</a>
*
* \sa BLAKE2b, SHA256, SHA3_256
*/
Expand Down Expand Up @@ -101,6 +129,10 @@ void BLAKE2s::reset()
*/
void BLAKE2s::reset(uint8_t outputLength)
{
if (outputLength < 1)
outputLength = 1;
else if (outputLength > 32)
outputLength = 32;
state.h[0] = BLAKE2s_IV0 ^ 0x01010000 ^ outputLength;
state.h[1] = BLAKE2s_IV1;
state.h[2] = BLAKE2s_IV2;
Expand All @@ -113,6 +145,47 @@ void BLAKE2s::reset(uint8_t outputLength)
state.length = 0;
}

/**
* \brief Resets the hash ready for a new hashing process with a specified
* key and output length.
*
* \param key Points to the key.
* \param keyLen The length of the key in bytes, between 0 and 32.
* \param outputLength The output length to use for the final hash in bytes,
* between 1 and 32.
*
* If \a keyLen is greater than 32, then the \a key will be truncated to
* the first 32 bytes.
*/
void BLAKE2s::reset(const void *key, size_t keyLen, uint8_t outputLength)
{
if (keyLen > 32)
keyLen = 32;
if (outputLength < 1)
outputLength = 1;
else if (outputLength > 32)
outputLength = 32;
state.h[0] = BLAKE2s_IV0 ^ 0x01010000 ^ (keyLen << 8) ^ outputLength;
state.h[1] = BLAKE2s_IV1;
state.h[2] = BLAKE2s_IV2;
state.h[3] = BLAKE2s_IV3;
state.h[4] = BLAKE2s_IV4;
state.h[5] = BLAKE2s_IV5;
state.h[6] = BLAKE2s_IV6;
state.h[7] = BLAKE2s_IV7;
if (keyLen > 0) {
// Set the first block to the key and pad with zeroes.
memcpy(state.m, key, keyLen);
memset(((uint8_t *)state.m) + keyLen, 0, 64 - keyLen);
state.chunkSize = 64;
state.length = 64;
} else {
// No key. The first data block is the first hashed block.
state.chunkSize = 0;
state.length = 0;
}
}

void BLAKE2s::update(const void *data, size_t len)
{
// Break the input up into 512-bit chunks and process each in turn.
Expand Down
2 changes: 2 additions & 0 deletions libraries/Crypto/BLAKE2s.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class BLAKE2s : public Hash

void reset();
void reset(uint8_t outputLength);
void reset(const void *key, size_t keyLen, uint8_t outputLength = 32);

void update(const void *data, size_t len);
void finalize(void *hash, size_t len);

Expand Down
Loading

0 comments on commit c8d7c31

Please sign in to comment.