From 91b3aa70e7faa7feea5bd96fc946a4ff5dd01e9b Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Sun, 4 Jan 2015 15:49:16 +1000 Subject: [PATCH] BLAKE2s hash function --- doc/crypto.dox | 8 +- doc/mainpage.dox | 2 +- libraries/Crypto/AESCommon.cpp | 4 + libraries/Crypto/BLAKE2s.cpp | 239 ++++++++++++++++++ libraries/Crypto/BLAKE2s.h | 57 +++++ libraries/Crypto/ChaCha.cpp | 12 - libraries/Crypto/SHA256.cpp | 2 +- .../examples/TestBLAKE2s/TestBLAKE2s.ino | 177 +++++++++++++ libraries/Crypto/utility/EndianUtil.h | 2 + libraries/Crypto/utility/RotateUtil.h | 4 +- 10 files changed, 490 insertions(+), 17 deletions(-) create mode 100644 libraries/Crypto/BLAKE2s.cpp create mode 100644 libraries/Crypto/BLAKE2s.h create mode 100644 libraries/Crypto/examples/TestBLAKE2s/TestBLAKE2s.ino diff --git a/doc/crypto.dox b/doc/crypto.dox index ccc5fb27..c629daea 100644 --- a/doc/crypto.dox +++ b/doc/crypto.dox @@ -29,7 +29,7 @@ \li Block ciphers: AES128, AES192, AES256 \li Block cipher modes: CTR, CFB, CBC, OFB \li Stream ciphers: ChaCha, Arcfour -\li Hash algorithms: SHA1, SHA256 +\li Hash algorithms: SHA1, SHA256, BLAKE2s All cryptographic algorithms have been optimized for 8-bit Arduino platforms like the Uno. Memory usage is also reduced, particularly for SHA1 and SHA256 @@ -43,6 +43,11 @@ constant-time, and much more secure. AES128, AES192, AES256, and Arcfour are provided for use in applications where compatibility with other systems is desirable. +BLAKE2s is a variation on the ChaCha stream cipher, designed for hashing, +with a 256-bit hash output. It is intended as a high performance drop-in +replacement for SHA256 for when speed is critical but exact SHA256 +compatibility is not. + \section crypto_examples Examples TBD @@ -62,6 +67,7 @@ All figures are for the Arduino Uno running at 16 MHz: ChaCha (8 rounds)8.13us8.14us43.74us130 SHA121.90us 94 SHA25643.85us 106 +BLAKE2s18.54us 170 Where a cipher supports more than one key size (such as ChaCha and Arcfour), diff --git a/doc/mainpage.dox b/doc/mainpage.dox index 2f984512..5b386078 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, Arcfour -\li Hash algorithms: SHA1, SHA256 +\li Hash algorithms: SHA1, SHA256, BLAKE2s More information can be found on the \ref crypto "Cryptographic Library" page. diff --git a/libraries/Crypto/AESCommon.cpp b/libraries/Crypto/AESCommon.cpp index 012947bc..02a946ba 100644 --- a/libraries/Crypto/AESCommon.cpp +++ b/libraries/Crypto/AESCommon.cpp @@ -43,6 +43,8 @@ * \sa ChaCha, AES128, AES192, AES256 */ +/** @cond */ + // AES S-box (http://en.wikipedia.org/wiki/Rijndael_S-box) static uint8_t const sbox[256] PROGMEM = { 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, // 0x00 @@ -115,6 +117,8 @@ static uint8_t const sbox_inverse[256] PROGMEM = { 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D }; +/** @endcond */ + /** * \brief Constructs an AES block cipher object. */ diff --git a/libraries/Crypto/BLAKE2s.cpp b/libraries/Crypto/BLAKE2s.cpp new file mode 100644 index 00000000..762dfa1a --- /dev/null +++ b/libraries/Crypto/BLAKE2s.cpp @@ -0,0 +1,239 @@ +/* + * 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 "BLAKE2s.h" +#include "Crypto.h" +#include "utility/EndianUtil.h" +#include "utility/RotateUtil.h" +#include "utility/ProgMemUtil.h" +#include + +/** + * \class BLAKE2s BLAKE2s.h + * \brief BLAKE2s hash algorithm. + * + * BLAKE2s is a variation on the ChaCha stream cipher, designed for hashing, + * with a 256-bit hash output. It is intended as a high performance + * replacement for SHA256 for when speed is critical but exact SHA256 + * compatibility is not. + * + * Reference: https://blake2.net/ + * + * \sa SHA256 + */ + +/** + * \brief Constructs a BLAKE2s hash object. + */ +BLAKE2s::BLAKE2s() +{ + reset(); +} + +/** + * \brief Destroys this BLAKE2s hash object after clearing + * sensitive information. + */ +BLAKE2s::~BLAKE2s() +{ + clean(state); +} + +size_t BLAKE2s::hashSize() const +{ + return 32; +} + +size_t BLAKE2s::blockSize() const +{ + return 64; +} + +// Initialization vectors for BLAKE2s. +#define BLAKE2s_IV0 0x6A09E667 +#define BLAKE2s_IV1 0xBB67AE85 +#define BLAKE2s_IV2 0x3C6EF372 +#define BLAKE2s_IV3 0xA54FF53A +#define BLAKE2s_IV4 0x510E527F +#define BLAKE2s_IV5 0x9B05688C +#define BLAKE2s_IV6 0x1F83D9AB +#define BLAKE2s_IV7 0x5BE0CD19 + +void BLAKE2s::reset() +{ + state.h[0] = BLAKE2s_IV0 ^ 0x01010020; // Default output length of 32. + 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; + state.chunkSize = 0; + state.finalized = false; + state.length = 0; +} + +/** + * \brief Resets the hash ready for a new hashing process with a specified + * output length. + * + * \param outputLength The output length to use for the final hash in bytes, + * between 1 and 32. + */ +void BLAKE2s::reset(uint8_t outputLength) +{ + state.h[0] = BLAKE2s_IV0 ^ 0x01010000 ^ 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; + state.chunkSize = 0; + state.finalized = false; + state.length = 0; +} + +void BLAKE2s::update(const void *data, size_t len) +{ + // Reset the hashing process if finalize() was called previously. + if (state.finalized) + reset(); + + // Break the input up into 512-bit chunks and process each in turn. + const uint8_t *d = (const uint8_t *)data; + while (len > 0) { + if (state.chunkSize == 64) { + // Previous chunk was full and we know that it wasn't the + // last chunk, so we can process it now with f0 set to zero. + processChunk(0); + state.chunkSize = 0; + } + uint8_t size = 64 - state.chunkSize; + if (size > len) + size = len; + memcpy(((uint8_t *)state.m) + state.chunkSize, d, size); + state.chunkSize += size; + state.length += size; + len -= size; + d += size; + } +} + +void BLAKE2s::finalize(void *hash, size_t len) +{ + // Finalize the hash if necessary. + if (!state.finalized) { + // Pad the last chunk and hash it with f0 set to all-ones. + memset(((uint8_t *)state.m) + state.chunkSize, 0, 64 - state.chunkSize); + processChunk(0xFFFFFFFF); + + // Convert the hash into little-endian in the message buffer. + for (uint8_t posn = 0; posn < 8; ++posn) + state.m[posn] = htole32(state.h[posn]); + state.finalized = true; + } + + // Copy the hash to the caller's return buffer. + if (len > 32) + len = 32; + memcpy(hash, state.m, len); +} + +void BLAKE2s::clear() +{ + clean(state); + reset(); +} + +// Permutation on the message input state for BLAKE2s. +static const uint8_t sigma[10][16] PROGMEM = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0} +}; + +// Perform a BLAKE2s quarter round operation. +#define quarterRound(a, b, c, d, i) \ + do { \ + uint32_t _b = (b); \ + uint32_t _a = (a) + _b + state.m[pgm_read_byte(&(sigma[index][2 * (i)]))]; \ + uint32_t _d = rightRotate16((d) ^ _a); \ + uint32_t _c = (c) + _d; \ + _b = rightRotate12(_b ^ _c); \ + _a += _b + state.m[pgm_read_byte(&(sigma[index][2 * (i) + 1]))]; \ + (d) = _d = rightRotate8(_d ^ _a); \ + _c += _d; \ + (a) = _a; \ + (b) = rightRotate7(_b ^ _c); \ + (c) = _c; \ + } while (0) + +void BLAKE2s::processChunk(uint32_t f0) +{ + uint8_t index; + + // Byte-swap the message buffer into little-endian if necessary. +#if !defined(CRYPTO_LITTLE_ENDIAN) + for (index = 0; index < 16; ++index) + state.m[index] = le32toh(state.m[index]); +#endif + + // Format the block to be hashed. + memcpy(state.v, state.h, sizeof(state.h)); + state.v[8] = BLAKE2s_IV0; + state.v[9] = BLAKE2s_IV1; + state.v[10] = BLAKE2s_IV2; + state.v[11] = BLAKE2s_IV3; + state.v[12] = BLAKE2s_IV4 ^ (uint32_t)(state.length); + state.v[13] = BLAKE2s_IV5 ^ (uint32_t)(state.length >> 32); + state.v[14] = BLAKE2s_IV6 ^ f0; + state.v[15] = BLAKE2s_IV7; + + // Perform the 10 BLAKE2s rounds. + for (index = 0; index < 10; ++index) { + // Column round. + quarterRound(state.v[0], state.v[4], state.v[8], state.v[12], 0); + quarterRound(state.v[1], state.v[5], state.v[9], state.v[13], 1); + quarterRound(state.v[2], state.v[6], state.v[10], state.v[14], 2); + quarterRound(state.v[3], state.v[7], state.v[11], state.v[15], 3); + + // Diagonal round. + quarterRound(state.v[0], state.v[5], state.v[10], state.v[15], 4); + quarterRound(state.v[1], state.v[6], state.v[11], state.v[12], 5); + quarterRound(state.v[2], state.v[7], state.v[8], state.v[13], 6); + quarterRound(state.v[3], state.v[4], state.v[9], state.v[14], 7); + } + + // Combine the new and old hash values. + for (index = 0; index < 8; ++index) + state.h[index] ^= (state.v[index] ^ state.v[index + 8]); +} diff --git a/libraries/Crypto/BLAKE2s.h b/libraries/Crypto/BLAKE2s.h new file mode 100644 index 00000000..51f8df14 --- /dev/null +++ b/libraries/Crypto/BLAKE2s.h @@ -0,0 +1,57 @@ +/* + * 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_BLAKE2S_H +#define CRYPTO_BLAKE2S_H + +#include "Hash.h" + +class BLAKE2s : public Hash +{ +public: + BLAKE2s(); + virtual ~BLAKE2s(); + + size_t hashSize() const; + size_t blockSize() const; + + void reset(); + void reset(uint8_t outputLength); + void update(const void *data, size_t len); + void finalize(void *hash, size_t len); + + void clear(); + +private: + struct { + uint32_t h[8]; + uint32_t m[16]; + uint32_t v[16]; + uint8_t chunkSize; + bool finalized; + uint64_t length; + } state; + + void processChunk(uint32_t f0); +}; + +#endif diff --git a/libraries/Crypto/ChaCha.cpp b/libraries/Crypto/ChaCha.cpp index 6c381534..82a6318e 100644 --- a/libraries/Crypto/ChaCha.cpp +++ b/libraries/Crypto/ChaCha.cpp @@ -199,18 +199,6 @@ void ChaCha::clear() posn = 64; } -// On AVR it is faster to rotate left by 16 bits and then right by 4 bits -// one at a time than to rotate left by 12 bits in a single step. -#define leftRotate12(a) \ - (__extension__ ({ \ - uint32_t temp = (a); \ - temp = (temp << 16) | (temp >> 16); \ - temp = rightRotate(temp, 1); \ - temp = rightRotate(temp, 1); \ - temp = rightRotate(temp, 1); \ - rightRotate(temp, 1); \ - })) - // Perform a ChaCha quarter round operation. #define quarterRound(a, b, c, d) \ do { \ diff --git a/libraries/Crypto/SHA256.cpp b/libraries/Crypto/SHA256.cpp index 96a1003a..63a20f97 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 + * \sa SHA1, BLAKE2s */ /** diff --git a/libraries/Crypto/examples/TestBLAKE2s/TestBLAKE2s.ino b/libraries/Crypto/examples/TestBLAKE2s/TestBLAKE2s.ino new file mode 100644 index 00000000..d7eb6839 --- /dev/null +++ b/libraries/Crypto/examples/TestBLAKE2s/TestBLAKE2s.ino @@ -0,0 +1,177 @@ +/* + * 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 BLAKE2s implementation to verify correct behaviour. +*/ + +#include +#include +#include + +#define HASH_SIZE 32 + +struct TestHashVector +{ + const char *name; + const char *data; + uint8_t hash[HASH_SIZE]; +}; + +// Test vectors generated with the reference implementation of BLAKE2s. +static TestHashVector const testVectorBLAKE2s_1 = { + "BLAKE2s #1", + "", + {0x69, 0x21, 0x7a, 0x30, 0x79, 0x90, 0x80, 0x94, + 0xe1, 0x11, 0x21, 0xd0, 0x42, 0x35, 0x4a, 0x7c, + 0x1f, 0x55, 0xb6, 0x48, 0x2c, 0xa1, 0xa5, 0x1e, + 0x1b, 0x25, 0x0d, 0xfd, 0x1e, 0xd0, 0xee, 0xf9} +}; +static TestHashVector const testVectorBLAKE2s_2 = { + "BLAKE2s #2", + "abc", + {0x50, 0x8c, 0x5e, 0x8c, 0x32, 0x7c, 0x14, 0xe2, + 0xe1, 0xa7, 0x2b, 0xa3, 0x4e, 0xeb, 0x45, 0x2f, + 0x37, 0x45, 0x8b, 0x20, 0x9e, 0xd6, 0x3a, 0x29, + 0x4d, 0x99, 0x9b, 0x4c, 0x86, 0x67, 0x59, 0x82} +}; +static TestHashVector const testVectorBLAKE2s_3 = { + "BLAKE2s #3", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + {0x6f, 0x4d, 0xf5, 0x11, 0x6a, 0x6f, 0x33, 0x2e, + 0xda, 0xb1, 0xd9, 0xe1, 0x0e, 0xe8, 0x7d, 0xf6, + 0x55, 0x7b, 0xea, 0xb6, 0x25, 0x9d, 0x76, 0x63, + 0xf3, 0xbc, 0xd5, 0x72, 0x2c, 0x13, 0xf1, 0x89} +}; +static TestHashVector const testVectorBLAKE2s_4 = { + "BLAKE2s #4", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + {0x35, 0x8d, 0xd2, 0xed, 0x07, 0x80, 0xd4, 0x05, + 0x4e, 0x76, 0xcb, 0x6f, 0x3a, 0x5b, 0xce, 0x28, + 0x41, 0xe8, 0xe2, 0xf5, 0x47, 0x43, 0x1d, 0x4d, + 0x09, 0xdb, 0x21, 0xb6, 0x6d, 0x94, 0x1f, 0xc7} +}; + +BLAKE2s blake2s; + +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 < 1000; ++count) { + hash->update(buffer, sizeof(buffer)); + } + elapsed = micros() - start; + + Serial.print(elapsed / (sizeof(buffer) * 1000.0)); + Serial.print("us per byte, "); + Serial.print((sizeof(buffer) * 1000.0 * 1000000.0) / elapsed); + Serial.println(" bytes per second"); +} + +void setup() +{ + Serial.begin(9600); + + Serial.println(); + + Serial.println("Test Vectors:"); + testHash(&blake2s, &testVectorBLAKE2s_1); + testHash(&blake2s, &testVectorBLAKE2s_2); + testHash(&blake2s, &testVectorBLAKE2s_3); + testHash(&blake2s, &testVectorBLAKE2s_4); + + Serial.println(); + + Serial.println("Performance Tests:"); + perfHash(&blake2s); +} + +void loop() +{ +} diff --git a/libraries/Crypto/utility/EndianUtil.h b/libraries/Crypto/utility/EndianUtil.h index 58ba1804..f85b39de 100644 --- a/libraries/Crypto/utility/EndianUtil.h +++ b/libraries/Crypto/utility/EndianUtil.h @@ -28,6 +28,8 @@ // CPU is assumed to be little endian. Edit this file if you // need to port this library to a big endian CPU. +#define CRYPTO_LITTLE_ENDIAN 1 + #define htole32(x) (x) #define le32toh(x) (x) #define htobe32(x) \ diff --git a/libraries/Crypto/utility/RotateUtil.h b/libraries/Crypto/utility/RotateUtil.h index c0b2cdc4..ebef8b39 100644 --- a/libraries/Crypto/utility/RotateUtil.h +++ b/libraries/Crypto/utility/RotateUtil.h @@ -78,8 +78,8 @@ // Left rotate by 11: Rotate left by 8, then left by 3. #define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) -// Left rotate by 12: Rotate left by 8, then left by 4. -#define leftRotate12(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1), 1)) +// Left rotate by 12: Rotate left by 16, then right by 4. +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) // Left rotate by 13: Rotate left by 16, then right by 3. #define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1))