1
0
mirror of https://github.com/taigrr/arduinolibs synced 2025-01-18 04:33:12 -08:00

SHA512 hash algorithm

This commit is contained in:
Rhys Weatherley 2015-03-14 07:19:44 +10:00
parent 436e597d83
commit 72901a91f9
10 changed files with 631 additions and 99 deletions

View File

@ -29,15 +29,15 @@
\li Block ciphers: AES128, AES192, AES256 \li Block ciphers: AES128, AES192, AES256
\li Block cipher modes: CTR, CFB, CBC, OFB \li Block cipher modes: CTR, CFB, CBC, OFB
\li Stream ciphers: ChaCha \li Stream ciphers: ChaCha
\li Hash algorithms: SHA1, SHA256, BLAKE2s \li Hash algorithms: SHA1, SHA256, SHA512, BLAKE2s
\li Public key algorithms: Curve25519 \li Public key algorithms: Curve25519
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource \li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource
All cryptographic algorithms have been optimized for 8-bit Arduino platforms All cryptographic algorithms have been optimized for 8-bit Arduino platforms
like the Uno. Memory usage is also reduced, particularly for SHA1 and SHA256 like the Uno. Memory usage is also reduced, particularly for SHA1, SHA256,
which save 256 and 192 bytes respectively over traditional implementations. and SHA512 which save 256, 192, and 512 bytes respectively over traditional
For other algorithms, static sbox tables and the like are placed into implementations. For other algorithms, static sbox tables and the like are
program memory to further reduce data memory usage. placed into program memory to further reduce data memory usage.
ChaCha with 20 rounds and 256-bit keys is the recommended ChaCha with 20 rounds and 256-bit keys is the recommended
symmetric encryption algorithm because it is twice as fast as AES128, symmetric encryption algorithm because it is twice as fast as AES128,
@ -65,6 +65,7 @@ Ardunino Mega 2560 running at 16 MHz are similar:
<tr><td>ChaCha (8 rounds)</td><td align="right">8.13us</td><td align="right">8.14us</td><td align="right">43.74us</td><td align="right">130</td></tr> <tr><td>ChaCha (8 rounds)</td><td align="right">8.13us</td><td align="right">8.14us</td><td align="right">43.74us</td><td align="right">130</td></tr>
<tr><td>SHA1</td><td align="right">21.90us</td><td> </td><td align="right"> </td><td align="right">94</td></tr> <tr><td>SHA1</td><td align="right">21.90us</td><td> </td><td align="right"> </td><td align="right">94</td></tr>
<tr><td>SHA256</td><td align="right">43.85us</td><td> </td><td align="right"> </td><td align="right">106</td></tr> <tr><td>SHA256</td><td align="right">43.85us</td><td> </td><td align="right"> </td><td align="right">106</td></tr>
<tr><td>SHA512</td><td align="right">123.25us</td><td> </td><td align="right"> </td><td align="right">210</td></tr>
<tr><td>BLAKE2s</td><td align="right">18.54us</td><td> </td><td align="right"> </td><td align="right">170</td></tr> <tr><td>BLAKE2s</td><td align="right">18.54us</td><td> </td><td align="right"> </td><td align="right">170</td></tr>
</table> </table>

View File

@ -93,7 +93,7 @@ realtime clock and the LCD library to implement an alarm clock.
\li Block ciphers: AES128, AES192, AES256 \li Block ciphers: AES128, AES192, AES256
\li Block cipher modes: CTR, CFB, CBC, OFB \li Block cipher modes: CTR, CFB, CBC, OFB
\li Stream ciphers: ChaCha \li Stream ciphers: ChaCha
\li Hash algorithms: SHA1, SHA256, BLAKE2s \li Hash algorithms: SHA1, SHA256, SHA512, BLAKE2s
\li Public key algorithms: Curve25519 \li Public key algorithms: Curve25519
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource \li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource

View File

@ -32,7 +32,7 @@
* *
* Reference: http://en.wikipedia.org/wiki/SHA-1 * Reference: http://en.wikipedia.org/wiki/SHA-1
* *
* \sa SHA256 * \sa SHA256, SHA512
*/ */
/** /**

View File

@ -33,7 +33,7 @@
* *
* Reference: http://en.wikipedia.org/wiki/SHA-2 * Reference: http://en.wikipedia.org/wiki/SHA-2
* *
* \sa SHA1, BLAKE2s * \sa SHA512, SHA1, BLAKE2s
*/ */
/** /**

264
libraries/Crypto/SHA512.cpp Normal file
View File

@ -0,0 +1,264 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "SHA512.h"
#include "Crypto.h"
#include "utility/RotateUtil.h"
#include "utility/EndianUtil.h"
#include "utility/ProgMemUtil.h"
#include <string.h>
/**
* \class SHA512 SHA512.h <SHA512.h>
* \brief SHA-512 hash algorithm.
*
* Reference: http://en.wikipedia.org/wiki/SHA-2
*
* \sa SHA256, SHA1
*/
/**
* \brief Constructs a SHA-512 hash object.
*/
SHA512::SHA512()
{
reset();
}
/**
* \brief Destroys this SHA-512 hash object after clearing
* sensitive information.
*/
SHA512::~SHA512()
{
clean(state);
}
size_t SHA512::hashSize() const
{
return 64;
}
size_t SHA512::blockSize() const
{
return 128;
}
void SHA512::reset()
{
static uint64_t const hashStart[8] PROGMEM = {
0x6A09E667F3BCC908ULL, 0xBB67AE8584CAA73BULL, 0x3C6EF372FE94F82BULL,
0xA54FF53A5F1D36F1ULL, 0x510E527FADE682D1ULL, 0x9B05688C2B3E6C1FULL,
0x1F83D9ABFB41BD6BULL, 0x5BE0CD19137E2179ULL
};
memcpy_P(state.h, hashStart, sizeof(hashStart));
state.chunkSize = 0;
state.finalized = false;
state.lengthLow = 0;
state.lengthHigh = 0;
}
void SHA512::update(const void *data, size_t len)
{
// Reset the hashing process if finalize() was called previously.
if (state.finalized)
reset();
// Update the total length in bits, not bytes.
uint64_t temp = state.lengthLow;
state.lengthLow += (((uint64_t)len) << 3);
state.lengthHigh += (((uint64_t)len) >> 61);
if (state.lengthLow < temp)
++state.lengthHigh;
// Break the input up into 1024-bit chunks and process each in turn.
const uint8_t *d = (const uint8_t *)data;
while (len > 0) {
uint8_t size = 128 - state.chunkSize;
if (size > len)
size = len;
memcpy(((uint8_t *)state.w) + state.chunkSize, d, size);
state.chunkSize += size;
len -= size;
d += size;
if (state.chunkSize == 128) {
processChunk();
state.chunkSize = 0;
}
}
}
void SHA512::finalize(void *hash, size_t len)
{
// Finalize the hash if necessary.
if (!state.finalized) {
// Pad the last chunk. We may need two padding chunks if there
// isn't enough room in the first for the padding and length.
uint8_t *wbytes = (uint8_t *)state.w;
if (state.chunkSize <= (128 - 17)) {
wbytes[state.chunkSize] = 0x80;
memset(wbytes + state.chunkSize + 1, 0x00, 128 - 16 - (state.chunkSize + 1));
state.w[14] = htobe64(state.lengthHigh);
state.w[15] = htobe64(state.lengthLow);
processChunk();
} else {
wbytes[state.chunkSize] = 0x80;
memset(wbytes + state.chunkSize + 1, 0x00, 128 - (state.chunkSize + 1));
processChunk();
memset(wbytes, 0x00, 128 - 16);
state.w[14] = htobe64(state.lengthHigh);
state.w[15] = htobe64(state.lengthLow);
processChunk();
}
// Convert the result into big endian and return it.
for (uint8_t posn = 0; posn < 8; ++posn)
state.w[posn] = htobe64(state.h[posn]);
state.finalized = true;
}
// Copy the hash to the caller's return buffer.
if (len > 64)
len = 64;
memcpy(hash, state.w, len);
}
void SHA512::clear()
{
clean(state);
reset();
}
/**
* \brief Processes a single 1024-bit chunk with the core SHA-512 algorithm.
*
* Reference: http://en.wikipedia.org/wiki/SHA-2
*/
void SHA512::processChunk()
{
// Round constants for SHA-512.
static uint64_t const k[80] PROGMEM = {
0x428A2F98D728AE22ULL, 0x7137449123EF65CDULL, 0xB5C0FBCFEC4D3B2FULL,
0xE9B5DBA58189DBBCULL, 0x3956C25BF348B538ULL, 0x59F111F1B605D019ULL,
0x923F82A4AF194F9BULL, 0xAB1C5ED5DA6D8118ULL, 0xD807AA98A3030242ULL,
0x12835B0145706FBEULL, 0x243185BE4EE4B28CULL, 0x550C7DC3D5FFB4E2ULL,
0x72BE5D74F27B896FULL, 0x80DEB1FE3B1696B1ULL, 0x9BDC06A725C71235ULL,
0xC19BF174CF692694ULL, 0xE49B69C19EF14AD2ULL, 0xEFBE4786384F25E3ULL,
0x0FC19DC68B8CD5B5ULL, 0x240CA1CC77AC9C65ULL, 0x2DE92C6F592B0275ULL,
0x4A7484AA6EA6E483ULL, 0x5CB0A9DCBD41FBD4ULL, 0x76F988DA831153B5ULL,
0x983E5152EE66DFABULL, 0xA831C66D2DB43210ULL, 0xB00327C898FB213FULL,
0xBF597FC7BEEF0EE4ULL, 0xC6E00BF33DA88FC2ULL, 0xD5A79147930AA725ULL,
0x06CA6351E003826FULL, 0x142929670A0E6E70ULL, 0x27B70A8546D22FFCULL,
0x2E1B21385C26C926ULL, 0x4D2C6DFC5AC42AEDULL, 0x53380D139D95B3DFULL,
0x650A73548BAF63DEULL, 0x766A0ABB3C77B2A8ULL, 0x81C2C92E47EDAEE6ULL,
0x92722C851482353BULL, 0xA2BFE8A14CF10364ULL, 0xA81A664BBC423001ULL,
0xC24B8B70D0F89791ULL, 0xC76C51A30654BE30ULL, 0xD192E819D6EF5218ULL,
0xD69906245565A910ULL, 0xF40E35855771202AULL, 0x106AA07032BBD1B8ULL,
0x19A4C116B8D2D0C8ULL, 0x1E376C085141AB53ULL, 0x2748774CDF8EEB99ULL,
0x34B0BCB5E19B48A8ULL, 0x391C0CB3C5C95A63ULL, 0x4ED8AA4AE3418ACBULL,
0x5B9CCA4F7763E373ULL, 0x682E6FF3D6B2B8A3ULL, 0x748F82EE5DEFB2FCULL,
0x78A5636F43172F60ULL, 0x84C87814A1F0AB72ULL, 0x8CC702081A6439ECULL,
0x90BEFFFA23631E28ULL, 0xA4506CEBDE82BDE9ULL, 0xBEF9A3F7B2C67915ULL,
0xC67178F2E372532BULL, 0xCA273ECEEA26619CULL, 0xD186B8C721C0C207ULL,
0xEADA7DD6CDE0EB1EULL, 0xF57D4F7FEE6ED178ULL, 0x06F067AA72176FBAULL,
0x0A637DC5A2C898A6ULL, 0x113F9804BEF90DAEULL, 0x1B710B35131C471BULL,
0x28DB77F523047D84ULL, 0x32CAAB7B40C72493ULL, 0x3C9EBE0A15C9BEBCULL,
0x431D67C49C100D4CULL, 0x4CC5D4BECB3E42B6ULL, 0x597F299CFC657E2AULL,
0x5FCB6FAB3AD6FAECULL, 0x6C44198C4A475817ULL
};
// Convert the first 16 words from big endian to host byte order.
uint8_t index;
for (index = 0; index < 16; ++index)
state.w[index] = be64toh(state.w[index]);
// Initialise working variables to the current hash value.
uint64_t a = state.h[0];
uint64_t b = state.h[1];
uint64_t c = state.h[2];
uint64_t d = state.h[3];
uint64_t e = state.h[4];
uint64_t f = state.h[5];
uint64_t g = state.h[6];
uint64_t h = state.h[7];
// Perform the first 16 rounds of the compression function main loop.
uint64_t temp1, temp2;
for (index = 0; index < 16; ++index) {
temp1 = h + pgm_read_qword(k + index) + state.w[index] +
(rightRotate14_64(e) ^ rightRotate18_64(e) ^
rightRotate41_64(e)) + ((e & f) ^ ((~e) & g));
temp2 = (rightRotate28_64(a) ^ rightRotate34_64(a) ^
rightRotate39_64(a)) + ((a & b) ^ (a & c) ^ (b & c));
h = g;
g = f;
f = e;
e = d + temp1;
d = c;
c = b;
b = a;
a = temp1 + temp2;
}
// Perform the 64 remaining rounds. We expand the first 16 words to
// 80 in-place in the "w" array. This saves 512 bytes of memory
// that would have otherwise need to be allocated to the "w" array.
for (; index < 80; ++index) {
// Expand the next word.
temp1 = state.w[(index - 15) & 0x0F];
temp2 = state.w[(index - 2) & 0x0F];
temp1 = state.w[index & 0x0F] =
state.w[(index - 16) & 0x0F] + state.w[(index - 7) & 0x0F] +
(rightRotate1_64(temp1) ^ rightRotate8_64(temp1) ^
(temp1 >> 7)) +
(rightRotate19_64(temp2) ^ rightRotate61_64(temp2) ^
(temp2 >> 6));
// Perform the round.
temp1 = h + pgm_read_qword(k + index) + temp1 +
(rightRotate14_64(e) ^ rightRotate18_64(e) ^
rightRotate41_64(e)) + ((e & f) ^ ((~e) & g));
temp2 = (rightRotate28_64(a) ^ rightRotate34_64(a) ^
rightRotate39_64(a)) + ((a & b) ^ (a & c) ^ (b & c));
h = g;
g = f;
f = e;
e = d + temp1;
d = c;
c = b;
b = a;
a = temp1 + temp2;
}
// Add the compressed chunk to the current hash value.
state.h[0] += a;
state.h[1] += b;
state.h[2] += c;
state.h[3] += d;
state.h[4] += e;
state.h[5] += f;
state.h[6] += g;
state.h[7] += h;
// Attempt to clean up the stack.
a = b = c = d = e = f = g = h = temp1 = temp2 = 0;
}

56
libraries/Crypto/SHA512.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CRYPTO_SHA512_h
#define CRYPTO_SHA512_h
#include "Hash.h"
class SHA512 : public Hash
{
public:
SHA512();
virtual ~SHA512();
size_t hashSize() const;
size_t blockSize() const;
void reset();
void update(const void *data, size_t len);
void finalize(void *hash, size_t len);
void clear();
private:
struct {
uint64_t h[8];
uint64_t w[16];
uint8_t chunkSize;
bool finalized;
uint64_t lengthLow;
uint64_t lengthHigh;
} state;
void processChunk();
};
#endif

View File

@ -0,0 +1,179 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/*
This example runs tests on the SHA512 implementation to verify correct behaviour.
*/
#include <Crypto.h>
#include <SHA512.h>
#include <string.h>
#define HASH_SIZE 64
struct TestHashVector
{
const char *name;
const char *data;
uint8_t hash[HASH_SIZE];
};
static TestHashVector const testVectorSHA512_1 = {
"SHA-512 #1",
"",
{0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd,
0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07,
0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc,
0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce,
0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0,
0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f,
0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81,
0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e}
};
static TestHashVector const testVectorSHA512_2 = {
"SHA-512 #2",
"abc",
{0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba,
0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8,
0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f}
};
static TestHashVector const testVectorSHA512_3 = {
"SHA-512 #3",
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
{0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda,
0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f,
0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1,
0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18,
0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4,
0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a,
0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54,
0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09}
};
SHA512 sha512;
byte buffer[128];
bool testHash_N(Hash *hash, const struct TestHashVector *test, size_t inc)
{
size_t size = strlen(test->data);
size_t posn, len;
uint8_t value[HASH_SIZE];
for (posn = 0; posn < size; posn += inc) {
len = size - posn;
if (len > inc)
len = inc;
hash->update(test->data + posn, len);
}
hash->finalize(value, sizeof(value));
if (memcmp(value, test->hash, sizeof(value)) != 0)
return false;
// Try again to make sure the hash resets.
for (posn = 0; posn < size; posn += inc) {
len = size - posn;
if (len > inc)
len = inc;
hash->update(test->data + posn, len);
}
hash->finalize(value, sizeof(value));
if (memcmp(value, test->hash, sizeof(value)) != 0)
return false;
return true;
}
void testHash(Hash *hash, const struct TestHashVector *test)
{
bool ok;
Serial.print(test->name);
Serial.print(" ... ");
ok = testHash_N(hash, test, strlen(test->data));
ok &= testHash_N(hash, test, 1);
ok &= testHash_N(hash, test, 2);
ok &= testHash_N(hash, test, 5);
ok &= testHash_N(hash, test, 8);
ok &= testHash_N(hash, test, 13);
ok &= testHash_N(hash, test, 16);
ok &= testHash_N(hash, test, 24);
ok &= testHash_N(hash, test, 63);
ok &= testHash_N(hash, test, 64);
if (ok)
Serial.println("Passed");
else
Serial.println("Failed");
}
void perfHash(Hash *hash)
{
unsigned long start;
unsigned long elapsed;
int count;
Serial.print("Hashing ... ");
for (size_t posn = 0; posn < sizeof(buffer); ++posn)
buffer[posn] = (uint8_t)posn;
hash->reset();
start = micros();
for (count = 0; count < 250; ++count) {
hash->update(buffer, sizeof(buffer));
}
elapsed = micros() - start;
Serial.print(elapsed / (sizeof(buffer) * 250.0));
Serial.print("us per byte, ");
Serial.print((sizeof(buffer) * 250.0 * 1000000.0) / elapsed);
Serial.println(" bytes per second");
}
void setup()
{
Serial.begin(9600);
Serial.println();
Serial.println("Test Vectors:");
testHash(&sha512, &testVectorSHA512_1);
testHash(&sha512, &testVectorSHA512_2);
testHash(&sha512, &testVectorSHA512_3);
Serial.println();
Serial.println("Performance Tests:");
perfHash(&sha512);
}
void loop()
{
}

View File

@ -42,4 +42,15 @@
})) }))
#define be32toh(x) (htobe32((x))) #define be32toh(x) (htobe32((x)))
#define htole64(x) (x)
#define le64toh(x) (x)
#define htobe64(x) \
(__extension__ ({ \
uint64_t __temp = (x); \
uint32_t __low = htobe32((uint32_t)__temp); \
uint32_t __high = htobe32((uint32_t)(__temp >> 32)); \
(((uint64_t)__low) << 32) | __high; \
}))
#define be64toh(x) (htobe64((x)))
#endif #endif

View File

@ -25,12 +25,19 @@
#if defined(__AVR__) #if defined(__AVR__)
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
#define pgm_read_qword(x) \
(__extension__ ({ \
const uint32_t *_temp = (const uint32_t *)(x); \
((uint64_t)pgm_read_dword(_temp)) | \
(((uint64_t)pgm_read_dword(_temp + 1)) << 32); \
}))
#else #else
#include <string.h> #include <string.h>
#define PROGMEM #define PROGMEM
#define pgm_read_byte(x) (*(x)) #define pgm_read_byte(x) (*(x))
#define pgm_read_word(x) (*(x)) #define pgm_read_word(x) (*(x))
#define pgm_read_dword(x) (*(x)) #define pgm_read_dword(x) (*(x))
#define pgm_read_qword(x) (*(x))
#define memcpy_P(d,s,l) memcpy((d), (s), (l)) #define memcpy_P(d,s,l) memcpy((d), (s), (l))
#endif #endif

View File

@ -25,13 +25,21 @@
#include <inttypes.h> #include <inttypes.h>
#if defined(__AVR__)
// Rotation functions that are optimised for best performance on AVR. // Rotation functions that are optimised for best performance on AVR.
// The most efficient rotations are where the number of bits is 1 or a // The most efficient rotations are where the number of bits is 1 or a
// multiple of 8, so we compose the efficient rotations to produce all // multiple of 8, so we compose the efficient rotations to produce all
// other rotation counts of interest. // other rotation counts of interest.
#if defined(__AVR__)
#define CRYPTO_ROTATE32_COMPOSED 1
#define CRYPTO_ROTATE64_COMPOSED 0
#else
#define CRYPTO_ROTATE32_COMPOSED 0
#define CRYPTO_ROTATE64_COMPOSED 0
#endif
#if CRYPTO_ROTATE32_COMPOSED
// Rotation macros for 32-bit arguments. // Rotation macros for 32-bit arguments.
// Generic left rotate - best performance when "bits" is 1 or a multiple of 8. // Generic left rotate - best performance when "bits" is 1 or a multiple of 8.
@ -174,6 +182,97 @@
#define rightRotate30(a) (leftRotate2((a))) #define rightRotate30(a) (leftRotate2((a)))
#define rightRotate31(a) (leftRotate1((a))) #define rightRotate31(a) (leftRotate1((a)))
#else // !CRYPTO_ROTATE32_COMPOSED
// Generic rotation functions. All bit shifts are considered to have
// similar performance. Usually true of 32-bit and higher platforms.
// Rotation macros for 32-bit arguments.
// Generic left rotate.
#define leftRotate(a, bits) \
(__extension__ ({ \
uint32_t _temp = (a); \
(_temp << (bits)) | (_temp >> (32 - (bits))); \
}))
// Generic right rotate.
#define rightRotate(a, bits) \
(__extension__ ({ \
uint32_t _temp = (a); \
(_temp >> (bits)) | (_temp << (32 - (bits))); \
}))
// Left rotate by a specific number of bits.
#define leftRotate1(a) (leftRotate((a), 1))
#define leftRotate2(a) (leftRotate((a), 2))
#define leftRotate3(a) (leftRotate((a), 3))
#define leftRotate4(a) (leftRotate((a), 4))
#define leftRotate5(a) (leftRotate((a), 5))
#define leftRotate6(a) (leftRotate((a), 6))
#define leftRotate7(a) (leftRotate((a), 7))
#define leftRotate8(a) (leftRotate((a), 8))
#define leftRotate9(a) (leftRotate((a), 9))
#define leftRotate10(a) (leftRotate((a), 10))
#define leftRotate11(a) (leftRotate((a), 11))
#define leftRotate12(a) (leftRotate((a), 12))
#define leftRotate13(a) (leftRotate((a), 13))
#define leftRotate14(a) (leftRotate((a), 14))
#define leftRotate15(a) (leftRotate((a), 15))
#define leftRotate16(a) (leftRotate((a), 16))
#define leftRotate17(a) (leftRotate((a), 17))
#define leftRotate18(a) (leftRotate((a), 18))
#define leftRotate19(a) (leftRotate((a), 19))
#define leftRotate20(a) (leftRotate((a), 20))
#define leftRotate21(a) (leftRotate((a), 21))
#define leftRotate22(a) (leftRotate((a), 22))
#define leftRotate23(a) (leftRotate((a), 23))
#define leftRotate24(a) (leftRotate((a), 24))
#define leftRotate25(a) (leftRotate((a), 25))
#define leftRotate26(a) (leftRotate((a), 26))
#define leftRotate27(a) (leftRotate((a), 27))
#define leftRotate28(a) (leftRotate((a), 28))
#define leftRotate29(a) (leftRotate((a), 29))
#define leftRotate30(a) (leftRotate((a), 30))
#define leftRotate31(a) (leftRotate((a), 31))
// Right rotate by a specific number of bits.
#define rightRotate1(a) (rightRotate((a), 1))
#define rightRotate2(a) (rightRotate((a), 2))
#define rightRotate3(a) (rightRotate((a), 3))
#define rightRotate4(a) (rightRotate((a), 4))
#define rightRotate5(a) (rightRotate((a), 5))
#define rightRotate6(a) (rightRotate((a), 6))
#define rightRotate7(a) (rightRotate((a), 7))
#define rightRotate8(a) (rightRotate((a), 8))
#define rightRotate9(a) (rightRotate((a), 9))
#define rightRotate10(a) (rightRotate((a), 10))
#define rightRotate11(a) (rightRotate((a), 11))
#define rightRotate12(a) (rightRotate((a), 12))
#define rightRotate13(a) (rightRotate((a), 13))
#define rightRotate14(a) (rightRotate((a), 14))
#define rightRotate15(a) (rightRotate((a), 15))
#define rightRotate16(a) (rightRotate((a), 16))
#define rightRotate17(a) (rightRotate((a), 17))
#define rightRotate18(a) (rightRotate((a), 18))
#define rightRotate19(a) (rightRotate((a), 19))
#define rightRotate20(a) (rightRotate((a), 20))
#define rightRotate21(a) (rightRotate((a), 21))
#define rightRotate22(a) (rightRotate((a), 22))
#define rightRotate23(a) (rightRotate((a), 23))
#define rightRotate24(a) (rightRotate((a), 24))
#define rightRotate25(a) (rightRotate((a), 25))
#define rightRotate26(a) (rightRotate((a), 26))
#define rightRotate27(a) (rightRotate((a), 27))
#define rightRotate28(a) (rightRotate((a), 28))
#define rightRotate29(a) (rightRotate((a), 29))
#define rightRotate30(a) (rightRotate((a), 30))
#define rightRotate31(a) (rightRotate((a), 31))
#endif // !CRYPTO_ROTATE32_COMPOSED
#if CRYPTO_ROTATE64_COMPOSED
// Rotation macros for 64-bit arguments. // Rotation macros for 64-bit arguments.
// Generic left rotate - best performance when "bits" is 1 or a multiple of 8. // Generic left rotate - best performance when "bits" is 1 or a multiple of 8.
@ -272,13 +371,13 @@
#define leftRotate27_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 24), 1), 1), 1)) #define leftRotate27_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 24), 1), 1), 1))
// Left rotate by 28: Rotate left by 24, then left by 4. // Left rotate by 28: Rotate left by 24, then left by 4.
#define leftRotate28_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 1), 1), 1), 1)) #define leftRotate28_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 24), 1), 1), 1), 1))
// Left rotate by 29: Rotate left by 32, then right by 3. // Left rotate by 29: Rotate left by 32, then right by 3.
#define leftRotate29_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 32), 1), 1), 1)) #define leftRotate29_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 32), 1), 1), 1))
// Left rotate by 30: Rotate left by 32, then right by 2. // Left rotate by 30: Rotate left by 32, then right by 2.
#define leftRotate29_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 32), 1), 1)) #define leftRotate30_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 32), 1), 1))
// Left rotate by 31: Rotate left by 32, then right by 1. // Left rotate by 31: Rotate left by 32, then right by 1.
#define leftRotate31_64(a) (rightRotate_64(leftRotate_64((a), 32), 1)) #define leftRotate31_64(a) (rightRotate_64(leftRotate_64((a), 32), 1))
@ -444,92 +543,7 @@
#define rightRotate62_64(a) (leftRotate2_64((a))) #define rightRotate62_64(a) (leftRotate2_64((a)))
#define rightRotate63_64(a) (leftRotate1_64((a))) #define rightRotate63_64(a) (leftRotate1_64((a)))
#else #else // !CRYPTO_ROTATE64_COMPOSED
// Generic rotation functions. All bit shifts are considered to have
// similar performance. Usually true of 32-bit and higher platforms.
// Rotation macros for 32-bit arguments.
// Generic left rotate.
#define leftRotate(a, bits) \
(__extension__ ({ \
uint32_t _temp = (a); \
(_temp << (bits)) | (_temp >> (32 - (bits))); \
}))
// Generic right rotate.
#define rightRotate(a, bits) \
(__extension__ ({ \
uint32_t _temp = (a); \
(_temp >> (bits)) | (_temp << (32 - (bits))); \
}))
// Left rotate by a specific number of bits.
#define leftRotate1(a) (leftRotate((a), 1))
#define leftRotate2(a) (leftRotate((a), 2))
#define leftRotate3(a) (leftRotate((a), 3))
#define leftRotate4(a) (leftRotate((a), 4))
#define leftRotate5(a) (leftRotate((a), 5))
#define leftRotate6(a) (leftRotate((a), 6))
#define leftRotate7(a) (leftRotate((a), 7))
#define leftRotate8(a) (leftRotate((a), 8))
#define leftRotate9(a) (leftRotate((a), 9))
#define leftRotate10(a) (leftRotate((a), 10))
#define leftRotate11(a) (leftRotate((a), 11))
#define leftRotate12(a) (leftRotate((a), 12))
#define leftRotate13(a) (leftRotate((a), 13))
#define leftRotate14(a) (leftRotate((a), 14))
#define leftRotate15(a) (leftRotate((a), 15))
#define leftRotate16(a) (leftRotate((a), 16))
#define leftRotate17(a) (leftRotate((a), 17))
#define leftRotate18(a) (leftRotate((a), 18))
#define leftRotate19(a) (leftRotate((a), 19))
#define leftRotate20(a) (leftRotate((a), 20))
#define leftRotate21(a) (leftRotate((a), 21))
#define leftRotate22(a) (leftRotate((a), 22))
#define leftRotate23(a) (leftRotate((a), 23))
#define leftRotate24(a) (leftRotate((a), 24))
#define leftRotate25(a) (leftRotate((a), 25))
#define leftRotate26(a) (leftRotate((a), 26))
#define leftRotate27(a) (leftRotate((a), 27))
#define leftRotate28(a) (leftRotate((a), 28))
#define leftRotate29(a) (leftRotate((a), 29))
#define leftRotate30(a) (leftRotate((a), 30))
#define leftRotate31(a) (leftRotate((a), 31))
// Right rotate by a specific number of bits.
#define rightRotate1(a) (rightRotate((a), 1))
#define rightRotate2(a) (rightRotate((a), 2))
#define rightRotate3(a) (rightRotate((a), 3))
#define rightRotate4(a) (rightRotate((a), 4))
#define rightRotate5(a) (rightRotate((a), 5))
#define rightRotate6(a) (rightRotate((a), 6))
#define rightRotate7(a) (rightRotate((a), 7))
#define rightRotate8(a) (rightRotate((a), 8))
#define rightRotate9(a) (rightRotate((a), 9))
#define rightRotate10(a) (rightRotate((a), 10))
#define rightRotate11(a) (rightRotate((a), 11))
#define rightRotate12(a) (rightRotate((a), 12))
#define rightRotate13(a) (rightRotate((a), 13))
#define rightRotate14(a) (rightRotate((a), 14))
#define rightRotate15(a) (rightRotate((a), 15))
#define rightRotate16(a) (rightRotate((a), 16))
#define rightRotate17(a) (rightRotate((a), 17))
#define rightRotate18(a) (rightRotate((a), 18))
#define rightRotate19(a) (rightRotate((a), 19))
#define rightRotate20(a) (rightRotate((a), 20))
#define rightRotate21(a) (rightRotate((a), 21))
#define rightRotate22(a) (rightRotate((a), 22))
#define rightRotate23(a) (rightRotate((a), 23))
#define rightRotate24(a) (rightRotate((a), 24))
#define rightRotate25(a) (rightRotate((a), 25))
#define rightRotate26(a) (rightRotate((a), 26))
#define rightRotate27(a) (rightRotate((a), 27))
#define rightRotate28(a) (rightRotate((a), 28))
#define rightRotate29(a) (rightRotate((a), 29))
#define rightRotate30(a) (rightRotate((a), 30))
#define rightRotate31(a) (rightRotate((a), 31))
// Rotation macros for 64-bit arguments. // Rotation macros for 64-bit arguments.
@ -677,6 +691,6 @@
#define rightRotate62_64(a) (rightRotate_64((a), 62)) #define rightRotate62_64(a) (rightRotate_64((a), 62))
#define rightRotate63_64(a) (rightRotate_64((a), 63)) #define rightRotate63_64(a) (rightRotate_64((a), 63))
#endif #endif // !CRYPTO_ROTATE64_COMPOSED
#endif #endif