From 72901a91f903d40438270b17258d8877ada12671 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Sat, 14 Mar 2015 07:19:44 +1000 Subject: [PATCH] SHA512 hash algorithm --- doc/crypto.dox | 11 +- doc/mainpage.dox | 2 +- libraries/Crypto/SHA1.cpp | 2 +- libraries/Crypto/SHA256.cpp | 2 +- libraries/Crypto/SHA512.cpp | 264 ++++++++++++++++++ libraries/Crypto/SHA512.h | 56 ++++ .../Crypto/examples/TestSHA512/TestSHA512.ino | 179 ++++++++++++ libraries/Crypto/utility/EndianUtil.h | 11 + libraries/Crypto/utility/ProgMemUtil.h | 7 + libraries/Crypto/utility/RotateUtil.h | 196 +++++++------ 10 files changed, 631 insertions(+), 99 deletions(-) create mode 100644 libraries/Crypto/SHA512.cpp create mode 100644 libraries/Crypto/SHA512.h create mode 100644 libraries/Crypto/examples/TestSHA512/TestSHA512.ino 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.13us8.14us43.74us130 SHA121.90us 94 SHA25643.85us 106 +SHA512123.25us 210 BLAKE2s18.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