diff --git a/doc/crypto.dox b/doc/crypto.dox
index e26d84ad..2f0ddd70 100644
--- a/doc/crypto.dox
+++ b/doc/crypto.dox
@@ -29,15 +29,15 @@
\li Block ciphers: AES128, AES192, AES256
\li Block cipher modes: CTR, CFB, CBC, OFB
\li Stream ciphers: ChaCha
-\li Hash algorithms: SHA1, SHA256, BLAKE2s
+\li Hash algorithms: SHA1, SHA256, SHA512, BLAKE2s
\li Public key algorithms: Curve25519
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource
All cryptographic algorithms have been optimized for 8-bit Arduino platforms
-like the Uno. Memory usage is also reduced, particularly for SHA1 and SHA256
-which save 256 and 192 bytes respectively over traditional implementations.
-For other algorithms, static sbox tables and the like are placed into
-program memory to further reduce data memory usage.
+like the Uno. Memory usage is also reduced, particularly for SHA1, SHA256,
+and SHA512 which save 256, 192, and 512 bytes respectively over traditional
+implementations. For other algorithms, static sbox tables and the like are
+placed into program memory to further reduce data memory usage.
ChaCha with 20 rounds and 256-bit keys is the recommended
symmetric encryption algorithm because it is twice as fast as AES128,
@@ -65,6 +65,7 @@ Ardunino Mega 2560 running at 16 MHz are similar:
ChaCha (8 rounds) | 8.13us | 8.14us | 43.74us | 130 |
SHA1 | 21.90us | | | 94 |
SHA256 | 43.85us | | | 106 |
+SHA512 | 123.25us | | | 210 |
BLAKE2s | 18.54us | | | 170 |
diff --git a/doc/mainpage.dox b/doc/mainpage.dox
index bfc545d0..a8940535 100644
--- a/doc/mainpage.dox
+++ b/doc/mainpage.dox
@@ -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, BLAKE2s
+\li Hash algorithms: SHA1, SHA256, SHA512, BLAKE2s
\li Public key algorithms: Curve25519
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource
diff --git a/libraries/Crypto/SHA1.cpp b/libraries/Crypto/SHA1.cpp
index 8209eb45..8783fdad 100644
--- a/libraries/Crypto/SHA1.cpp
+++ b/libraries/Crypto/SHA1.cpp
@@ -32,7 +32,7 @@
*
* Reference: http://en.wikipedia.org/wiki/SHA-1
*
- * \sa SHA256
+ * \sa SHA256, SHA512
*/
/**
diff --git a/libraries/Crypto/SHA256.cpp b/libraries/Crypto/SHA256.cpp
index 63a20f97..30257620 100644
--- a/libraries/Crypto/SHA256.cpp
+++ b/libraries/Crypto/SHA256.cpp
@@ -33,7 +33,7 @@
*
* Reference: http://en.wikipedia.org/wiki/SHA-2
*
- * \sa SHA1, BLAKE2s
+ * \sa SHA512, SHA1, BLAKE2s
*/
/**
diff --git a/libraries/Crypto/SHA512.cpp b/libraries/Crypto/SHA512.cpp
new file mode 100644
index 00000000..d9588dda
--- /dev/null
+++ b/libraries/Crypto/SHA512.cpp
@@ -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
+
+/**
+ * \class SHA512 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;
+}
diff --git a/libraries/Crypto/SHA512.h b/libraries/Crypto/SHA512.h
new file mode 100644
index 00000000..ae37118a
--- /dev/null
+++ b/libraries/Crypto/SHA512.h
@@ -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
diff --git a/libraries/Crypto/examples/TestSHA512/TestSHA512.ino b/libraries/Crypto/examples/TestSHA512/TestSHA512.ino
new file mode 100644
index 00000000..9e47701d
--- /dev/null
+++ b/libraries/Crypto/examples/TestSHA512/TestSHA512.ino
@@ -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
+#include
+#include
+
+#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()
+{
+}
diff --git a/libraries/Crypto/utility/EndianUtil.h b/libraries/Crypto/utility/EndianUtil.h
index f85b39de..b64f9726 100644
--- a/libraries/Crypto/utility/EndianUtil.h
+++ b/libraries/Crypto/utility/EndianUtil.h
@@ -42,4 +42,15 @@
}))
#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
diff --git a/libraries/Crypto/utility/ProgMemUtil.h b/libraries/Crypto/utility/ProgMemUtil.h
index ccd3fde4..ea56224a 100644
--- a/libraries/Crypto/utility/ProgMemUtil.h
+++ b/libraries/Crypto/utility/ProgMemUtil.h
@@ -25,12 +25,19 @@
#if defined(__AVR__)
#include
+#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
#include
#define PROGMEM
#define pgm_read_byte(x) (*(x))
#define pgm_read_word(x) (*(x))
#define pgm_read_dword(x) (*(x))
+#define pgm_read_qword(x) (*(x))
#define memcpy_P(d,s,l) memcpy((d), (s), (l))
#endif
diff --git a/libraries/Crypto/utility/RotateUtil.h b/libraries/Crypto/utility/RotateUtil.h
index 77cff486..fcabc824 100644
--- a/libraries/Crypto/utility/RotateUtil.h
+++ b/libraries/Crypto/utility/RotateUtil.h
@@ -25,13 +25,21 @@
#include
-#if defined(__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
// multiple of 8, so we compose the efficient rotations to produce all
// 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.
// Generic left rotate - best performance when "bits" is 1 or a multiple of 8.
@@ -174,6 +182,97 @@
#define rightRotate30(a) (leftRotate2((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.
// 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))
// 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.
#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.
-#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.
#define leftRotate31_64(a) (rightRotate_64(leftRotate_64((a), 32), 1))
@@ -444,92 +543,7 @@
#define rightRotate62_64(a) (leftRotate2_64((a)))
#define rightRotate63_64(a) (leftRotate1_64((a)))
-#else
-
-// 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))
+#else // !CRYPTO_ROTATE64_COMPOSED
// Rotation macros for 64-bit arguments.
@@ -677,6 +691,6 @@
#define rightRotate62_64(a) (rightRotate_64((a), 62))
#define rightRotate63_64(a) (rightRotate_64((a), 63))
-#endif
+#endif // !CRYPTO_ROTATE64_COMPOSED
#endif