feat(sim): add variants/sim/ — real companion_radio firmware on native + Emscripten

New board variant compiling the unmodified MyMesh/UITask/DataStore app
logic against real mesh::Radio/MainBoard/RTCClock/RNG interfaces, for
running the actual firmware outside embedded hardware:

- Native (plain g++, platform = native): ASCII-art display over stdout,
  stdin-driven input, local-disk-backed DataStore/IdentityStore.
- Emscripten/WASM (variants/sim/build_wasm.sh, since PlatformIO's native
  platform force-overrides any CC/CXX toolchain override back to system
  clang++): canvas-backed display, IDBFS-backed persistence across page
  reloads, JS-callable input via sim_enqueue_key(), emscripten_set_main_loop.

Real rweather/Crypto (AES128/SHA256/Ed25519) vendored unmodified and
proven working on both targets. variants/sim/web/index.html is a bare
verification harness, not the polished website embed.
This commit is contained in:
Jakub
2026-09-03 00:46:47 +02:00
parent bbf107d62c
commit 8f4c92a217
197 changed files with 23070 additions and 0 deletions
+269
View File
@@ -0,0 +1,269 @@
/*
* Copyright (C) 2015,2018 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_AES_h
#define CRYPTO_AES_h
#include "BlockCipher.h"
// Determine which AES implementation to export to applications.
#if defined(ESP32)
#define CRYPTO_AES_ESP32 1
#else
#define CRYPTO_AES_DEFAULT 1
#endif
#if defined(CRYPTO_AES_DEFAULT) || defined(CRYPTO_DOC)
class AESTiny128;
class AESTiny256;
class AESSmall128;
class AESSmall256;
class AESCommon : public BlockCipher
{
public:
virtual ~AESCommon();
size_t blockSize() const;
void encryptBlock(uint8_t *output, const uint8_t *input);
void decryptBlock(uint8_t *output, const uint8_t *input);
void clear();
protected:
AESCommon();
/** @cond aes_internal */
uint8_t rounds;
uint8_t *schedule;
static void subBytesAndShiftRows(uint8_t *output, const uint8_t *input);
static void inverseShiftRowsAndSubBytes(uint8_t *output, const uint8_t *input);
static void mixColumn(uint8_t *output, uint8_t *input);
static void inverseMixColumn(uint8_t *output, const uint8_t *input);
static void keyScheduleCore(uint8_t *output, const uint8_t *input, uint8_t iteration);
static void applySbox(uint8_t *output, const uint8_t *input);
/** @endcond */
friend class AESTiny128;
friend class AESTiny256;
friend class AESSmall128;
friend class AESSmall256;
};
class AES128 : public AESCommon
{
public:
AES128();
virtual ~AES128();
size_t keySize() const;
bool setKey(const uint8_t *key, size_t len);
private:
uint8_t sched[176];
};
class AES192 : public AESCommon
{
public:
AES192();
virtual ~AES192();
size_t keySize() const;
bool setKey(const uint8_t *key, size_t len);
private:
uint8_t sched[208];
};
class AES256 : public AESCommon
{
public:
AES256();
virtual ~AES256();
size_t keySize() const;
bool setKey(const uint8_t *key, size_t len);
private:
uint8_t sched[240];
};
class AESTiny256 : public BlockCipher
{
public:
AESTiny256();
virtual ~AESTiny256();
size_t blockSize() const;
size_t keySize() const;
bool setKey(const uint8_t *key, size_t len);
void encryptBlock(uint8_t *output, const uint8_t *input);
void decryptBlock(uint8_t *output, const uint8_t *input);
void clear();
private:
uint8_t schedule[32];
};
class AESSmall256 : public AESTiny256
{
public:
AESSmall256();
virtual ~AESSmall256();
bool setKey(const uint8_t *key, size_t len);
void decryptBlock(uint8_t *output, const uint8_t *input);
void clear();
private:
uint8_t reverse[32];
};
class AESTiny128 : public BlockCipher
{
public:
AESTiny128();
virtual ~AESTiny128();
size_t blockSize() const;
size_t keySize() const;
bool setKey(const uint8_t *key, size_t len);
void encryptBlock(uint8_t *output, const uint8_t *input);
void decryptBlock(uint8_t *output, const uint8_t *input);
void clear();
private:
uint8_t schedule[16];
};
class AESSmall128 : public AESTiny128
{
public:
AESSmall128();
virtual ~AESSmall128();
bool setKey(const uint8_t *key, size_t len);
void decryptBlock(uint8_t *output, const uint8_t *input);
void clear();
private:
uint8_t reverse[16];
};
#endif // CRYPTO_AES_DEFAULT
#if defined(CRYPTO_AES_ESP32)
/** @cond aes_esp_rename */
// The esp32 SDK keeps moving where aes.h is located, so we have to
// declare the API functions ourselves and make the context opaque.
//
// About the only thing the various SDK versions agree on is that the
// first byte is the length of the key in bytes.
//
// Some versions of esp-idf have a 33 byte AES context, and others 34.
// Allocate up to 40 to make space for future expansion.
#define CRYPTO_ESP32_CONTEXT_SIZE 40
// Some of the esp-idf system headers define enumerations for AES128,
// AES192, and AES256 to identify the hardware-accelerated algorithms.
// These can cause conflicts with the names we use in our library.
// Define our class names to something else to work around esp-idf.
#undef AES128
#undef AES192
#undef AES256
#define AES128 AES128_ESP
#define AES192 AES192_ESP
#define AES256 AES256_ESP
/** @endcond */
class AESCommon : public BlockCipher
{
public:
virtual ~AESCommon();
size_t blockSize() const;
size_t keySize() const;
bool setKey(const uint8_t *key, size_t len);
void encryptBlock(uint8_t *output, const uint8_t *input);
void decryptBlock(uint8_t *output, const uint8_t *input);
void clear();
protected:
AESCommon(uint8_t keySize);
private:
uint8_t ctx[CRYPTO_ESP32_CONTEXT_SIZE];
};
class AES128 : public AESCommon
{
public:
AES128() : AESCommon(16) {}
virtual ~AES128();
};
class AES192 : public AESCommon
{
public:
AES192() : AESCommon(24) {}
virtual ~AES192();
};
class AES256 : public AESCommon
{
public:
AES256() : AESCommon(32) {}
virtual ~AES256();
};
// The ESP32 AES context is so small that it already qualifies as "tiny".
typedef AES128 AESTiny128;
typedef AES256 AESTiny256;
typedef AES128 AESSmall128;
typedef AES256 AESSmall256;
#endif // CRYPTO_AES_ESP32
#endif
+356
View File
@@ -0,0 +1,356 @@
/*
* Copyright (C) 2015,2018 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 "AES.h"
#include "Crypto.h"
#include <string.h>
#if defined(CRYPTO_AES_DEFAULT) || defined(CRYPTO_DOC)
/**
* \class AES128 AES.h <AES.h>
* \brief AES block cipher with 128-bit keys.
*
* \sa AES192, AES256, AESTiny128, AESSmall128
*/
/**
* \brief Constructs an AES 128-bit block cipher with no initial key.
*
* This constructor must be followed by a call to setKey() before the
* block cipher can be used for encryption or decryption.
*/
AES128::AES128()
{
rounds = 10;
schedule = sched;
}
AES128::~AES128()
{
clean(sched);
}
/**
* \brief Size of a 128-bit AES key in bytes.
* \return Always returns 16.
*/
size_t AES128::keySize() const
{
return 16;
}
bool AES128::setKey(const uint8_t *key, size_t len)
{
if (len != 16)
return false;
// Copy the key itself into the first 16 bytes of the schedule.
uint8_t *schedule = sched;
memcpy(schedule, key, 16);
// Expand the key schedule until we have 176 bytes of expanded key.
uint8_t iteration = 1;
uint8_t n = 16;
uint8_t w = 4;
while (n < 176) {
if (w == 4) {
// Every 16 bytes (4 words) we need to apply the key schedule core.
keyScheduleCore(schedule + 16, schedule + 12, iteration);
schedule[16] ^= schedule[0];
schedule[17] ^= schedule[1];
schedule[18] ^= schedule[2];
schedule[19] ^= schedule[3];
++iteration;
w = 0;
} else {
// Otherwise just XOR the word with the one 16 bytes previous.
schedule[16] = schedule[12] ^ schedule[0];
schedule[17] = schedule[13] ^ schedule[1];
schedule[18] = schedule[14] ^ schedule[2];
schedule[19] = schedule[15] ^ schedule[3];
}
// Advance to the next word in the schedule.
schedule += 4;
n += 4;
++w;
}
return true;
}
/**
* \class AESTiny128 AES.h <AES.h>
* \brief AES block cipher with 128-bit keys and tiny memory usage.
*
* This class differs from the AES128 class in the following ways:
*
* \li RAM requirements are vastly reduced. The key is stored directly
* and then expanded to the full key schedule round by round. The setKey()
* method is very fast because of this.
* \li Performance of encryptBlock() is slower than for AES128 due to
* expanding the key on the fly rather than ahead of time.
* \li The decryptBlock() function is not supported, which means that CBC
* mode cannot be used but the CTR, CFB, OFB, EAX, and GCM modes can be used.
*
* This class is useful when RAM is at a premium, CBC mode is not required,
* and reduced encryption performance is not a hindrance to the application.
*
* The companion AESSmall128 class supports decryptBlock() at the cost of
* some additional memory and slower setKey() times.
*
* \sa AESSmall128, AES128
*/
/** @cond */
// Helper macros.
#define KCORE(n) \
do { \
AESCommon::keyScheduleCore(temp, schedule + 12, (n)); \
schedule[0] ^= temp[0]; \
schedule[1] ^= temp[1]; \
schedule[2] ^= temp[2]; \
schedule[3] ^= temp[3]; \
} while (0)
#define KXOR(a, b) \
do { \
schedule[(a) * 4] ^= schedule[(b) * 4]; \
schedule[(a) * 4 + 1] ^= schedule[(b) * 4 + 1]; \
schedule[(a) * 4 + 2] ^= schedule[(b) * 4 + 2]; \
schedule[(a) * 4 + 3] ^= schedule[(b) * 4 + 3]; \
} while (0)
/** @endcond */
/**
* \brief Constructs an AES 128-bit block cipher with no initial key.
*
* This constructor must be followed by a call to setKey() before the
* block cipher can be used for encryption or decryption.
*/
AESTiny128::AESTiny128()
{
}
AESTiny128::~AESTiny128()
{
clean(schedule);
}
/**
* \brief Size of an AES block in bytes.
* \return Always returns 16.
*/
size_t AESTiny128::blockSize() const
{
return 16;
}
/**
* \brief Size of a 128-bit AES key in bytes.
* \return Always returns 16.
*/
size_t AESTiny128::keySize() const
{
return 16;
}
bool AESTiny128::setKey(const uint8_t *key, size_t len)
{
if (len == 16) {
// Make a copy of the key - it will be expanded in encryptBlock().
memcpy(schedule, key, 16);
return true;
}
return false;
}
void AESTiny128::encryptBlock(uint8_t *output, const uint8_t *input)
{
uint8_t schedule[16];
uint8_t posn;
uint8_t round;
uint8_t state1[16];
uint8_t state2[16];
uint8_t temp[4];
// Start with the key in the schedule buffer.
memcpy(schedule, this->schedule, 16);
// Copy the input into the state and XOR with the key schedule.
for (posn = 0; posn < 16; ++posn)
state1[posn] = input[posn] ^ schedule[posn];
// Perform the first 9 rounds of the cipher.
for (round = 1; round <= 9; ++round) {
// Expand the next 16 bytes of the key schedule.
KCORE(round);
KXOR(1, 0);
KXOR(2, 1);
KXOR(3, 2);
// Encrypt using the key schedule.
AESCommon::subBytesAndShiftRows(state2, state1);
AESCommon::mixColumn(state1, state2);
AESCommon::mixColumn(state1 + 4, state2 + 4);
AESCommon::mixColumn(state1 + 8, state2 + 8);
AESCommon::mixColumn(state1 + 12, state2 + 12);
for (posn = 0; posn < 16; ++posn)
state1[posn] ^= schedule[posn];
}
// Expand the final 16 bytes of the key schedule.
KCORE(10);
KXOR(1, 0);
KXOR(2, 1);
KXOR(3, 2);
// Perform the final round.
AESCommon::subBytesAndShiftRows(state2, state1);
for (posn = 0; posn < 16; ++posn)
output[posn] = state2[posn] ^ schedule[posn];
}
void AESTiny128::decryptBlock(uint8_t *output, const uint8_t *input)
{
// Decryption is not supported by AESTiny128.
}
void AESTiny128::clear()
{
clean(schedule);
}
/**
* \class AESSmall128 AES.h <AES.h>
* \brief AES block cipher with 128-bit keys and reduced memory usage.
*
* This class differs from the AES128 class in that the RAM requirements are
* vastly reduced. The key schedule is expanded round by round instead of
* being generated and stored by setKey(). The performance of encryption
* and decryption is slightly less because of this.
*
* This class is useful when RAM is at a premium and reduced encryption
* performance is not a hindrance to the application.
*
* The companion AESTiny128 class uses even less RAM but only supports the
* encryptBlock() operation. Block cipher modes like CTR, EAX, and GCM
* do not need the decryptBlock() operation, so AESTiny128 may be a better
* option than AESSmall128 for many applications.
*
* \sa AESTiny128, AES128
*/
/**
* \brief Constructs an AES 128-bit block cipher with no initial key.
*
* This constructor must be followed by a call to setKey() before the
* block cipher can be used for encryption or decryption.
*/
AESSmall128::AESSmall128()
{
}
AESSmall128::~AESSmall128()
{
clean(reverse);
}
bool AESSmall128::setKey(const uint8_t *key, size_t len)
{
uint8_t *schedule;
uint8_t round;
uint8_t temp[4];
// Set the encryption key first.
if (!AESTiny128::setKey(key, len))
return false;
// Expand the key schedule up to the last round which gives
// us the round keys to use for the final two rounds. We can
// then work backwards from there in decryptBlock().
schedule = reverse;
memcpy(schedule, key, 16);
for (round = 1; round <= 10; ++round) {
KCORE(round);
KXOR(1, 0);
KXOR(2, 1);
KXOR(3, 2);
}
// Key is ready to go.
return true;
}
void AESSmall128::decryptBlock(uint8_t *output, const uint8_t *input)
{
uint8_t schedule[16];
uint8_t round;
uint8_t posn;
uint8_t state1[16];
uint8_t state2[16];
uint8_t temp[4];
// Start with the end of the decryption schedule.
memcpy(schedule, reverse, 16);
// Copy the input into the state and reverse the final round.
for (posn = 0; posn < 16; ++posn)
state1[posn] = input[posn] ^ schedule[posn];
AESCommon::inverseShiftRowsAndSubBytes(state2, state1);
KXOR(3, 2);
KXOR(2, 1);
KXOR(1, 0);
KCORE(10);
// Perform the next 9 rounds of the decryption process.
for (round = 9; round >= 1; --round) {
// Decrypt using the key schedule.
for (posn = 0; posn < 16; ++posn)
state2[posn] ^= schedule[posn];
AESCommon::inverseMixColumn(state1, state2);
AESCommon::inverseMixColumn(state1 + 4, state2 + 4);
AESCommon::inverseMixColumn(state1 + 8, state2 + 8);
AESCommon::inverseMixColumn(state1 + 12, state2 + 12);
AESCommon::inverseShiftRowsAndSubBytes(state2, state1);
// Expand the next 16 bytes of the key schedule in reverse.
KXOR(3, 2);
KXOR(2, 1);
KXOR(1, 0);
KCORE(round);
}
// Reverse the initial round and create the output words.
for (posn = 0; posn < 16; ++posn)
output[posn] = state2[posn] ^ schedule[posn];
}
void AESSmall128::clear()
{
clean(reverse);
AESTiny128::clear();
}
#endif // CRYPTO_AES_DEFAULT
+363
View File
@@ -0,0 +1,363 @@
/*
* 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 "AES.h"
#include "Crypto.h"
#include "utility/ProgMemUtil.h"
#if defined(CRYPTO_AES_DEFAULT) || defined(CRYPTO_DOC)
/**
* \class AESCommon AES.h <AES.h>
* \brief Abstract base class for AES block ciphers.
*
* This class is abstract. The caller should instantiate AES128,
* AES192, or AES256 to create an AES block cipher with a specific
* key size.
*
* \note This AES implementation does not have constant cache behaviour due
* to the use of table lookups. It may not be safe to use this implementation
* in an environment where the attacker can observe the timing of encryption
* and decryption operations. Unless AES compatibility is required,
* it is recommended that the ChaCha stream cipher be used instead.
*
* Reference: http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
*
* \sa ChaCha, AES128, AES192, AES256
*/
/** @cond sbox */
// 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
0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, // 0x10
0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, // 0x20
0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, // 0x30
0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, // 0x40
0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, // 0x50
0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, // 0x60
0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, // 0x70
0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, // 0x80
0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, // 0x90
0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, // 0xA0
0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, // 0xB0
0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, // 0xC0
0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, // 0xD0
0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, // 0xE0
0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, // 0xF0
0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
// AES inverse S-box (http://en.wikipedia.org/wiki/Rijndael_S-box)
static uint8_t const sbox_inverse[256] PROGMEM = {
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, // 0x00
0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, // 0x10
0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, // 0x20
0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, // 0x30
0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, // 0x40
0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, // 0x50
0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, // 0x60
0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, // 0x70
0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, // 0x80
0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, // 0x90
0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, // 0xA0
0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, // 0xB0
0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, // 0xC0
0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, // 0xD0
0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, // 0xE0
0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, // 0xF0
0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
};
/** @endcond */
/**
* \brief Constructs an AES block cipher object.
*/
AESCommon::AESCommon()
: rounds(0), schedule(0)
{
}
/**
* \brief Destroys this AES block cipher object after clearing
* sensitive information.
*/
AESCommon::~AESCommon()
{
}
/**
* \brief Size of an AES block in bytes.
* \return Always returns 16.
*/
size_t AESCommon::blockSize() const
{
return 16;
}
// Constants to correct Galois multiplication for the high bits
// that are shifted out when multiplying by powers of two.
static uint8_t const K[8] = {
0x00,
0x1B,
(0x1B << 1),
(0x1B << 1) ^ 0x1B,
(0x1B << 2),
(0x1B << 2) ^ 0x1B,
(0x1B << 2) ^ (0x1B << 1),
(0x1B << 2) ^ (0x1B << 1) ^ 0x1B
};
// Multiply x by 2 in the Galois field, to achieve the effect of the following:
//
// if (x & 0x80)
// return (x << 1) ^ 0x1B;
// else
// return (x << 1);
//
// However, we don't want to use runtime conditionals if we can help it
// to avoid leaking timing information from the implementation.
// In this case, multiplication is slightly faster than table lookup on AVR.
#define gmul2(x) (t = ((uint16_t)(x)) << 1, \
((uint8_t)t) ^ (uint8_t)(0x1B * ((uint8_t)(t >> 8))))
// Multiply x by 4 in the Galois field.
#define gmul4(x) (t = ((uint16_t)(x)) << 2, ((uint8_t)t) ^ K[t >> 8])
// Multiply x by 8 in the Galois field.
#define gmul8(x) (t = ((uint16_t)(x)) << 3, ((uint8_t)t) ^ K[t >> 8])
#define OUT(col, row) output[(col) * 4 + (row)]
#define IN(col, row) input[(col) * 4 + (row)]
/** @cond aes_funcs */
void AESCommon::subBytesAndShiftRows(uint8_t *output, const uint8_t *input)
{
OUT(0, 0) = pgm_read_byte(sbox + IN(0, 0));
OUT(0, 1) = pgm_read_byte(sbox + IN(1, 1));
OUT(0, 2) = pgm_read_byte(sbox + IN(2, 2));
OUT(0, 3) = pgm_read_byte(sbox + IN(3, 3));
OUT(1, 0) = pgm_read_byte(sbox + IN(1, 0));
OUT(1, 1) = pgm_read_byte(sbox + IN(2, 1));
OUT(1, 2) = pgm_read_byte(sbox + IN(3, 2));
OUT(1, 3) = pgm_read_byte(sbox + IN(0, 3));
OUT(2, 0) = pgm_read_byte(sbox + IN(2, 0));
OUT(2, 1) = pgm_read_byte(sbox + IN(3, 1));
OUT(2, 2) = pgm_read_byte(sbox + IN(0, 2));
OUT(2, 3) = pgm_read_byte(sbox + IN(1, 3));
OUT(3, 0) = pgm_read_byte(sbox + IN(3, 0));
OUT(3, 1) = pgm_read_byte(sbox + IN(0, 1));
OUT(3, 2) = pgm_read_byte(sbox + IN(1, 2));
OUT(3, 3) = pgm_read_byte(sbox + IN(2, 3));
}
void AESCommon::inverseShiftRowsAndSubBytes(uint8_t *output, const uint8_t *input)
{
OUT(0, 0) = pgm_read_byte(sbox_inverse + IN(0, 0));
OUT(0, 1) = pgm_read_byte(sbox_inverse + IN(3, 1));
OUT(0, 2) = pgm_read_byte(sbox_inverse + IN(2, 2));
OUT(0, 3) = pgm_read_byte(sbox_inverse + IN(1, 3));
OUT(1, 0) = pgm_read_byte(sbox_inverse + IN(1, 0));
OUT(1, 1) = pgm_read_byte(sbox_inverse + IN(0, 1));
OUT(1, 2) = pgm_read_byte(sbox_inverse + IN(3, 2));
OUT(1, 3) = pgm_read_byte(sbox_inverse + IN(2, 3));
OUT(2, 0) = pgm_read_byte(sbox_inverse + IN(2, 0));
OUT(2, 1) = pgm_read_byte(sbox_inverse + IN(1, 1));
OUT(2, 2) = pgm_read_byte(sbox_inverse + IN(0, 2));
OUT(2, 3) = pgm_read_byte(sbox_inverse + IN(3, 3));
OUT(3, 0) = pgm_read_byte(sbox_inverse + IN(3, 0));
OUT(3, 1) = pgm_read_byte(sbox_inverse + IN(2, 1));
OUT(3, 2) = pgm_read_byte(sbox_inverse + IN(1, 2));
OUT(3, 3) = pgm_read_byte(sbox_inverse + IN(0, 3));
}
void AESCommon::mixColumn(uint8_t *output, uint8_t *input)
{
uint16_t t; // Needed by the gmul2 macro.
uint8_t a = input[0];
uint8_t b = input[1];
uint8_t c = input[2];
uint8_t d = input[3];
uint8_t a2 = gmul2(a);
uint8_t b2 = gmul2(b);
uint8_t c2 = gmul2(c);
uint8_t d2 = gmul2(d);
output[0] = a2 ^ b2 ^ b ^ c ^ d;
output[1] = a ^ b2 ^ c2 ^ c ^ d;
output[2] = a ^ b ^ c2 ^ d2 ^ d;
output[3] = a2 ^ a ^ b ^ c ^ d2;
}
void AESCommon::inverseMixColumn(uint8_t *output, const uint8_t *input)
{
uint16_t t; // Needed by the gmul2, gmul4, and gmul8 macros.
uint8_t a = input[0];
uint8_t b = input[1];
uint8_t c = input[2];
uint8_t d = input[3];
uint8_t a2 = gmul2(a);
uint8_t b2 = gmul2(b);
uint8_t c2 = gmul2(c);
uint8_t d2 = gmul2(d);
uint8_t a4 = gmul4(a);
uint8_t b4 = gmul4(b);
uint8_t c4 = gmul4(c);
uint8_t d4 = gmul4(d);
uint8_t a8 = gmul8(a);
uint8_t b8 = gmul8(b);
uint8_t c8 = gmul8(c);
uint8_t d8 = gmul8(d);
output[0] = a8 ^ a4 ^ a2 ^ b8 ^ b2 ^ b ^ c8 ^ c4 ^ c ^ d8 ^ d;
output[1] = a8 ^ a ^ b8 ^ b4 ^ b2 ^ c8 ^ c2 ^ c ^ d8 ^ d4 ^ d;
output[2] = a8 ^ a4 ^ a ^ b8 ^ b ^ c8 ^ c4 ^ c2 ^ d8 ^ d2 ^ d;
output[3] = a8 ^ a2 ^ a ^ b8 ^ b4 ^ b ^ c8 ^ c ^ d8 ^ d4 ^ d2;
}
/** @endcond */
void AESCommon::encryptBlock(uint8_t *output, const uint8_t *input)
{
const uint8_t *roundKey = schedule;
uint8_t posn;
uint8_t round;
uint8_t state1[16];
uint8_t state2[16];
// Copy the input into the state and XOR with the first round key.
for (posn = 0; posn < 16; ++posn)
state1[posn] = input[posn] ^ roundKey[posn];
roundKey += 16;
// Perform all rounds except the last.
for (round = rounds; round > 1; --round) {
subBytesAndShiftRows(state2, state1);
mixColumn(state1, state2);
mixColumn(state1 + 4, state2 + 4);
mixColumn(state1 + 8, state2 + 8);
mixColumn(state1 + 12, state2 + 12);
for (posn = 0; posn < 16; ++posn)
state1[posn] ^= roundKey[posn];
roundKey += 16;
}
// Perform the final round.
subBytesAndShiftRows(state2, state1);
for (posn = 0; posn < 16; ++posn)
output[posn] = state2[posn] ^ roundKey[posn];
}
void AESCommon::decryptBlock(uint8_t *output, const uint8_t *input)
{
const uint8_t *roundKey = schedule + rounds * 16;
uint8_t round;
uint8_t posn;
uint8_t state1[16];
uint8_t state2[16];
// Copy the input into the state and reverse the final round.
for (posn = 0; posn < 16; ++posn)
state1[posn] = input[posn] ^ roundKey[posn];
inverseShiftRowsAndSubBytes(state2, state1);
// Perform all other rounds in reverse.
for (round = rounds; round > 1; --round) {
roundKey -= 16;
for (posn = 0; posn < 16; ++posn)
state2[posn] ^= roundKey[posn];
inverseMixColumn(state1, state2);
inverseMixColumn(state1 + 4, state2 + 4);
inverseMixColumn(state1 + 8, state2 + 8);
inverseMixColumn(state1 + 12, state2 + 12);
inverseShiftRowsAndSubBytes(state2, state1);
}
// Reverse the initial round and create the output words.
roundKey -= 16;
for (posn = 0; posn < 16; ++posn)
output[posn] = state2[posn] ^ roundKey[posn];
}
void AESCommon::clear()
{
clean(schedule, (rounds + 1) * 16);
}
/** @cond aes_keycore */
void AESCommon::keyScheduleCore(uint8_t *output, const uint8_t *input, uint8_t iteration)
{
// Rcon(i), 2^i in the Rijndael finite field, for i = 0..10.
// http://en.wikipedia.org/wiki/Rijndael_key_schedule
static uint8_t const rcon[11] PROGMEM = {
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, // 0x00
0x80, 0x1B, 0x36
};
output[0] = pgm_read_byte(sbox + input[1]) ^ pgm_read_byte(rcon + iteration);
output[1] = pgm_read_byte(sbox + input[2]);
output[2] = pgm_read_byte(sbox + input[3]);
output[3] = pgm_read_byte(sbox + input[0]);
}
void AESCommon::applySbox(uint8_t *output, const uint8_t *input)
{
output[0] = pgm_read_byte(sbox + input[0]);
output[1] = pgm_read_byte(sbox + input[1]);
output[2] = pgm_read_byte(sbox + input[2]);
output[3] = pgm_read_byte(sbox + input[3]);
}
/** @endcond */
#endif // CRYPTO_AES_DEFAULT
+769
View File
@@ -0,0 +1,769 @@
/*
* 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 "BigNumberUtil.h"
#include "utility/EndianUtil.h"
#include "utility/LimbUtil.h"
#include <string.h>
/**
* \class BigNumberUtil BigNumberUtil.h <BigNumberUtil.h>
* \brief Utilities to assist with implementing big number arithmetic.
*
* Big numbers are represented as arrays of limb_t words, which may be
* 8 bits, 16 bits, or 32 bits in size depending upon how the library
* was configured. For AVR, 16 bit limbs usually give the best performance.
*
* Limb arrays are ordered from the least significant word to the most
* significant.
*/
/**
* \brief Unpacks the little-endian byte representation of a big number
* into a limb array.
*
* \param limbs The limb array, starting with the least significant word.
* \param count The number of elements in the \a limbs array.
* \param bytes The bytes to unpack.
* \param len The number of bytes to unpack.
*
* If \a len is shorter than the length of \a limbs, then the high bytes
* will be filled with zeroes. If \a len is longer than the length of
* \a limbs, then the high bytes will be truncated and lost.
*
* \sa packLE(), unpackBE()
*/
void BigNumberUtil::unpackLE(limb_t *limbs, size_t count,
const uint8_t *bytes, size_t len)
{
#if BIGNUMBER_LIMB_8BIT
if (len < count) {
memcpy(limbs, bytes, len);
memset(limbs + len, 0, count - len);
} else {
memcpy(limbs, bytes, count);
}
#elif CRYPTO_LITTLE_ENDIAN
count *= sizeof(limb_t);
if (len < count) {
memcpy(limbs, bytes, len);
memset(((uint8_t *)limbs) + len, 0, count - len);
} else {
memcpy(limbs, bytes, count);
}
#elif BIGNUMBER_LIMB_16BIT
while (count > 0 && len >= 2) {
*limbs++ = ((limb_t)(bytes[0])) |
(((limb_t)(bytes[1])) << 8);
bytes += 2;
--count;
len -= 2;
}
if (count > 0 && len == 1) {
*limbs++ = ((limb_t)(bytes[0]));
--count;
}
while (count > 0) {
*limbs++ = 0;
--count;
}
#elif BIGNUMBER_LIMB_32BIT
while (count > 0 && len >= 4) {
*limbs++ = ((limb_t)(bytes[0])) |
(((limb_t)(bytes[1])) << 8) |
(((limb_t)(bytes[2])) << 16) |
(((limb_t)(bytes[3])) << 24);
bytes += 4;
--count;
len -= 4;
}
if (count > 0 && len > 0) {
if (len == 3) {
*limbs++ = ((limb_t)(bytes[0])) |
(((limb_t)(bytes[1])) << 8) |
(((limb_t)(bytes[2])) << 16);
} else if (len == 2) {
*limbs++ = ((limb_t)(bytes[0])) |
(((limb_t)(bytes[1])) << 8);
} else {
*limbs++ = ((limb_t)(bytes[0]));
}
--count;
}
while (count > 0) {
*limbs++ = 0;
--count;
}
#elif BIGNUMBER_LIMB_64BIT
while (count > 0 && len >= 8) {
*limbs++ = ((limb_t)(bytes[0])) |
(((limb_t)(bytes[1])) << 8) |
(((limb_t)(bytes[2])) << 16) |
(((limb_t)(bytes[3])) << 24) |
(((limb_t)(bytes[4])) << 32) |
(((limb_t)(bytes[5])) << 40) |
(((limb_t)(bytes[6])) << 48) |
(((limb_t)(bytes[7])) << 56);
bytes += 8;
--count;
len -= 8;
}
if (count > 0 && len > 0) {
limb_t word = 0;
uint8_t shift = 0;
while (len > 0 && shift < 64) {
word |= (((limb_t)(*bytes++)) << shift);
shift += 8;
--len;
}
*limbs++ = word;
--count;
}
while (count > 0) {
*limbs++ = 0;
--count;
}
#endif
}
/**
* \brief Unpacks the big-endian byte representation of a big number
* into a limb array.
*
* \param limbs The limb array, starting with the least significant word.
* \param count The number of elements in the \a limbs array.
* \param bytes The bytes to unpack.
* \param len The number of bytes to unpack.
*
* If \a len is shorter than the length of \a limbs, then the high bytes
* will be filled with zeroes. If \a len is longer than the length of
* \a limbs, then the high bytes will be truncated and lost.
*
* \sa packBE(), unpackLE()
*/
void BigNumberUtil::unpackBE(limb_t *limbs, size_t count,
const uint8_t *bytes, size_t len)
{
#if BIGNUMBER_LIMB_8BIT
while (count > 0 && len > 0) {
--count;
--len;
*limbs++ = bytes[len];
}
memset(limbs, 0, count);
#elif BIGNUMBER_LIMB_16BIT
bytes += len;
while (count > 0 && len >= 2) {
--count;
bytes -= 2;
len -= 2;
*limbs++ = ((limb_t)(bytes[1])) |
(((limb_t)(bytes[0])) << 8);
}
if (count > 0 && len == 1) {
--count;
--bytes;
*limbs++ = (limb_t)(bytes[0]);
}
memset(limbs, 0, count * sizeof(limb_t));
#elif BIGNUMBER_LIMB_32BIT
bytes += len;
while (count > 0 && len >= 4) {
--count;
bytes -= 4;
len -= 4;
*limbs++ = ((limb_t)(bytes[3])) |
(((limb_t)(bytes[2])) << 8) |
(((limb_t)(bytes[1])) << 16) |
(((limb_t)(bytes[0])) << 24);
}
if (count > 0) {
if (len == 3) {
--count;
bytes -= 3;
*limbs++ = ((limb_t)(bytes[2])) |
(((limb_t)(bytes[1])) << 8) |
(((limb_t)(bytes[0])) << 16);
} else if (len == 2) {
--count;
bytes -= 2;
*limbs++ = ((limb_t)(bytes[1])) |
(((limb_t)(bytes[0])) << 8);
} else if (len == 1) {
--count;
--bytes;
*limbs++ = (limb_t)(bytes[0]);
}
}
memset(limbs, 0, count * sizeof(limb_t));
#elif BIGNUMBER_LIMB_64BIT
bytes += len;
while (count > 0 && len >= 8) {
--count;
bytes -= 8;
len -= 8;
*limbs++ = ((limb_t)(bytes[7])) |
(((limb_t)(bytes[6])) << 8) |
(((limb_t)(bytes[5])) << 16) |
(((limb_t)(bytes[4])) << 24) |
(((limb_t)(bytes[3])) << 32) |
(((limb_t)(bytes[2])) << 40) |
(((limb_t)(bytes[1])) << 48) |
(((limb_t)(bytes[0])) << 56);
}
if (count > 0 && len > 0) {
limb_t word = 0;
uint8_t shift = 0;
while (len > 0 && shift < 64) {
word |= (((limb_t)(*(--bytes))) << shift);
shift += 8;
--len;
}
*limbs++ = word;
--count;
}
memset(limbs, 0, count * sizeof(limb_t));
#endif
}
/**
* \brief Packs the little-endian byte representation of a big number
* into a byte array.
*
* \param bytes The byte array to pack into.
* \param len The number of bytes in the destination \a bytes array.
* \param limbs The limb array representing the big number, starting with
* the least significant word.
* \param count The number of elements in the \a limbs array.
*
* If \a len is shorter than the length of \a limbs, then the number will
* be truncated to the least significant \a len bytes. If \a len is longer
* than the length of \a limbs, then the high bytes will be filled with zeroes.
*
* \sa unpackLE(), packBE()
*/
void BigNumberUtil::packLE(uint8_t *bytes, size_t len,
const limb_t *limbs, size_t count)
{
#if BIGNUMBER_LIMB_8BIT
if (len <= count) {
memcpy(bytes, limbs, len);
} else {
memcpy(bytes, limbs, count);
memset(bytes + count, 0, len - count);
}
#elif CRYPTO_LITTLE_ENDIAN
count *= sizeof(limb_t);
if (len <= count) {
memcpy(bytes, limbs, len);
} else {
memcpy(bytes, limbs, count);
memset(bytes + count, 0, len - count);
}
#elif BIGNUMBER_LIMB_16BIT
limb_t word;
while (count > 0 && len >= 2) {
word = *limbs++;
bytes[0] = (uint8_t)word;
bytes[1] = (uint8_t)(word >> 8);
--count;
len -= 2;
bytes += 2;
}
if (count > 0 && len == 1) {
bytes[0] = (uint8_t)(*limbs);
--len;
++bytes;
}
memset(bytes, 0, len);
#elif BIGNUMBER_LIMB_32BIT
limb_t word;
while (count > 0 && len >= 4) {
word = *limbs++;
bytes[0] = (uint8_t)word;
bytes[1] = (uint8_t)(word >> 8);
bytes[2] = (uint8_t)(word >> 16);
bytes[3] = (uint8_t)(word >> 24);
--count;
len -= 4;
bytes += 4;
}
if (count > 0) {
if (len == 3) {
word = *limbs;
bytes[0] = (uint8_t)word;
bytes[1] = (uint8_t)(word >> 8);
bytes[2] = (uint8_t)(word >> 16);
len -= 3;
bytes += 3;
} else if (len == 2) {
word = *limbs;
bytes[0] = (uint8_t)word;
bytes[1] = (uint8_t)(word >> 8);
len -= 2;
bytes += 2;
} else if (len == 1) {
bytes[0] = (uint8_t)(*limbs);
--len;
++bytes;
}
}
memset(bytes, 0, len);
#elif BIGNUMBER_LIMB_64BIT
limb_t word;
while (count > 0 && len >= 8) {
word = *limbs++;
bytes[0] = (uint8_t)word;
bytes[1] = (uint8_t)(word >> 8);
bytes[2] = (uint8_t)(word >> 16);
bytes[3] = (uint8_t)(word >> 24);
bytes[4] = (uint8_t)(word >> 32);
bytes[5] = (uint8_t)(word >> 40);
bytes[6] = (uint8_t)(word >> 48);
bytes[7] = (uint8_t)(word >> 56);
--count;
len -= 8;
bytes += 8;
}
if (count > 0) {
word = *limbs;
while (len > 0) {
*bytes++ = (uint8_t)word;
word >>= 8;
--len;
}
}
memset(bytes, 0, len);
#endif
}
/**
* \brief Packs the big-endian byte representation of a big number
* into a byte array.
*
* \param bytes The byte array to pack into.
* \param len The number of bytes in the destination \a bytes array.
* \param limbs The limb array representing the big number, starting with
* the least significant word.
* \param count The number of elements in the \a limbs array.
*
* If \a len is shorter than the length of \a limbs, then the number will
* be truncated to the least significant \a len bytes. If \a len is longer
* than the length of \a limbs, then the high bytes will be filled with zeroes.
*
* \sa unpackLE(), packBE()
*/
void BigNumberUtil::packBE(uint8_t *bytes, size_t len,
const limb_t *limbs, size_t count)
{
#if BIGNUMBER_LIMB_8BIT
if (len > count) {
size_t size = len - count;
memset(bytes, 0, size);
len -= size;
bytes += size;
} else if (len < count) {
count = len;
}
limbs += count;
while (count > 0) {
--count;
*bytes++ = *(--limbs);
}
#elif BIGNUMBER_LIMB_16BIT
size_t countBytes = count * sizeof(limb_t);
limb_t word;
if (len >= countBytes) {
size_t size = len - countBytes;
memset(bytes, 0, size);
len -= size;
bytes += size;
limbs += count;
} else {
count = len / sizeof(limb_t);
limbs += count;
if ((len & 1) != 0)
*bytes++ = (uint8_t)(*limbs);
}
while (count > 0) {
--count;
word = *(--limbs);
*bytes++ = (uint8_t)(word >> 8);
*bytes++ = (uint8_t)word;
}
#elif BIGNUMBER_LIMB_32BIT
size_t countBytes = count * sizeof(limb_t);
limb_t word;
if (len >= countBytes) {
size_t size = len - countBytes;
memset(bytes, 0, size);
len -= size;
bytes += size;
limbs += count;
} else {
count = len / sizeof(limb_t);
limbs += count;
if ((len & 3) == 3) {
word = *limbs;
*bytes++ = (uint8_t)(word >> 16);
*bytes++ = (uint8_t)(word >> 8);
*bytes++ = (uint8_t)word;
} else if ((len & 3) == 2) {
word = *limbs;
*bytes++ = (uint8_t)(word >> 8);
*bytes++ = (uint8_t)word;
} else if ((len & 3) == 1) {
*bytes++ = (uint8_t)(*limbs);
}
}
while (count > 0) {
--count;
word = *(--limbs);
*bytes++ = (uint8_t)(word >> 24);
*bytes++ = (uint8_t)(word >> 16);
*bytes++ = (uint8_t)(word >> 8);
*bytes++ = (uint8_t)word;
}
#elif BIGNUMBER_LIMB_64BIT
size_t countBytes = count * sizeof(limb_t);
limb_t word;
if (len >= countBytes) {
size_t size = len - countBytes;
memset(bytes, 0, size);
len -= size;
bytes += size;
limbs += count;
} else {
count = len / sizeof(limb_t);
limbs += count;
uint8_t size = len & 7;
uint8_t shift = size * 8;
word = *limbs;
while (size > 0) {
shift -= 8;
*bytes++ = (uint8_t)(word >> shift);
--size;
}
}
while (count > 0) {
--count;
word = *(--limbs);
*bytes++ = (uint8_t)(word >> 56);
*bytes++ = (uint8_t)(word >> 48);
*bytes++ = (uint8_t)(word >> 40);
*bytes++ = (uint8_t)(word >> 32);
*bytes++ = (uint8_t)(word >> 24);
*bytes++ = (uint8_t)(word >> 16);
*bytes++ = (uint8_t)(word >> 8);
*bytes++ = (uint8_t)word;
}
#endif
}
/**
* \brief Adds two big numbers.
*
* \param result The result of the addition. This can be the same
* as either \a x or \a y.
* \param x The first big number.
* \param y The second big number.
* \param size The size of the values in limbs.
*
* \return Returns 1 if there was a carry out or 0 if there was no carry out.
*
* \sa sub(), mul()
*/
limb_t BigNumberUtil::add(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
dlimb_t carry = 0;
while (size > 0) {
carry += *x++;
carry += *y++;
*result++ = (limb_t)carry;
carry >>= LIMB_BITS;
--size;
}
return (limb_t)carry;
}
/**
* \brief Subtracts one big number from another.
*
* \param result The result of the subtraction. This can be the same
* as either \a x or \a y.
* \param x The first big number.
* \param y The second big number to subtract from \a x.
* \param size The size of the values in limbs.
*
* \return Returns 1 if there was a borrow, or 0 if there was no borrow.
*
* \sa add(), mul()
*/
limb_t BigNumberUtil::sub(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
dlimb_t borrow = 0;
while (size > 0) {
borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
*result++ = (limb_t)borrow;
--size;
}
return ((limb_t)(borrow >> LIMB_BITS)) & 0x01;
}
/**
* \brief Multiplies two big numbers.
*
* \param result The result of the multiplication. The array must be
* \a xcount + \a ycount limbs in size.
* \param x Points to the first value to multiply.
* \param xcount The number of limbs in \a x.
* \param y Points to the second value to multiply.
* \param ycount The number of limbs in \a y.
*
* \sa mul_P()
*/
void BigNumberUtil::mul(limb_t *result, const limb_t *x, size_t xcount,
const limb_t *y, size_t ycount)
{
size_t i, j;
dlimb_t carry;
limb_t word;
const limb_t *xx;
limb_t *rr;
// Multiply the lowest limb of y by x.
carry = 0;
word = y[0];
xx = x;
rr = result;
for (i = 0; i < xcount; ++i) {
carry += ((dlimb_t)(*xx++)) * word;
*rr++ = (limb_t)carry;
carry >>= LIMB_BITS;
}
*rr = (limb_t)carry;
// Multiply and add the remaining limbs of y by x.
for (i = 1; i < ycount; ++i) {
word = y[i];
carry = 0;
xx = x;
rr = result + i;
for (j = 0; j < xcount; ++j) {
carry += ((dlimb_t)(*xx++)) * word;
carry += *rr;
*rr++ = (limb_t)carry;
carry >>= LIMB_BITS;
}
*rr = (limb_t)carry;
}
}
/**
* \brief Reduces \a x modulo \a y using subtraction.
*
* \param result The result of the reduction. This can be the
* same as \a x.
* \param x The number to be reduced.
* \param y The base to use for the modulo reduction.
* \param size The size of the values in limbs.
*
* It is assumed that \a x is less than \a y * 2 so that a single
* conditional subtraction will bring it down below \a y. The reduction
* is performed in constant time.
*
* \sa reduceQuick_P()
*/
void BigNumberUtil::reduceQuick(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
// Subtract "y" from "x" and turn the borrow into an AND mask.
limb_t mask = sub(result, x, y, size);
mask = (~mask) + 1;
// Add "y" back to the result if the mask is non-zero.
dlimb_t carry = 0;
while (size > 0) {
carry += *result;
carry += (*y++ & mask);
*result++ = (limb_t)carry;
carry >>= LIMB_BITS;
--size;
}
}
/**
* \brief Adds two big numbers where one of them is in program memory.
*
* \param result The result of the addition. This can be the same as \a x.
* \param x The first big number.
* \param y The second big number. This must point into program memory.
* \param size The size of the values in limbs.
*
* \return Returns 1 if there was a carry out or 0 if there was no carry out.
*
* \sa sub_P(), mul_P()
*/
limb_t BigNumberUtil::add_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
dlimb_t carry = 0;
while (size > 0) {
carry += *x++;
carry += pgm_read_limb(y++);
*result++ = (limb_t)carry;
carry >>= LIMB_BITS;
--size;
}
return (limb_t)carry;
}
/**
* \brief Subtracts one big number from another where one is in program memory.
*
* \param result The result of the subtraction. This can be the same as \a x.
* \param x The first big number.
* \param y The second big number to subtract from \a x. This must point
* into program memory.
* \param size The size of the values in limbs.
*
* \return Returns 1 if there was a borrow, or 0 if there was no borrow.
*
* \sa add_P(), mul_P()
*/
limb_t BigNumberUtil::sub_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
dlimb_t borrow = 0;
while (size > 0) {
borrow = ((dlimb_t)(*x++)) - pgm_read_limb(y++) - ((borrow >> LIMB_BITS) & 0x01);
*result++ = (limb_t)borrow;
--size;
}
return ((limb_t)(borrow >> LIMB_BITS)) & 0x01;
}
/**
* \brief Multiplies two big numbers where one is in program memory.
*
* \param result The result of the multiplication. The array must be
* \a xcount + \a ycount limbs in size.
* \param x Points to the first value to multiply.
* \param xcount The number of limbs in \a x.
* \param y Points to the second value to multiply. This must point
* into program memory.
* \param ycount The number of limbs in \a y.
*
* \sa mul()
*/
void BigNumberUtil::mul_P(limb_t *result, const limb_t *x, size_t xcount,
const limb_t *y, size_t ycount)
{
size_t i, j;
dlimb_t carry;
limb_t word;
const limb_t *xx;
limb_t *rr;
// Multiply the lowest limb of y by x.
carry = 0;
word = pgm_read_limb(&(y[0]));
xx = x;
rr = result;
for (i = 0; i < xcount; ++i) {
carry += ((dlimb_t)(*xx++)) * word;
*rr++ = (limb_t)carry;
carry >>= LIMB_BITS;
}
*rr = (limb_t)carry;
// Multiply and add the remaining limb of y by x.
for (i = 1; i < ycount; ++i) {
word = pgm_read_limb(&(y[i]));
carry = 0;
xx = x;
rr = result + i;
for (j = 0; j < xcount; ++j) {
carry += ((dlimb_t)(*xx++)) * word;
carry += *rr;
*rr++ = (limb_t)carry;
carry >>= LIMB_BITS;
}
*rr = (limb_t)carry;
}
}
/**
* \brief Reduces \a x modulo \a y using subtraction where \a y is
* in program memory.
*
* \param result The result of the reduction. This can be the
* same as \a x.
* \param x The number to be reduced.
* \param y The base to use for the modulo reduction. This must point
* into program memory.
* \param size The size of the values in limbs.
*
* It is assumed that \a x is less than \a y * 2 so that a single
* conditional subtraction will bring it down below \a y. The reduction
* is performed in constant time.
*
* \sa reduceQuick()
*/
void BigNumberUtil::reduceQuick_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
// Subtract "y" from "x" and turn the borrow into an AND mask.
limb_t mask = sub_P(result, x, y, size);
mask = (~mask) + 1;
// Add "y" back to the result if the mask is non-zero.
dlimb_t carry = 0;
while (size > 0) {
carry += *result;
carry += (pgm_read_limb(y++) & mask);
*result++ = (limb_t)carry;
carry >>= LIMB_BITS;
--size;
}
}
/**
* \brief Determine if a big number is zero.
*
* \param x Points to the number to test.
* \param size The number of limbs in \a x.
* \return Returns 1 if \a x is zero or 0 otherwise.
*
* This function attempts to make the determination in constant time.
*/
limb_t BigNumberUtil::isZero(const limb_t *x, size_t size)
{
limb_t word = 0;
while (size > 0) {
word |= *x++;
--size;
}
return (limb_t)(((((dlimb_t)1) << LIMB_BITS) - word) >> LIMB_BITS);
}
+110
View File
@@ -0,0 +1,110 @@
/*
* 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_BIGNUMBERUTIL_h
#define CRYPTO_BIGNUMBERUTIL_h
#include <inttypes.h>
#include <stddef.h>
// Define exactly one of these to 1 to set the size of the basic limb type.
#if defined(__AVR__) || defined(ESP8266)
// 16-bit limbs seem to give the best performance on 8-bit AVR micros.
// They also seem to give better performance on ESP8266 as well.
#define BIGNUMBER_LIMB_8BIT 0
#define BIGNUMBER_LIMB_16BIT 1
#define BIGNUMBER_LIMB_32BIT 0
#define BIGNUMBER_LIMB_64BIT 0
#elif defined(__GNUC__) && __WORDSIZE == 64
// 64-bit system with 128-bit double limbs.
#define BIGNUMBER_LIMB_8BIT 0
#define BIGNUMBER_LIMB_16BIT 0
#define BIGNUMBER_LIMB_32BIT 0
#define BIGNUMBER_LIMB_64BIT 1
#else
// On all other platforms, assume 32-bit is best.
#define BIGNUMBER_LIMB_8BIT 0
#define BIGNUMBER_LIMB_16BIT 0
#define BIGNUMBER_LIMB_32BIT 1
#define BIGNUMBER_LIMB_64BIT 0
#endif
// Define the limb types to use on this platform.
#if BIGNUMBER_LIMB_8BIT
typedef uint8_t limb_t;
typedef int8_t slimb_t;
typedef uint16_t dlimb_t;
#elif BIGNUMBER_LIMB_16BIT
typedef uint16_t limb_t;
typedef int16_t slimb_t;
typedef uint32_t dlimb_t;
#elif BIGNUMBER_LIMB_32BIT
typedef uint32_t limb_t;
typedef int32_t slimb_t;
typedef uint64_t dlimb_t;
#elif BIGNUMBER_LIMB_64BIT
typedef uint64_t limb_t;
typedef int64_t slimb_t;
typedef unsigned __int128 dlimb_t;
#else
#error "limb_t must be 8, 16, 32, or 64 bits in size"
#endif
class BigNumberUtil
{
public:
static void unpackLE(limb_t *limbs, size_t count,
const uint8_t *bytes, size_t len);
static void unpackBE(limb_t *limbs, size_t count,
const uint8_t *bytes, size_t len);
static void packLE(uint8_t *bytes, size_t len,
const limb_t *limbs, size_t count);
static void packBE(uint8_t *bytes, size_t len,
const limb_t *limbs, size_t count);
static limb_t add(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static limb_t sub(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static void mul(limb_t *result, const limb_t *x, size_t xcount,
const limb_t *y, size_t ycount);
static void reduceQuick(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static limb_t add_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static limb_t sub_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static void mul_P(limb_t *result, const limb_t *x, size_t xcount,
const limb_t *y, size_t ycount);
static void reduceQuick_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static limb_t isZero(const limb_t *x, size_t size);
private:
// Constructor and destructor are private - cannot instantiate this class.
BigNumberUtil() {}
~BigNumberUtil() {}
};
#endif
+124
View File
@@ -0,0 +1,124 @@
/*
* 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 "BlockCipher.h"
/**
* \class BlockCipher BlockCipher.h <BlockCipher.h>
* \brief Abstract base class for block ciphers.
*
* Block ciphers always operate in electronic codebook (ECB) mode.
* Higher-level classes such as CFB128 and CTR128 wrap the block cipher to
* create more useful classes for encryption and decryption of bulk data.
*
* References: http://en.wikipedia.org/wiki/Block_cipher,
* http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
*/
/**
* \brief Constructs a block cipher.
*/
BlockCipher::BlockCipher()
{
}
/**
* \brief Destroys this block cipher object.
*
* Subclasses are responsible for clearing temporary key schedules
* and other buffers so as to avoid leaking sensitive information.
*
* \sa clear()
*/
BlockCipher::~BlockCipher()
{
}
/**
* \fn size_t BlockCipher::blockSize() const
* \brief Size of a single block processed by this cipher, in bytes.
*
* \return Returns the size of a block in bytes.
*
* \sa keySize(), encryptBlock()
*/
/**
* \fn size_t BlockCipher::keySize() const
* \brief Default size of the key for this block cipher, in bytes.
*
* This value indicates the default, or recommended, size for the key.
*
* \sa setKey(), blockSize()
*/
/**
* \fn bool BlockCipher::setKey(const uint8_t *key, size_t len)
* \brief Sets the key to use for future encryption and decryption operations.
*
* \param key The key to use.
* \param len The length of the key.
* \return Returns false if the key length is not supported, or the key
* is somehow "weak" and unusable by this cipher.
*
* Use clear() or the destructor to remove the key and any other sensitive
* data from the object once encryption or decryption is complete.
*
* \sa keySize(), clear()
*/
/**
* \fn void BlockCipher::encryptBlock(uint8_t *output, const uint8_t *input)
* \brief Encrypts a single block using this cipher.
*
* \param output The output buffer to put the ciphertext into.
* Must be at least blockSize() bytes in length.
* \param input The input buffer to read the plaintext from which is
* allowed to overlap with \a output. Must be at least blockSize()
* bytes in length.
*
* \sa decryptBlock(), blockSize()
*/
/**
* \fn void BlockCipher::decryptBlock(uint8_t *output, const uint8_t *input)
* \brief Decrypts a single block using this cipher.
*
* \param output The output buffer to put the plaintext into.
* Must be at least blockSize() bytes in length.
* \param input The input buffer to read the ciphertext from which is
* allowed to overlap with \a output. Must be at least blockSize()
* bytes in length.
*
* \sa encryptBlock(), blockSize()
*/
/**
* \fn void BlockCipher::clear()
* \brief Clears all security-sensitive state from this block cipher.
*
* Security-sensitive information includes key schedules and any
* temporary state that is used by encryptBlock() or decryptBlock()
* which is stored in the object itself.
*
* \sa setKey(), encryptBlock(), decryptBlock()
*/
+46
View File
@@ -0,0 +1,46 @@
/*
* 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_BLOCKCIPHER_h
#define CRYPTO_BLOCKCIPHER_h
#include <inttypes.h>
#include <stddef.h>
class BlockCipher
{
public:
BlockCipher();
virtual ~BlockCipher();
virtual size_t blockSize() const = 0;
virtual size_t keySize() const = 0;
virtual bool setKey(const uint8_t *key, size_t len) = 0;
virtual void encryptBlock(uint8_t *output, const uint8_t *input) = 0;
virtual void decryptBlock(uint8_t *output, const uint8_t *input) = 0;
virtual void clear() = 0;
};
#endif
+114
View File
@@ -0,0 +1,114 @@
/*
* 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 "Crypto.h"
/**
* \brief Cleans a block of bytes.
*
* \param dest The destination block to be cleaned.
* \param size The size of the destination to be cleaned in bytes.
*
* Unlike memset(), this function attempts to prevent the compiler
* from optimizing away the clear on a memory buffer.
*/
void clean(void *dest, size_t size)
{
// Force the use of volatile so that we actually clear the memory.
// Otherwise the compiler might optimise the entire contents of this
// function away, which will not be secure.
volatile uint8_t *d = (volatile uint8_t *)dest;
while (size > 0) {
*d++ = 0;
--size;
}
}
/**
* \fn void clean(T &var)
* \brief Template function that cleans a variable.
*
* \param var A reference to the variable to clean.
*
* The variable will be cleared to all-zeroes in a secure manner.
* Unlike memset(), this function attempts to prevent the compiler
* from optimizing away the variable clear.
*/
/**
* \brief Compares two memory blocks for equality.
*
* \param data1 Points to the first memory block.
* \param data2 Points to the second memory block.
* \param len The size of the memory blocks in bytes.
*
* Unlike memcmp(), this function attempts to compare the two memory blocks
* in a way that will not reveal the contents in the instruction timing.
* In particular, this function will not stop early if a byte is different.
* It will instead continue onto the end of the array.
*/
bool secure_compare(const void *data1, const void *data2, size_t len)
{
uint8_t result = 0;
const uint8_t *d1 = (const uint8_t *)data1;
const uint8_t *d2 = (const uint8_t *)data2;
while (len > 0) {
result |= (*d1++ ^ *d2++);
--len;
}
return (bool)((((uint16_t)0x0100) - result) >> 8);
}
/**
* \brief Calculates the CRC-8 value over an array in memory.
*
* \param tag Starting tag to distinguish this calculation.
* \param data The data to checksum.
* \param size The number of bytes to checksum.
* \return The CRC-8 value over the data.
*
* This function does not provide any real security. It is a simple
* check that seed values have been initialized within EEPROM or Flash.
* If the CRC-8 check fails, then it is assumed that the EEPROM/Flash
* contents are invalid and should be re-initialized.
*
* Reference: http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html#ch4
*/
uint8_t crypto_crc8(uint8_t tag, const void *data, unsigned size)
{
const uint8_t *d = (const uint8_t *)data;
uint8_t crc = 0xFF ^ tag;
uint8_t bit;
while (size > 0) {
crc ^= *d++;
for (bit = 0; bit < 8; ++bit) {
// if (crc & 0x80)
// crc = (crc << 1) ^ 0x1D;
// else
// crc = (crc << 1);
uint8_t generator = (uint8_t)((((int8_t)crc) >> 7) & 0x1D);
crc = (crc << 1) ^ generator;
}
--size;
}
return crc;
}
+46
View File
@@ -0,0 +1,46 @@
/*
* 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_h
#define CRYPTO_h
#include <inttypes.h>
#include <stddef.h>
void clean(void *dest, size_t size);
template <typename T>
inline void clean(T &var)
{
clean(&var, sizeof(T));
}
bool secure_compare(const void *data1, const void *data2, size_t len);
#if defined(ESP8266)
extern "C" void system_soft_wdt_feed(void);
#define crypto_feed_watchdog() system_soft_wdt_feed()
#else
#define crypto_feed_watchdog() do { ; } while (0)
#endif
#endif
File diff suppressed because it is too large Load Diff
+77
View File
@@ -0,0 +1,77 @@
/*
* 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_CURVE25519_h
#define CRYPTO_CURVE25519_h
#include "BigNumberUtil.h"
class Ed25519;
class Curve25519
{
public:
static bool eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[32]);
static void dh1(uint8_t k[32], uint8_t f[32]);
static bool dh2(uint8_t k[32], uint8_t f[32]);
#if defined(TEST_CURVE25519_FIELD_OPS)
public:
#else
private:
#endif
static uint8_t isWeakPoint(const uint8_t k[32]);
static void reduce(limb_t *result, limb_t *x, uint8_t size);
static limb_t reduceQuick(limb_t *x);
static void mulNoReduce(limb_t *result, const limb_t *x, const limb_t *y);
static void mul(limb_t *result, const limb_t *x, const limb_t *y);
static void square(limb_t *result, const limb_t *x)
{
mul(result, x, x);
}
static void mulA24(limb_t *result, const limb_t *x);
static void mul_P(limb_t *result, const limb_t *x, const limb_t *y);
static void add(limb_t *result, const limb_t *x, const limb_t *y);
static void sub(limb_t *result, const limb_t *x, const limb_t *y);
static void cswap(limb_t select, limb_t *x, limb_t *y);
static void cmove(limb_t select, limb_t *x, const limb_t *y);
static void pow250(limb_t *result, const limb_t *x);
static void recip(limb_t *result, const limb_t *x);
static bool sqrt(limb_t *result, const limb_t *x);
// Constructor and destructor are private - cannot instantiate this class.
Curve25519() {}
~Curve25519() {}
friend class Ed25519;
};
#endif
+642
View File
@@ -0,0 +1,642 @@
/*
* 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 "Ed25519.h"
#include "Curve25519.h"
#include "Crypto.h"
#include "RNG.h"
#include "utility/LimbUtil.h"
#include <string.h>
/**
* \class Ed25519 Ed25519.h <Ed25519.h>
* \brief Digital signatures based on the elliptic curve modulo 2^255 - 19.
*
* The first step in creating a digital signature with Ed25519 is to
* generate a key pair:
*
* \code
* uint8_t privateKey[32];
* uint8_t publicKey[32];
*
* Ed25519::generatePrivateKey(privateKey);
* Ed25519::derivePublicKey(publicKey, privateKey);
* \endcode
*
* The application can store both the private and public key for later
* signing operations. Or it can store just the private key and then
* derive the public key at the point where signing is to occur.
*
* Message signing produces a 64-byte signature as follows:
*
* \code
* uint8_t message[N];
* uint8_t signature[64];
*
* Ed25519::sign(signature, privateKey, publicKey, message, N);
* \endcode
*
* And then to verify the signature:
*
* \code
* if (!Ed25519::verify(signature, publicKey, message, N)) {
* // The signature is invalid.
* ...
* }
* \endcode
*
* \note The public functions in this class need a substantial amount of
* stack space to store intermediate results while the curve function is
* being evaluated. About 1.5k of free stack space is recommended for safety.
*
* References: https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05
*
* \sa Curve25519
*/
/** @cond */
// 37095705934669439343138083508754565189542113879843219016388785533085940283555
static limb_t const numD[NUM_LIMBS_256BIT] PROGMEM = {
LIMB_PAIR(0x135978A3, 0x75EB4DCA), LIMB_PAIR(0x4141D8AB, 0x00700A4D),
LIMB_PAIR(0x7779E898, 0x8CC74079), LIMB_PAIR(0x2B6FFE73, 0x52036CEE)
};
// d * 2
static limb_t const numDx2[NUM_LIMBS_256BIT] PROGMEM = {
LIMB_PAIR(0x26B2F159, 0xEBD69B94), LIMB_PAIR(0x8283B156, 0x00E0149A),
LIMB_PAIR(0xEEF3D130, 0x198E80F2), LIMB_PAIR(0x56DFFCE7, 0x2406D9DC)
};
// Extended homogenous co-ordinates for the base point.
static limb_t const numBx[NUM_LIMBS_256BIT] PROGMEM = {
LIMB_PAIR(0x8F25D51A, 0xC9562D60), LIMB_PAIR(0x9525A7B2, 0x692CC760),
LIMB_PAIR(0xFDD6DC5C, 0xC0A4E231), LIMB_PAIR(0xCD6E53FE, 0x216936D3)
};
static limb_t const numBy[NUM_LIMBS_256BIT] PROGMEM = {
LIMB_PAIR(0x66666658, 0x66666666), LIMB_PAIR(0x66666666, 0x66666666),
LIMB_PAIR(0x66666666, 0x66666666), LIMB_PAIR(0x66666666, 0x66666666)
};
static limb_t const numBz[NUM_LIMBS_256BIT] PROGMEM = {
LIMB_PAIR(0x00000001, 0x00000000), LIMB_PAIR(0x00000000, 0x00000000),
LIMB_PAIR(0x00000000, 0x00000000), LIMB_PAIR(0x00000000, 0x00000000)
};
static limb_t const numBt[NUM_LIMBS_256BIT] PROGMEM = {
LIMB_PAIR(0xA5B7DDA3, 0x6DDE8AB3), LIMB_PAIR(0x775152F5, 0x20F09F80),
LIMB_PAIR(0x64ABE37D, 0x66EA4E8E), LIMB_PAIR(0xD78B7665, 0x67875F0F)
};
// 2^252 + 27742317777372353535851937790883648493
static limb_t const numQ[NUM_LIMBS_256BIT] PROGMEM = {
LIMB_PAIR(0x5CF5D3ED, 0x5812631A), LIMB_PAIR(0xA2F79CD6, 0x14DEF9DE),
LIMB_PAIR(0x00000000, 0x00000000), LIMB_PAIR(0x00000000, 0x10000000)
};
/** @endcond */
/**
* \brief Signs a message using a specific Ed25519 private key.
*
* \param signature The signature value.
* \param privateKey The private key to use to sign the message.
* \param publicKey The public key corresponding to \a privateKey.
* \param message Points to the message to be signed.
* \param len The length of the \a message to be signed.
*
* \sa verify(), derivePublicKey()
*/
void Ed25519::sign(uint8_t signature[64], const uint8_t privateKey[32],
const uint8_t publicKey[32], const void *message, size_t len)
{
SHA512 hash;
uint8_t *buf = (uint8_t *)(hash.state.w); // Reuse hash buffer to save memory.
limb_t a[NUM_LIMBS_256BIT];
limb_t r[NUM_LIMBS_256BIT];
limb_t k[NUM_LIMBS_256BIT];
limb_t t[NUM_LIMBS_512BIT + 1];
Point rB;
// Derive the secret scalar a and the message prefix from the private key.
deriveKeys(&hash, a, privateKey);
// Hash the prefix and the message to derive r.
hash.reset();
hash.update(buf + 32, 32);
hash.update(message, len);
hash.finalize(buf, 0);
reduceQFromBuffer(r, buf, t);
// Encode rB into the first half of the signature buffer as R.
mul(rB, r);
encodePoint(signature, rB);
// Hash R, A, and the message to get k.
hash.reset();
hash.update(signature, 32); // R
hash.update(publicKey, 32); // A
hash.update(message, len);
hash.finalize(buf, 0);
reduceQFromBuffer(k, buf, t);
// Compute s = (r + k * a) mod q.
Curve25519::mulNoReduce(t, k, a);
t[NUM_LIMBS_512BIT] = 0;
reduceQ(t, t);
BigNumberUtil::add(t, t, r, NUM_LIMBS_256BIT);
BigNumberUtil::reduceQuick_P(t, t, numQ, NUM_LIMBS_256BIT);
BigNumberUtil::packLE(signature + 32, 32, t, NUM_LIMBS_256BIT);
// Clean up.
clean(a);
clean(r);
clean(k);
clean(t);
clean(rB);
}
/**
* \brief Verifies a signature using a specific Ed25519 public key.
*
* \param signature The signature value to be verified.
* \param publicKey The public key to use to verify the signature.
* \param message The message whose signature is to be verified.
* \param len The length of the \a message to be verified.
*
* \return Returns true if the \a signature is valid for \a message;
* or false if the \a signature is not valid.
*
* \sa sign()
*/
bool Ed25519::verify(const uint8_t signature[64], const uint8_t publicKey[32],
const void *message, size_t len)
{
SHA512 hash;
Point A;
Point R;
Point sB;
Point kA;
uint8_t *k = (uint8_t *)(hash.state.w); // Reuse hash buffer to save memory.
bool result = false;
// Decode the public key and the R component of the signature.
if (decodePoint(A, publicKey) && decodePoint(R, signature)) {
// Reconstruct the k value from the signing step.
hash.reset();
hash.update(signature, 32);
hash.update(publicKey, 32);
hash.update(message, len);
hash.finalize(k, 0);
// Calculate s * B. The s value is stored temporarily in kA.t.
BigNumberUtil::unpackLE(kA.t, NUM_LIMBS_256BIT, signature + 32, 32);
mul(sB, kA.t, false);
// Calculate R + k * A. We don't need sB.t in equal() below,
// so we reuse that as a temporary buffer when reducing k.
reduceQFromBuffer(sB.t, k, kA.x);
mul(kA, sB.t, A, false);
add(R, kA);
// Compare s * B and R + k * A for equality.
result = equal(sB, R);
}
// Clean up and exit.
clean(A);
clean(R);
clean(sB);
clean(kA);
return result;
}
/**
* \brief Generates a private key for Ed25519 signing operations.
*
* \param privateKey The resulting private key.
*
* The private key is generated with \link RNGClass::rand() RNG.rand()\endlink.
* It is the caller's responsibility to ensure that the global random number
* pool has sufficient entropy to generate the 32 bytes of the key safely
* before calling this function.
*
* \sa derivePublicKey()
*/
void Ed25519::generatePrivateKey(uint8_t privateKey[32])
{
RNG.rand(privateKey, 32);
}
/**
* \brief Derives the public key from a private key.
*
* \param publicKey The public key.
* \param privateKey The private key.
*
* \sa generatePrivateKey()
*/
void Ed25519::derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32])
{
SHA512 hash;
limb_t a[NUM_LIMBS_256BIT];
Point ptA;
// Derive the secret scalar a from the private key.
deriveKeys(&hash, a, privateKey);
// Compute the point A = aB and encode it.
mul(ptA, a);
encodePoint(publicKey, ptA);
// Clean up and exit.
clean(a);
clean(ptA);
}
/**
* \brief Reduces a number modulo q that was specified in a 512 bit buffer.
*
* \param result The result array, which must be NUM_LIMBS_256BIT limbs in size.
* \param buf The buffer containing the value to reduce in little-endian order.
* \param temp A temporary buffer of at least NUM_LIMBS_512BIT + 1 in size.
*
* \sa reduceQ()
*/
void Ed25519::reduceQFromBuffer(limb_t *result, const uint8_t buf[64], limb_t *temp)
{
BigNumberUtil::unpackLE(temp, NUM_LIMBS_512BIT, buf, 64);
temp[NUM_LIMBS_512BIT] = 0;
reduceQ(result, temp);
}
/**
* \brief Reduces a number modulo q.
*
* \param result The result array, which must be NUM_LIMBS_256BIT limbs in size.
* \param r The value to reduce, which must be NUM_LIMBS_512BIT + 1
* limbs in size.
*
* The \a r array will be modified by this function as a side effect of
* the division. It is allowed for \a result to be the same as \a r.
*
* \sa reduceQFromBuffer()
*/
void Ed25519::reduceQ(limb_t *result, limb_t *r)
{
// Algorithm from: http://en.wikipedia.org/wiki/Barrett_reduction
//
// We assume that r is less than or equal to (q - 1)^2.
//
// We want to compute result = r mod q. Find the smallest k such
// that 2^k > q. In our case, k = 253. Then set m = floor(4^k / q)
// and let r = r - q * floor(m * r / 4^k). This will be the result
// or it will be at most one subtraction of q away from the result.
//
// Note: 4^k = 4^253 = 2^506 = 2^512/2^6. We can more easily compute
// the result we want if we set m = floor(4^k * 2^6 / q) instead and
// then r = r - q * floor(m * r / 2^512). Because the slight extra
// precision in m, r is at most two subtractions of q away from the
// final result.
static limb_t const numM[NUM_LIMBS_256BIT + 1] PROGMEM = {
LIMB_PAIR(0x0A2C131B, 0xED9CE5A3), LIMB_PAIR(0x086329A7, 0x2106215D),
LIMB_PAIR(0xFFFFFFEB, 0xFFFFFFFF), LIMB_PAIR(0xFFFFFFFF, 0xFFFFFFFF),
0x0F
};
limb_t temp[NUM_LIMBS_512BIT + NUM_LIMBS_256BIT + 1];
// Multiply r by m.
BigNumberUtil::mul_P(temp, r, NUM_LIMBS_512BIT, numM, NUM_LIMBS_256BIT + 1);
// Multiply (m * r) / 2^512 by q and subtract it from r.
// We can ignore the high words of the subtraction result
// because they will all turn into zero after the subtraction.
BigNumberUtil::mul_P(temp, temp + NUM_LIMBS_512BIT, NUM_LIMBS_256BIT + 1,
numQ, NUM_LIMBS_256BIT);
BigNumberUtil::sub(r, r, temp, NUM_LIMBS_256BIT);
// Perform two subtractions of q from the result to reduce it.
BigNumberUtil::reduceQuick_P(result, r, numQ, NUM_LIMBS_256BIT);
BigNumberUtil::reduceQuick_P(result, result, numQ, NUM_LIMBS_256BIT);
// Clean up and exit.
clean(temp);
}
/**
* \brief Multiplies a value by a curve point.
*
* \param result The result of the multiplication.
* \param s The value, which must be NUM_LIMBS_256BIT limbs in size.
* \param p The curve point, which will be modified by this function.
* \param constTime Set to true if the evaluation must be constant-time
* because \a s is a secret value.
*/
void Ed25519::mul(Point &result, const limb_t *s, Point &p, bool constTime)
{
Point q;
limb_t A[NUM_LIMBS_256BIT];
limb_t B[NUM_LIMBS_256BIT];
limb_t C[NUM_LIMBS_256BIT];
limb_t D[NUM_LIMBS_256BIT];
limb_t mask, select;
uint8_t sposn, t;
// Initialize the result to (0, 1, 1, 0).
memset(&result, 0, sizeof(Point));
result.y[0] = 1;
result.z[0] = 1;
// Iterate over the 255 bits of "s" to calculate "s * p".
mask = 1;
sposn = 0;
for (t = 255; t > 0; --t) {
// Add p to the result to produce q. The specification refers
// to temporary variables A to H. We can dispense with E to H
// by using B, D, q.z, and q.t to hold those values temporarily.
select = s[sposn] & mask;
if (constTime || select) {
Curve25519::sub(A, result.y, result.x);
Curve25519::sub(C, p.y, p.x);
Curve25519::mul(A, A, C);
Curve25519::add(B, result.y, result.x);
Curve25519::add(C, p.y, p.x);
Curve25519::mul(B, B, C);
Curve25519::mul(C, result.t, p.t);
Curve25519::mul_P(C, C, numDx2);
Curve25519::mul(D, result.z, p.z);
Curve25519::add(D, D, D);
Curve25519::sub(q.t, B, A); // E = B - A
Curve25519::sub(q.z, D, C); // F = D - C
Curve25519::add(D, D, C); // G = D + C
Curve25519::add(B, B, A); // H = B + A
if (constTime) {
// Put the intermediate value into q.
Curve25519::mul(q.x, q.t, q.z); // q.x = E * F
Curve25519::mul(q.y, D, B); // q.y = G * H
Curve25519::mul(q.z, q.z, D); // q.z = F * G
Curve25519::mul(q.t, q.t, B); // q.t = E * H
// Copy q into the result if the current bit of s is 1.
Curve25519::cmove(select, result.x, q.x);
Curve25519::cmove(select, result.y, q.y);
Curve25519::cmove(select, result.z, q.z);
Curve25519::cmove(select, result.t, q.t);
} else {
// Put the intermediate value directly into the result.
Curve25519::mul(result.x, q.t, q.z); // q.x = E * F
Curve25519::mul(result.y, D, B); // q.y = G * H
Curve25519::mul(result.z, q.z, D); // q.z = F * G
Curve25519::mul(result.t, q.t, B); // q.t = E * H
}
}
// Double p for the next iteration.
Curve25519::sub(A, p.y, p.x);
Curve25519::square(A, A);
Curve25519::add(B, p.y, p.x);
Curve25519::square(B, B);
Curve25519::square(C, p.t);
Curve25519::mul_P(C, C, numDx2);
Curve25519::square(D, p.z);
Curve25519::add(D, D, D);
Curve25519::sub(p.t, B, A); // E = B - A
Curve25519::sub(p.z, D, C); // F = D - C
Curve25519::add(D, D, C); // G = D + C
Curve25519::add(B, B, A); // H = B + A
Curve25519::mul(p.x, p.t, p.z); // p.x = E * F
Curve25519::mul(p.y, D, B); // p.y = G * H
Curve25519::mul(p.z, p.z, D); // p.z = F * G
Curve25519::mul(p.t, p.t, B); // p.t = E * H
// Move onto the next bit of s from lowest to highest.
if (mask != (((limb_t)1) << (LIMB_BITS - 1))) {
mask <<= 1;
} else {
++sposn;
mask = 1;
}
}
// Clean up.
clean(q);
clean(A);
clean(B);
clean(C);
clean(D);
}
/**
* \brief Multiplies a value by the base point of the curve.
*
* \param result The result of the multiplication.
* \param s The value, which must be NUM_LIMBS_256BIT limbs in size.
* \param constTime Set to true if the evaluation must be constant-time
* because \a s is a secret values.
*/
void Ed25519::mul(Point &result, const limb_t *s, bool constTime)
{
Point P;
memcpy_P(P.x, numBx, sizeof(P.x));
memcpy_P(P.y, numBy, sizeof(P.y));
memcpy_P(P.z, numBz, sizeof(P.z));
memcpy_P(P.t, numBt, sizeof(P.t));
mul(result, s, P, constTime);
clean(P);
}
/**
* \brief Adds two curve points.
*
* \param p The first point and the result.
* \param q The second point.
*/
void Ed25519::add(Point &p, const Point &q)
{
limb_t A[NUM_LIMBS_256BIT];
limb_t B[NUM_LIMBS_256BIT];
limb_t C[NUM_LIMBS_256BIT];
limb_t D[NUM_LIMBS_256BIT];
Curve25519::sub(A, p.y, p.x);
Curve25519::sub(C, q.y, q.x);
Curve25519::mul(A, A, C);
Curve25519::add(B, p.y, p.x);
Curve25519::add(C, q.y, q.x);
Curve25519::mul(B, B, C);
Curve25519::mul(C, p.t, q.t);
Curve25519::mul_P(C, C, numDx2);
Curve25519::mul(D, p.z, q.z);
Curve25519::add(D, D, D);
Curve25519::sub(p.t, B, A); // E = B - A
Curve25519::sub(p.z, D, C); // F = D - C
Curve25519::add(D, D, C); // G = D + C
Curve25519::add(B, B, A); // H = B + A
Curve25519::mul(p.x, p.t, p.z); // p.x = E * F
Curve25519::mul(p.y, D, B); // p.y = G * H
Curve25519::mul(p.z, p.z, D); // p.z = F * G
Curve25519::mul(p.t, p.t, B); // p.t = E * H
clean(A);
clean(B);
clean(C);
clean(D);
}
/**
* \brief Determine if two curve points are equal.
*
* \param p The first curve point.
* \param q The second curve point.
*
* \return Returns true if \a p and \a q are equal; false otherwise.
*/
bool Ed25519::equal(const Point &p, const Point &q)
{
limb_t a[NUM_LIMBS_256BIT];
limb_t b[NUM_LIMBS_256BIT];
bool result = true;
Curve25519::mul(a, p.x, q.z);
Curve25519::mul(b, q.x, p.z);
result &= secure_compare(a, b, sizeof(a));
Curve25519::mul(a, p.y, q.z);
Curve25519::mul(b, q.y, p.z);
result &= secure_compare(a, b, sizeof(a));
clean(a);
clean(b);
return result;
}
/**
* \brief Encodes a curve point into a 32-byte buffer.
*
* \param buf The buffer to encode into.
* \param point The curve point to encode. This value will be modified
* the function and effectively destroyed.
*
* \sa decodePoint()
*/
void Ed25519::encodePoint(uint8_t *buf, Point &point)
{
// Convert the homogeneous coordinates into plain (x, y) coordinates:
// zinv = z^(-1) mod p
// x = x * zinv mod p
// y = y * zinv mod p
// We don't need the t coordinate, so use that to store zinv temporarily.
Curve25519::recip(point.t, point.z);
Curve25519::mul(point.x, point.x, point.t);
Curve25519::mul(point.y, point.y, point.t);
// Copy the lowest bit of x to the highest bit of y.
point.y[NUM_LIMBS_256BIT - 1] |= (point.x[0] << (LIMB_BITS - 1));
// Convert y into little-endian in the return buffer.
BigNumberUtil::packLE(buf, 32, point.y, NUM_LIMBS_256BIT);
}
/**
* \brief Decodes a curve point from a 32-byte buffer.
*
* \param point The curve point that was decoded from the buffer.
* \param buf The buffer to decode.
*
* \return Returns true if the point was decoded or false if the contents
* of the buffer do not correspond to a legitimate curve point.
*
* \note This function is not constant time so it should only be used
* on publicly-known values.
*/
bool Ed25519::decodePoint(Point &point, const uint8_t *buf)
{
limb_t temp[NUM_LIMBS_256BIT];
// Convert the input buffer from little-endian into the limbs of y.
BigNumberUtil::unpackLE(point.y, NUM_LIMBS_256BIT, buf, 32);
// The high bit of y is the sign bit for x.
limb_t sign = point.y[NUM_LIMBS_256BIT - 1] >> (LIMB_BITS - 1);
point.y[NUM_LIMBS_256BIT - 1] &= ~(((limb_t)1) << (LIMB_BITS - 1));
// Set z to 1.
memcpy_P(point.z, numBz, sizeof(point.z));
// Compute t = (y * y - 1) * modinv(d * y * y + 1).
Curve25519::square(point.t, point.y);
Curve25519::sub(point.x, point.t, point.z);
Curve25519::mul_P(point.t, point.t, numD);
Curve25519::add(point.t, point.t, point.z);
Curve25519::recip(temp, point.t);
Curve25519::mul(point.t, point.x, temp);
clean(temp);
// Check for t = 0.
limb_t check = point.t[0];
for (uint8_t posn = 1; posn < NUM_LIMBS_256BIT; ++posn)
check |= point.t[posn];
if (!check) {
// If the sign bit is set, then decoding has failed.
// Otherwise x is zero and we're done.
if (sign)
return false;
memset(point.x, 0, sizeof(point.x));
return true;
}
// Recover x by taking the sqrt of t and flipping the sign if necessary.
if (!Curve25519::sqrt(point.x, point.t))
return false;
if (sign != (point.x[0] & ((limb_t)1))) {
// The signs are different so we want the other square root.
memset(point.t, 0, sizeof(point.t));
Curve25519::sub(point.x, point.t, point.x);
}
// Finally, t = x * y.
Curve25519::mul(point.t, point.x, point.y);
return true;
}
/**
* \brief Derive key material from a 32-byte private key.
*
* \param hash SHA512 hash object from the caller for use in this function.
* The 64-byte output buffer within this hash object will contain the
* hash prefix on exit.
* \param a The secret scalar derived from \a privateKey. This must be
* NUM_LIMBS_256BIT limbs in size.
* \param privateKey The 32-byte private key to derive all other values from.
*/
void Ed25519::deriveKeys(SHA512 *hash, limb_t *a, const uint8_t privateKey[32])
{
// Hash the private key to get the "a" scalar and the message prefix.
uint8_t *buf = (uint8_t *)(hash->state.w); // Reuse hash buffer to save memory.
hash->reset();
hash->update(privateKey, 32);
hash->finalize(buf, 0);
buf[0] &= 0xF8;
buf[31] &= 0x7F;
buf[31] |= 0x40;
// Unpack the first half of the hash value into "a".
BigNumberUtil::unpackLE(a, NUM_LIMBS_256BIT, buf, 32);
}
+71
View File
@@ -0,0 +1,71 @@
/*
* 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_ED25519_h
#define CRYPTO_ED25519_h
#include "BigNumberUtil.h"
#include "SHA512.h"
class Ed25519
{
public:
static void sign(uint8_t signature[64], const uint8_t privateKey[32],
const uint8_t publicKey[32], const void *message,
size_t len);
static bool verify(const uint8_t signature[64], const uint8_t publicKey[32],
const void *message, size_t len);
static void generatePrivateKey(uint8_t privateKey[32]);
static void derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32]);
private:
// Constructor and destructor are private - cannot instantiate this class.
Ed25519();
~Ed25519();
// Curve point represented in extended homogeneous coordinates.
struct Point
{
limb_t x[32 / sizeof(limb_t)];
limb_t y[32 / sizeof(limb_t)];
limb_t z[32 / sizeof(limb_t)];
limb_t t[32 / sizeof(limb_t)];
};
static void reduceQFromBuffer(limb_t *result, const uint8_t buf[64], limb_t *temp);
static void reduceQ(limb_t *result, limb_t *r);
static void mul(Point &result, const limb_t *s, Point &p, bool constTime = true);
static void mul(Point &result, const limb_t *s, bool constTime = true);
static void add(Point &p, const Point &q);
static bool equal(const Point &p, const Point &q);
static void encodePoint(uint8_t *buf, Point &point);
static bool decodePoint(Point &point, const uint8_t *buf);
static void deriveKeys(SHA512 *hash, limb_t *a, const uint8_t privateKey[32]);
};
#endif
+202
View File
@@ -0,0 +1,202 @@
/*
* 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 "Hash.h"
#include <string.h>
/**
* \class Hash Hash.h <Hash.h>
* \brief Abstract base class for cryptographic hash algorithms.
*
* \sa SHA224, SHA256, SHA384, SHA3_256, BLAKE2s
*/
/**
* \brief Constructs a new hash object.
*/
Hash::Hash()
{
}
/**
* \brief Destroys this hash object.
*
* \note Subclasses are responsible for clearing any sensitive data
* that remains in the hash object when it is destroyed.
*
* \sa clear()
*/
Hash::~Hash()
{
}
/**
* \fn size_t Hash::hashSize() const
* \brief Size of the hash result from finalize().
*
* \sa finalize(), blockSize()
*/
/**
* \fn size_t Hash::blockSize() const
* \brief Size of the internal block used by the hash algorithm.
*
* \sa update(), hashSize()
*/
/**
* \fn void Hash::reset()
* \brief Resets the hash ready for a new hashing process.
*
* \sa update(), finalize(), resetHMAC()
*/
/**
* \fn void Hash::update(const void *data, size_t len)
* \brief Updates the hash with more data.
*
* \param data Data to be hashed.
* \param len Number of bytes of data to be hashed.
*
* If finalize() has already been called, then the behavior of update() will
* be undefined. Call reset() first to start a new hashing process.
*
* \sa reset(), finalize()
*/
/**
* \fn void Hash::finalize(void *hash, size_t len)
* \brief Finalizes the hashing process and returns the hash.
*
* \param hash The buffer to return the hash value in.
* \param len The length of the \a hash buffer, normally hashSize().
*
* If \a len is less than hashSize(), then the hash value will be
* truncated to the first \a len bytes. If \a len is greater than
* hashSize(), then the remaining bytes will left unchanged.
*
* If finalize() is called again, then the returned \a hash value is
* undefined. Call reset() first to start a new hashing process.
*
* \sa reset(), update(), finalizeHMAC()
*/
/**
* \fn void Hash::clear()
* \brief Clears the hash state, removing all sensitive data, and then
* resets the hash ready for a new hashing process.
*
* \sa reset()
*/
/**
* \fn void Hash::resetHMAC(const void *key, size_t keyLen)
* \brief Resets the hash ready for a new HMAC hashing process.
*
* \param key Points to the HMAC key for the hashing process.
* \param keyLen Size of the HMAC \a key in bytes.
*
* The following example computes a HMAC over a series of data blocks
* with a specific key:
*
* \code
* hash.resetHMAC(key, sizeof(key));
* hash.update(data1, sizeof(data1));
* hash.update(data2, sizeof(data2));
* ...
* hash.update(dataN, sizeof(dataN));
* hash.finalizeHMAC(key, sizeof(key), hmac, sizeof(hmac));
* \endcode
*
* The same key must be passed to both resetHMAC() and finalizeHMAC().
*
* \sa finalizeHMAC(), reset()
*/
/**
* \fn void Hash::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
* \brief Finalizes the HMAC hashing process and returns the hash.
*
* \param key Points to the HMAC key for the hashing process. The contents
* of this array must be identical to the value passed to resetHMAC().
* \param keyLen Size of the HMAC \a key in bytes.
* \param hash The buffer to return the hash value in.
* \param hashLen The length of the \a hash buffer, normally hashSize().
*
* \sa resetHMAC(), finalize()
*/
/**
* \brief Formats a HMAC key into a block.
*
* \param block The block to format the key into. Must be at least
* blockSize() bytes in length.
* \param key Points to the HMAC key for the hashing process.
* \param len Length of the HMAC \a key in bytes.
* \param pad Inner (0x36) or outer (0x5C) padding value to XOR with
* the formatted HMAC key.
*
* This function is intended to help subclasses implement resetHMAC() and
* finalizeHMAC() by directly formatting the HMAC key into the subclass's
* internal block buffer and resetting the hash.
*/
void Hash::formatHMACKey(void *block, const void *key, size_t len, uint8_t pad)
{
size_t size = blockSize();
reset();
if (len <= size) {
memcpy(block, key, len);
} else {
update(key, len);
len = hashSize();
finalize(block, len);
reset();
}
uint8_t *b = (uint8_t *)block;
memset(b + len, pad, size - len);
while (len > 0) {
*b++ ^= pad;
--len;
}
}
/**
* \fn void hmac<T>(void *out, size_t outLen, const void *key, size_t keyLen, const void *data, size_t dataLen)
* \brief All-in-one convenience function for computing HMAC values.
*
* \param out Points to the buffer to receive the output HMAC value.
* \param outLen Length of the buffer to receive the output HMAC value.
* \param key Points to the HMAC key for the hashing process.
* \param keyLen Length of the HMAC \a key in bytes.
* \param data Points to the data to hash under the HMAC \a key.
* \param dataLen Length of the input \a data in bytes.
*
* This is a convenience function for computing a HMAC value over a block
* of input data under a given key. The template argument T must be the
* name of a class that inherits from Hash. The following example
* computes a HMAC value using the SHA256 hash algorithm:
*
* \code
* uint8_t out[SHA256::HASH_SIZE];
* hmac<SHA256>(out, sizeof(out), key, keyLen, data, dataLen);
* \endcode
*/
+61
View File
@@ -0,0 +1,61 @@
/*
* 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_HASH_h
#define CRYPTO_HASH_h
#include <inttypes.h>
#include <stddef.h>
class Hash
{
public:
Hash();
virtual ~Hash();
virtual size_t hashSize() const = 0;
virtual size_t blockSize() const = 0;
virtual void reset() = 0;
virtual void update(const void *data, size_t len) = 0;
virtual void finalize(void *hash, size_t len) = 0;
virtual void clear() = 0;
virtual void resetHMAC(const void *key, size_t keyLen) = 0;
virtual void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen) = 0;
protected:
void formatHMACKey(void *block, const void *key, size_t len, uint8_t pad);
};
template <typename T> void hmac
(void *out, size_t outLen, const void *key, size_t keyLen,
const void *data, size_t dataLen)
{
T context;
context.resetHMAC(key, keyLen);
context.update(data, dataLen);
context.finalizeHMAC(key, keyLen, out, outLen);
}
#endif
+74
View File
@@ -0,0 +1,74 @@
/*
* 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_RNG_h
#define CRYPTO_RNG_h
#include <inttypes.h>
#include <stddef.h>
class NoiseSource;
class RNGClass
{
public:
RNGClass();
~RNGClass();
void begin(const char *tag);
void addNoiseSource(NoiseSource &source);
void setAutoSaveTime(uint16_t minutes);
void rand(uint8_t *data, size_t len);
bool available(size_t len) const;
void stir(const uint8_t *data, size_t len, unsigned int credit = 0);
void save();
void loop();
void destroy();
static const int SEED_SIZE = 48;
private:
uint32_t block[16];
uint32_t stream[16];
uint16_t credits : 13;
uint16_t firstSave : 1;
uint16_t initialized : 1;
uint16_t trngPending : 1;
unsigned long timer;
unsigned long timeout;
NoiseSource *noiseSources[4];
uint8_t count;
uint8_t trngPosn;
void rekey();
void mixTRNG();
};
extern RNGClass RNG;
#endif
+269
View File
@@ -0,0 +1,269 @@
/*
* 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 "SHA256.h"
#include "Crypto.h"
#include "utility/RotateUtil.h"
#include "utility/EndianUtil.h"
#include "utility/ProgMemUtil.h"
#include <string.h>
/**
* \class SHA256 SHA256.h <SHA256.h>
* \brief SHA-256 hash algorithm.
*
* Reference: http://en.wikipedia.org/wiki/SHA-2
*
* \sa SHA224, SHA384, SHA512, SHA3_256, BLAKE2s
*/
/**
* \var SHA256::HASH_SIZE
* \brief Constant for the size of the hash output of SHA256.
*/
/**
* \var SHA256::BLOCK_SIZE
* \brief Constant for the block size of SHA256.
*/
/**
* \brief Constructs a SHA-256 hash object.
*/
SHA256::SHA256()
{
reset();
}
/**
* \brief Destroys this SHA-256 hash object after clearing
* sensitive information.
*/
SHA256::~SHA256()
{
clean(state);
}
size_t SHA256::hashSize() const
{
return 32;
}
size_t SHA256::blockSize() const
{
return 64;
}
void SHA256::reset()
{
state.h[0] = 0x6a09e667;
state.h[1] = 0xbb67ae85;
state.h[2] = 0x3c6ef372;
state.h[3] = 0xa54ff53a,
state.h[4] = 0x510e527f;
state.h[5] = 0x9b05688c;
state.h[6] = 0x1f83d9ab;
state.h[7] = 0x5be0cd19;
state.chunkSize = 0;
state.length = 0;
}
void SHA256::update(const void *data, size_t len)
{
// Update the total length (in bits, not bytes).
state.length += ((uint64_t)len) << 3;
// Break the input up into 512-bit chunks and process each in turn.
const uint8_t *d = (const uint8_t *)data;
while (len > 0) {
uint8_t size = 64 - 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 == 64) {
processChunk();
state.chunkSize = 0;
}
}
}
void SHA256::finalize(void *hash, size_t len)
{
// 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 <= (64 - 9)) {
wbytes[state.chunkSize] = 0x80;
memset(wbytes + state.chunkSize + 1, 0x00, 64 - 8 - (state.chunkSize + 1));
state.w[14] = htobe32((uint32_t)(state.length >> 32));
state.w[15] = htobe32((uint32_t)state.length);
processChunk();
} else {
wbytes[state.chunkSize] = 0x80;
memset(wbytes + state.chunkSize + 1, 0x00, 64 - (state.chunkSize + 1));
processChunk();
memset(wbytes, 0x00, 64 - 8);
state.w[14] = htobe32((uint32_t)(state.length >> 32));
state.w[15] = htobe32((uint32_t)state.length);
processChunk();
}
// Convert the result into big endian and return it.
for (uint8_t posn = 0; posn < 8; ++posn)
state.w[posn] = htobe32(state.h[posn]);
// Copy the hash to the caller's return buffer.
size_t maxHashSize = hashSize();
if (len > maxHashSize)
len = maxHashSize;
memcpy(hash, state.w, len);
}
void SHA256::clear()
{
clean(state);
reset();
}
void SHA256::resetHMAC(const void *key, size_t keyLen)
{
formatHMACKey(state.w, key, keyLen, 0x36);
state.length += 64 * 8;
processChunk();
}
void SHA256::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
uint8_t temp[32];
finalize(temp, sizeof(temp));
formatHMACKey(state.w, key, keyLen, 0x5C);
state.length += 64 * 8;
processChunk();
update(temp, hashSize());
finalize(hash, hashLen);
clean(temp);
}
/**
* \brief Processes a single 512-bit chunk with the core SHA-256 algorithm.
*
* Reference: http://en.wikipedia.org/wiki/SHA-2
*/
void SHA256::processChunk()
{
// Round constants for SHA-256.
static uint32_t const k[64] PROGMEM = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
// Convert the first 16 words from big endian to host byte order.
uint8_t index;
for (index = 0; index < 16; ++index)
state.w[index] = be32toh(state.w[index]);
// Initialise working variables to the current hash value.
uint32_t a = state.h[0];
uint32_t b = state.h[1];
uint32_t c = state.h[2];
uint32_t d = state.h[3];
uint32_t e = state.h[4];
uint32_t f = state.h[5];
uint32_t g = state.h[6];
uint32_t h = state.h[7];
// Perform the first 16 rounds of the compression function main loop.
uint32_t temp1, temp2;
for (index = 0; index < 16; ++index) {
temp1 = h + pgm_read_dword(k + index) + state.w[index] +
(rightRotate6(e) ^ rightRotate11(e) ^ rightRotate25(e)) +
((e & f) ^ ((~e) & g));
temp2 = (rightRotate2(a) ^ rightRotate13(a) ^ rightRotate22(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 48 remaining rounds. We expand the first 16 words to
// 64 in-place in the "w" array. This saves 192 bytes of memory
// that would have otherwise need to be allocated to the "w" array.
for (; index < 64; ++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] +
(rightRotate7(temp1) ^ rightRotate18(temp1) ^ (temp1 >> 3)) +
(rightRotate17(temp2) ^ rightRotate19(temp2) ^ (temp2 >> 10));
// Perform the round.
temp1 = h + pgm_read_dword(k + index) + temp1 +
(rightRotate6(e) ^ rightRotate11(e) ^ rightRotate25(e)) +
((e & f) ^ ((~e) & g));
temp2 = (rightRotate2(a) ^ rightRotate13(a) ^ rightRotate22(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;
}
+60
View File
@@ -0,0 +1,60 @@
/*
* 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_SHA256_h
#define CRYPTO_SHA256_h
#include "Hash.h"
class SHA256 : public Hash
{
public:
SHA256();
virtual ~SHA256();
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();
void resetHMAC(const void *key, size_t keyLen);
void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);
static const size_t HASH_SIZE = 32;
static const size_t BLOCK_SIZE = 64;
protected:
struct {
uint32_t h[8];
uint32_t w[16];
uint64_t length;
uint8_t chunkSize;
} state;
void processChunk();
};
#endif
+285
View File
@@ -0,0 +1,285 @@
/*
* 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 SHA224, SHA256, SHA3_512, BLAKE2b
*/
/**
* \var SHA512::HASH_SIZE
* \brief Constant for the size of the hash output of SHA512.
*/
/**
* \var SHA512::BLOCK_SIZE
* \brief Constant for the block size of SHA512.
*/
/**
* \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.lengthLow = 0;
state.lengthHigh = 0;
}
void SHA512::update(const void *data, size_t len)
{
// 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)
{
// 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]);
// Copy the hash to the caller's return buffer.
size_t maxHashSize = hashSize();
if (len > maxHashSize)
len = maxHashSize;
memcpy(hash, state.w, len);
}
void SHA512::clear()
{
clean(state);
reset();
}
void SHA512::resetHMAC(const void *key, size_t keyLen)
{
formatHMACKey(state.w, key, keyLen, 0x36);
state.lengthLow += 128 * 8;
processChunk();
}
void SHA512::finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen)
{
uint8_t temp[64];
finalize(temp, sizeof(temp));
formatHMACKey(state.w, key, keyLen, 0x5C);
state.lengthLow += 128 * 8;
processChunk();
update(temp, hashSize());
finalize(hash, hashLen);
clean(temp);
}
/**
* \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;
}
+65
View File
@@ -0,0 +1,65 @@
/*
* 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 Ed25519;
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();
void resetHMAC(const void *key, size_t keyLen);
void finalizeHMAC(const void *key, size_t keyLen, void *hash, size_t hashLen);
static const size_t HASH_SIZE = 64;
static const size_t BLOCK_SIZE = 128;
protected:
struct {
uint64_t h[8];
uint64_t w[16];
uint64_t lengthLow;
uint64_t lengthHigh;
uint8_t chunkSize;
} state;
void processChunk();
friend class Ed25519;
};
#endif
+32
View File
@@ -0,0 +1,32 @@
// Minimal native stand-in for rweather/Crypto's own RNGClass (RNG.cpp /
// NoiseSource.cpp are Arduino/AVR/ESP-hardware-entropy-only -- EEPROM/NVS
// seed persistence, TRNG registers, etc. -- and were deliberately NOT vendored
// here). Ed25519::generatePrivateKey() and Curve25519::dh1() reference the
// global `RNG` object even though MeshCore itself never calls either
// (real keypair generation goes through lib/ed25519 + mesh::RNG /
// SimRNG, see variants/sim/SimRNG.h) -- the symbol still has to resolve
// because it's referenced inside Ed25519.cpp/Curve25519.cpp regardless of
// which functions actually get called at runtime.
#include <RNG.h>
#include <cstdlib>
RNGClass::RNGClass() { }
RNGClass::~RNGClass() { }
void RNGClass::begin(const char *tag) { }
void RNGClass::addNoiseSource(NoiseSource &source) { }
void RNGClass::setAutoSaveTime(uint16_t minutes) { }
void RNGClass::rand(uint8_t *data, size_t len) {
for (size_t i = 0; i < len; i++) data[i] = (uint8_t)::rand();
}
bool RNGClass::available(size_t len) const { return true; }
void RNGClass::stir(const uint8_t *data, size_t len, unsigned int credit) { }
void RNGClass::save() { }
void RNGClass::loop() { }
void RNGClass::destroy() { }
void RNGClass::rekey() { }
void RNGClass::mixTRNG() { }
RNGClass RNG;
+77
View File
@@ -0,0 +1,77 @@
/*
* 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_ENDIANUTIL_H
#define CRYPTO_ENDIANUTIL_H
#include <inttypes.h>
#if !defined(HOST_BUILD)
// 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 htole16(x) (x)
#define le16toh(x) (x)
#define htobe16(x) \
(__extension__ ({ \
uint16_t _temp = (x); \
((_temp >> 8) & 0x00FF) | \
((_temp << 8) & 0xFF00); \
}))
#define be16toh(x) (htobe16((x)))
#define htole32(x) (x)
#define le32toh(x) (x)
#define htobe32(x) \
(__extension__ ({ \
uint32_t _temp = (x); \
((_temp >> 24) & 0x000000FF) | \
((_temp >> 8) & 0x0000FF00) | \
((_temp << 8) & 0x00FF0000) | \
((_temp << 24) & 0xFF000000); \
}))
#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)))
#else // HOST_BUILD
#include <endian.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define CRYPTO_LITTLE_ENDIAN 1
#endif
#endif // HOST_BUILD
#endif
+70
View File
@@ -0,0 +1,70 @@
/*
* 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_LIMBUTIL_H
#define CRYPTO_LIMBUTIL_H
#include "ProgMemUtil.h"
// Number of limbs in a big number value of various sizes.
#define NUM_LIMBS_BITS(n) \
(((n) + sizeof(limb_t) * 8 - 1) / (8 * sizeof(limb_t)))
#define NUM_LIMBS_128BIT NUM_LIMBS_BITS(128)
#define NUM_LIMBS_256BIT NUM_LIMBS_BITS(256)
#define NUM_LIMBS_512BIT NUM_LIMBS_BITS(512)
// The number of bits in a limb.
#define LIMB_BITS (8 * sizeof(limb_t))
// Read a limb-sized quantity from program memory.
#if BIGNUMBER_LIMB_8BIT
#define pgm_read_limb(x) (pgm_read_byte((x)))
#elif BIGNUMBER_LIMB_16BIT
#define pgm_read_limb(x) (pgm_read_word((x)))
#elif BIGNUMBER_LIMB_32BIT
#define pgm_read_limb(x) (pgm_read_dword((x)))
#elif BIGNUMBER_LIMB_64BIT
#define pgm_read_limb(x) (pgm_read_qword((x)))
#endif
// Expand a 32-bit value into a set of limbs depending upon the limb size.
// This is used when initializing constant big number values in the code.
// For 64-bit system compatibility it is necessary to use LIMB_PAIR(x, y).
#if BIGNUMBER_LIMB_8BIT
#define LIMB(value) ((uint8_t)(value)), \
((uint8_t)((value) >> 8)), \
((uint8_t)((value) >> 16)), \
((uint8_t)((value) >> 24))
#define LIMB_PAIR(x,y) LIMB((x)), LIMB((y))
#elif BIGNUMBER_LIMB_16BIT
#define LIMB(value) ((uint16_t)(value)), \
((uint16_t)(((uint32_t)(value)) >> 16))
#define LIMB_PAIR(x,y) LIMB((x)), LIMB((y))
#elif BIGNUMBER_LIMB_32BIT
#define LIMB(value) (value)
#define LIMB_PAIR(x,y) LIMB((x)), LIMB((y))
#elif BIGNUMBER_LIMB_64BIT
#define LIMB(value) (value)
#define LIMB_PAIR(x,y) ((((uint64_t)(y)) << 32) | ((uint64_t)(x)))
#endif
#endif
+62
View File
@@ -0,0 +1,62 @@
/*
* 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_PROGMEMUTIL_H
#define CRYPTO_PROGMEMUTIL_H
#if defined(__AVR__)
#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); \
}))
#elif defined(ESP8266) || defined(ESP32)
#include <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
#include <string.h>
#define PROGMEM
#ifndef pgm_read_byte
# define pgm_read_byte(x) (*(x))
#endif
#ifndef pgm_read_word
# define pgm_read_word(x) (*(x))
#endif
#ifndef pgm_read_dword
# define pgm_read_dword(x) (*(x))
#endif
#ifndef pgm_read_qword
# define pgm_read_qword(x) (*(x))
#endif
#ifndef memcpy_P
# define memcpy_P(d,s,l) memcpy((d), (s), (l))
#endif
#endif
#endif
+696
View File
@@ -0,0 +1,696 @@
/*
* 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_ROTATEUTIL_H
#define CRYPTO_ROTATEUTIL_H
#include <inttypes.h>
// 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.
#define leftRotate(a, bits) \
(__extension__ ({ \
uint32_t _temp = (a); \
(_temp << (bits)) | (_temp >> (32 - (bits))); \
}))
// Generic right rotate - best performance when "bits" is 1 or a multiple of 8.
#define rightRotate(a, bits) \
(__extension__ ({ \
uint32_t _temp = (a); \
(_temp >> (bits)) | (_temp << (32 - (bits))); \
}))
// Left rotate by 1.
#define leftRotate1(a) (leftRotate((a), 1))
// Left rotate by 2.
#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1))
// Left rotate by 3.
#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1))
// Left rotate by 4.
#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1))
// Left rotate by 5: Rotate left by 8, then right by 3.
#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1))
// Left rotate by 6: Rotate left by 8, then right by 2.
#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1))
// Left rotate by 7: Rotate left by 8, then right by 1.
#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1))
// Left rotate by 8.
#define leftRotate8(a) (leftRotate((a), 8))
// Left rotate by 9: Rotate left by 8, then left by 1.
#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1))
// Left rotate by 10: Rotate left by 8, then left by 2.
#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1))
// 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 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))
// Left rotate by 14: Rotate left by 16, then right by 2.
#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1))
// Left rotate by 15: Rotate left by 16, then right by 1.
#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1))
// Left rotate by 16.
#define leftRotate16(a) (leftRotate((a), 16))
// Left rotate by 17: Rotate left by 16, then left by 1.
#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1))
// Left rotate by 18: Rotate left by 16, then left by 2.
#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1))
// Left rotate by 19: Rotate left by 16, then left by 3.
#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1))
// Left rotate by 20: Rotate left by 16, then left by 4.
#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1))
// Left rotate by 21: Rotate left by 24, then right by 3.
#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1))
// Left rotate by 22: Rotate left by 24, then right by 2.
#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1))
// Left rotate by 23: Rotate left by 24, then right by 1.
#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1))
// Left rotate by 24.
#define leftRotate24(a) (leftRotate((a), 24))
// Left rotate by 25: Rotate left by 24, then left by 1.
#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1))
// Left rotate by 26: Rotate left by 24, then left by 2.
#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1))
// Left rotate by 27: Rotate left by 24, then left by 3.
#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1))
// Left rotate by 28: Rotate right by 4.
#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1))
// Left rotate by 29: Rotate right by 3.
#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1))
// Left rotate by 30: Rotate right by 2.
#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1))
// Left rotate by 31: Rotate right by 1.
#define leftRotate31(a) (rightRotate((a), 1))
// Define the 32-bit right rotations in terms of left rotations.
#define rightRotate1(a) (leftRotate31((a)))
#define rightRotate2(a) (leftRotate30((a)))
#define rightRotate3(a) (leftRotate29((a)))
#define rightRotate4(a) (leftRotate28((a)))
#define rightRotate5(a) (leftRotate27((a)))
#define rightRotate6(a) (leftRotate26((a)))
#define rightRotate7(a) (leftRotate25((a)))
#define rightRotate8(a) (leftRotate24((a)))
#define rightRotate9(a) (leftRotate23((a)))
#define rightRotate10(a) (leftRotate22((a)))
#define rightRotate11(a) (leftRotate21((a)))
#define rightRotate12(a) (leftRotate20((a)))
#define rightRotate13(a) (leftRotate19((a)))
#define rightRotate14(a) (leftRotate18((a)))
#define rightRotate15(a) (leftRotate17((a)))
#define rightRotate16(a) (leftRotate16((a)))
#define rightRotate17(a) (leftRotate15((a)))
#define rightRotate18(a) (leftRotate14((a)))
#define rightRotate19(a) (leftRotate13((a)))
#define rightRotate20(a) (leftRotate12((a)))
#define rightRotate21(a) (leftRotate11((a)))
#define rightRotate22(a) (leftRotate10((a)))
#define rightRotate23(a) (leftRotate9((a)))
#define rightRotate24(a) (leftRotate8((a)))
#define rightRotate25(a) (leftRotate7((a)))
#define rightRotate26(a) (leftRotate6((a)))
#define rightRotate27(a) (leftRotate5((a)))
#define rightRotate28(a) (leftRotate4((a)))
#define rightRotate29(a) (leftRotate3((a)))
#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.
#define leftRotate_64(a, bits) \
(__extension__ ({ \
uint64_t _temp = (a); \
(_temp << (bits)) | (_temp >> (64 - (bits))); \
}))
// Generic right rotate - best performance when "bits" is 1 or a multiple of 8.
#define rightRotate_64(a, bits) \
(__extension__ ({ \
uint64_t _temp = (a); \
(_temp >> (bits)) | (_temp << (64 - (bits))); \
}))
// Left rotate by 1.
#define leftRotate1_64(a) (leftRotate_64((a), 1))
// Left rotate by 2.
#define leftRotate2_64(a) (leftRotate_64(leftRotate_64((a), 1), 1))
// Left rotate by 3.
#define leftRotate3_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 1), 1), 1))
// Left rotate by 4.
#define leftRotate4_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 1), 1), 1), 1))
// Left rotate by 5: Rotate left by 8, then right by 3.
#define leftRotate5_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 8), 1), 1), 1))
// Left rotate by 6: Rotate left by 8, then right by 2.
#define leftRotate6_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 8), 1), 1))
// Left rotate by 7: Rotate left by 8, then right by 1.
#define leftRotate7_64(a) (rightRotate_64(leftRotate_64((a), 8), 1))
// Left rotate by 8.
#define leftRotate8_64(a) (leftRotate_64((a), 8))
// Left rotate by 9: Rotate left by 8, then left by 1.
#define leftRotate9_64(a) (leftRotate_64(leftRotate_64((a), 8), 1))
// Left rotate by 10: Rotate left by 8, then left by 2.
#define leftRotate10_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 8), 1), 1))
// Left rotate by 11: Rotate left by 8, then left by 3.
#define leftRotate11_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 8), 1), 1), 1))
// Left rotate by 12: Rotate left by 16, then right by 4.
#define leftRotate12_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 16), 1), 1), 1), 1))
// Left rotate by 13: Rotate left by 16, then right by 3.
#define leftRotate13_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 16), 1), 1), 1))
// Left rotate by 14: Rotate left by 16, then right by 2.
#define leftRotate14_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 16), 1), 1))
// Left rotate by 15: Rotate left by 16, then right by 1.
#define leftRotate15_64(a) (rightRotate_64(leftRotate_64((a), 16), 1))
// Left rotate by 16.
#define leftRotate16_64(a) (leftRotate_64((a), 16))
// Left rotate by 17: Rotate left by 16, then left by 1.
#define leftRotate17_64(a) (leftRotate_64(leftRotate_64((a), 16), 1))
// Left rotate by 18: Rotate left by 16, then left by 2.
#define leftRotate18_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 16), 1), 1))
// Left rotate by 19: Rotate left by 16, then left by 3.
#define leftRotate19_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 16), 1), 1), 1))
// Left rotate by 20: Rotate left by 16, then left by 4.
#define leftRotate20_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 16), 1), 1), 1), 1))
// Left rotate by 21: Rotate left by 24, then right by 3.
#define leftRotate21_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 24), 1), 1), 1))
// Left rotate by 22: Rotate left by 24, then right by 2.
#define leftRotate22_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 24), 1), 1))
// Left rotate by 23: Rotate left by 24, then right by 1.
#define leftRotate23_64(a) (rightRotate_64(leftRotate_64((a), 24), 1))
// Left rotate by 24.
#define leftRotate24_64(a) (leftRotate_64((a), 24))
// Left rotate by 25: Rotate left by 24, then left by 1.
#define leftRotate25_64(a) (leftRotate_64(leftRotate_64((a), 24), 1))
// Left rotate by 26: Rotate left by 24, then left by 2.
#define leftRotate26_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 24), 1), 1))
// Left rotate by 27: Rotate left by 24, then left by 3.
#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(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 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))
// Left rotate by 32.
#define leftRotate32_64(a) (leftRotate_64((a), 32))
// Left rotate by 33: Rotate left by 32, then left by 1.
#define leftRotate33_64(a) (leftRotate_64(leftRotate_64((a), 32), 1))
// Left rotate by 34: Rotate left by 32, then left by 2.
#define leftRotate34_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 32), 1), 1))
// Left rotate by 35: Rotate left by 32, then left by 3.
#define leftRotate35_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 32), 1), 1), 1))
// Left rotate by 36: Rotate left by 32, then left by 4.
#define leftRotate36_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 32), 1), 1), 1), 1))
// Left rotate by 37: Rotate left by 40, then right by 3.
#define leftRotate37_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 40), 1), 1), 1))
// Left rotate by 38: Rotate left by 40, then right by 2.
#define leftRotate38_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 40), 1), 1))
// Left rotate by 39: Rotate left by 40, then right by 1.
#define leftRotate39_64(a) (rightRotate_64(leftRotate_64((a), 40), 1))
// Left rotate by 40.
#define leftRotate40_64(a) (leftRotate_64((a), 40))
// Left rotate by 41: Rotate left by 40, then left by 1.
#define leftRotate41_64(a) (leftRotate_64(leftRotate_64((a), 40), 1))
// Left rotate by 42: Rotate left by 40, then left by 2.
#define leftRotate42_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 40), 1), 1))
// Left rotate by 43: Rotate left by 40, then left by 3.
#define leftRotate43_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 40), 1), 1), 1))
// Left rotate by 44: Rotate left by 40, then left by 4.
#define leftRotate44_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 40), 1), 1), 1), 1))
// Left rotate by 45: Rotate left by 48, then right by 3.
#define leftRotate45_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 48), 1), 1), 1))
// Left rotate by 46: Rotate left by 48, then right by 2.
#define leftRotate46_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 48), 1), 1))
// Left rotate by 47: Rotate left by 48, then right by 1.
#define leftRotate47_64(a) (rightRotate_64(leftRotate_64((a), 48), 1))
// Left rotate by 48.
#define leftRotate48_64(a) (leftRotate_64((a), 48))
// Left rotate by 49: Rotate left by 48, then left by 1.
#define leftRotate49_64(a) (leftRotate_64(leftRotate_64((a), 48), 1))
// Left rotate by 50: Rotate left by 48, then left by 2.
#define leftRotate50_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 48), 1), 1))
// Left rotate by 51: Rotate left by 48, then left by 3.
#define leftRotate51_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 48), 1), 1), 1))
// Left rotate by 52: Rotate left by 48, then left by 4.
#define leftRotate52_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 48), 1), 1), 1), 1))
// Left rotate by 53: Rotate left by 56, then right by 3.
#define leftRotate53_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 56), 1), 1), 1))
// Left rotate by 54: Rotate left by 56, then right by 2.
#define leftRotate54_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 56), 1), 1))
// Left rotate by 55: Rotate left by 56, then right by 1.
#define leftRotate55_64(a) (rightRotate_64(leftRotate_64((a), 56), 1))
// Left rotate by 56.
#define leftRotate56_64(a) (leftRotate_64((a), 56))
// Left rotate by 57: Rotate left by 56, then left by 1.
#define leftRotate57_64(a) (leftRotate_64(leftRotate_64((a), 56), 1))
// Left rotate by 58: Rotate left by 56, then left by 2.
#define leftRotate58_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 56), 1), 1))
// Left rotate by 59: Rotate left by 56, then left by 3.
#define leftRotate59_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 56), 1), 1), 1))
// Left rotate by 60: Rotate left by 60, then left by 4.
#define leftRotate60_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 56), 1), 1), 1), 1))
// Left rotate by 61: Rotate right by 3.
#define leftRotate61_64(a) (rightRotate_64(rightRotate_64(rightRotate_64((a), 1), 1), 1))
// Left rotate by 62: Rotate right by 2.
#define leftRotate62_64(a) (rightRotate_64(rightRotate_64((a), 1), 1))
// Left rotate by 63: Rotate right by 1.
#define leftRotate63_64(a) (rightRotate_64((a), 1))
// Define the 64-bit right rotations in terms of left rotations.
#define rightRotate1_64(a) (leftRotate63_64((a)))
#define rightRotate2_64(a) (leftRotate62_64((a)))
#define rightRotate3_64(a) (leftRotate61_64((a)))
#define rightRotate4_64(a) (leftRotate60_64((a)))
#define rightRotate5_64(a) (leftRotate59_64((a)))
#define rightRotate6_64(a) (leftRotate58_64((a)))
#define rightRotate7_64(a) (leftRotate57_64((a)))
#define rightRotate8_64(a) (leftRotate56_64((a)))
#define rightRotate9_64(a) (leftRotate55_64((a)))
#define rightRotate10_64(a) (leftRotate54_64((a)))
#define rightRotate11_64(a) (leftRotate53_64((a)))
#define rightRotate12_64(a) (leftRotate52_64((a)))
#define rightRotate13_64(a) (leftRotate51_64((a)))
#define rightRotate14_64(a) (leftRotate50_64((a)))
#define rightRotate15_64(a) (leftRotate49_64((a)))
#define rightRotate16_64(a) (leftRotate48_64((a)))
#define rightRotate17_64(a) (leftRotate47_64((a)))
#define rightRotate18_64(a) (leftRotate46_64((a)))
#define rightRotate19_64(a) (leftRotate45_64((a)))
#define rightRotate20_64(a) (leftRotate44_64((a)))
#define rightRotate21_64(a) (leftRotate43_64((a)))
#define rightRotate22_64(a) (leftRotate42_64((a)))
#define rightRotate23_64(a) (leftRotate41_64((a)))
#define rightRotate24_64(a) (leftRotate40_64((a)))
#define rightRotate25_64(a) (leftRotate39_64((a)))
#define rightRotate26_64(a) (leftRotate38_64((a)))
#define rightRotate27_64(a) (leftRotate37_64((a)))
#define rightRotate28_64(a) (leftRotate36_64((a)))
#define rightRotate29_64(a) (leftRotate35_64((a)))
#define rightRotate30_64(a) (leftRotate34_64((a)))
#define rightRotate31_64(a) (leftRotate33_64((a)))
#define rightRotate32_64(a) (leftRotate32_64((a)))
#define rightRotate33_64(a) (leftRotate31_64((a)))
#define rightRotate34_64(a) (leftRotate30_64((a)))
#define rightRotate35_64(a) (leftRotate29_64((a)))
#define rightRotate36_64(a) (leftRotate28_64((a)))
#define rightRotate37_64(a) (leftRotate27_64((a)))
#define rightRotate38_64(a) (leftRotate26_64((a)))
#define rightRotate39_64(a) (leftRotate25_64((a)))
#define rightRotate40_64(a) (leftRotate24_64((a)))
#define rightRotate41_64(a) (leftRotate23_64((a)))
#define rightRotate42_64(a) (leftRotate22_64((a)))
#define rightRotate43_64(a) (leftRotate21_64((a)))
#define rightRotate44_64(a) (leftRotate20_64((a)))
#define rightRotate45_64(a) (leftRotate19_64((a)))
#define rightRotate46_64(a) (leftRotate18_64((a)))
#define rightRotate47_64(a) (leftRotate17_64((a)))
#define rightRotate48_64(a) (leftRotate16_64((a)))
#define rightRotate49_64(a) (leftRotate15_64((a)))
#define rightRotate50_64(a) (leftRotate14_64((a)))
#define rightRotate51_64(a) (leftRotate13_64((a)))
#define rightRotate52_64(a) (leftRotate12_64((a)))
#define rightRotate53_64(a) (leftRotate11_64((a)))
#define rightRotate54_64(a) (leftRotate10_64((a)))
#define rightRotate55_64(a) (leftRotate9_64((a)))
#define rightRotate56_64(a) (leftRotate8_64((a)))
#define rightRotate57_64(a) (leftRotate7_64((a)))
#define rightRotate58_64(a) (leftRotate6_64((a)))
#define rightRotate59_64(a) (leftRotate5_64((a)))
#define rightRotate60_64(a) (leftRotate4_64((a)))
#define rightRotate61_64(a) (leftRotate3_64((a)))
#define rightRotate62_64(a) (leftRotate2_64((a)))
#define rightRotate63_64(a) (leftRotate1_64((a)))
#else // !CRYPTO_ROTATE64_COMPOSED
// Rotation macros for 64-bit arguments.
// Generic left rotate.
#define leftRotate_64(a, bits) \
(__extension__ ({ \
uint64_t _temp = (a); \
(_temp << (bits)) | (_temp >> (64 - (bits))); \
}))
// Generic right rotate.
#define rightRotate_64(a, bits) \
(__extension__ ({ \
uint64_t _temp = (a); \
(_temp >> (bits)) | (_temp << (64 - (bits))); \
}))
// Left rotate by a specific number of bits.
#define leftRotate1_64(a) (leftRotate_64((a), 1))
#define leftRotate2_64(a) (leftRotate_64((a), 2))
#define leftRotate3_64(a) (leftRotate_64((a), 3))
#define leftRotate4_64(a) (leftRotate_64((a), 4))
#define leftRotate5_64(a) (leftRotate_64((a), 5))
#define leftRotate6_64(a) (leftRotate_64((a), 6))
#define leftRotate7_64(a) (leftRotate_64((a), 7))
#define leftRotate8_64(a) (leftRotate_64((a), 8))
#define leftRotate9_64(a) (leftRotate_64((a), 9))
#define leftRotate10_64(a) (leftRotate_64((a), 10))
#define leftRotate11_64(a) (leftRotate_64((a), 11))
#define leftRotate12_64(a) (leftRotate_64((a), 12))
#define leftRotate13_64(a) (leftRotate_64((a), 13))
#define leftRotate14_64(a) (leftRotate_64((a), 14))
#define leftRotate15_64(a) (leftRotate_64((a), 15))
#define leftRotate16_64(a) (leftRotate_64((a), 16))
#define leftRotate17_64(a) (leftRotate_64((a), 17))
#define leftRotate18_64(a) (leftRotate_64((a), 18))
#define leftRotate19_64(a) (leftRotate_64((a), 19))
#define leftRotate20_64(a) (leftRotate_64((a), 20))
#define leftRotate21_64(a) (leftRotate_64((a), 21))
#define leftRotate22_64(a) (leftRotate_64((a), 22))
#define leftRotate23_64(a) (leftRotate_64((a), 23))
#define leftRotate24_64(a) (leftRotate_64((a), 24))
#define leftRotate25_64(a) (leftRotate_64((a), 25))
#define leftRotate26_64(a) (leftRotate_64((a), 26))
#define leftRotate27_64(a) (leftRotate_64((a), 27))
#define leftRotate28_64(a) (leftRotate_64((a), 28))
#define leftRotate29_64(a) (leftRotate_64((a), 29))
#define leftRotate30_64(a) (leftRotate_64((a), 30))
#define leftRotate31_64(a) (leftRotate_64((a), 31))
#define leftRotate32_64(a) (leftRotate_64((a), 32))
#define leftRotate33_64(a) (leftRotate_64((a), 33))
#define leftRotate34_64(a) (leftRotate_64((a), 34))
#define leftRotate35_64(a) (leftRotate_64((a), 35))
#define leftRotate36_64(a) (leftRotate_64((a), 36))
#define leftRotate37_64(a) (leftRotate_64((a), 37))
#define leftRotate38_64(a) (leftRotate_64((a), 38))
#define leftRotate39_64(a) (leftRotate_64((a), 39))
#define leftRotate40_64(a) (leftRotate_64((a), 40))
#define leftRotate41_64(a) (leftRotate_64((a), 41))
#define leftRotate42_64(a) (leftRotate_64((a), 42))
#define leftRotate43_64(a) (leftRotate_64((a), 43))
#define leftRotate44_64(a) (leftRotate_64((a), 44))
#define leftRotate45_64(a) (leftRotate_64((a), 45))
#define leftRotate46_64(a) (leftRotate_64((a), 46))
#define leftRotate47_64(a) (leftRotate_64((a), 47))
#define leftRotate48_64(a) (leftRotate_64((a), 48))
#define leftRotate49_64(a) (leftRotate_64((a), 49))
#define leftRotate50_64(a) (leftRotate_64((a), 50))
#define leftRotate51_64(a) (leftRotate_64((a), 51))
#define leftRotate52_64(a) (leftRotate_64((a), 52))
#define leftRotate53_64(a) (leftRotate_64((a), 53))
#define leftRotate54_64(a) (leftRotate_64((a), 54))
#define leftRotate55_64(a) (leftRotate_64((a), 55))
#define leftRotate56_64(a) (leftRotate_64((a), 56))
#define leftRotate57_64(a) (leftRotate_64((a), 57))
#define leftRotate58_64(a) (leftRotate_64((a), 58))
#define leftRotate59_64(a) (leftRotate_64((a), 59))
#define leftRotate60_64(a) (leftRotate_64((a), 60))
#define leftRotate61_64(a) (leftRotate_64((a), 61))
#define leftRotate62_64(a) (leftRotate_64((a), 62))
#define leftRotate63_64(a) (leftRotate_64((a), 63))
// Right rotate by a specific number of bits.
#define rightRotate1_64(a) (rightRotate_64((a), 1))
#define rightRotate2_64(a) (rightRotate_64((a), 2))
#define rightRotate3_64(a) (rightRotate_64((a), 3))
#define rightRotate4_64(a) (rightRotate_64((a), 4))
#define rightRotate5_64(a) (rightRotate_64((a), 5))
#define rightRotate6_64(a) (rightRotate_64((a), 6))
#define rightRotate7_64(a) (rightRotate_64((a), 7))
#define rightRotate8_64(a) (rightRotate_64((a), 8))
#define rightRotate9_64(a) (rightRotate_64((a), 9))
#define rightRotate10_64(a) (rightRotate_64((a), 10))
#define rightRotate11_64(a) (rightRotate_64((a), 11))
#define rightRotate12_64(a) (rightRotate_64((a), 12))
#define rightRotate13_64(a) (rightRotate_64((a), 13))
#define rightRotate14_64(a) (rightRotate_64((a), 14))
#define rightRotate15_64(a) (rightRotate_64((a), 15))
#define rightRotate16_64(a) (rightRotate_64((a), 16))
#define rightRotate17_64(a) (rightRotate_64((a), 17))
#define rightRotate18_64(a) (rightRotate_64((a), 18))
#define rightRotate19_64(a) (rightRotate_64((a), 19))
#define rightRotate20_64(a) (rightRotate_64((a), 20))
#define rightRotate21_64(a) (rightRotate_64((a), 21))
#define rightRotate22_64(a) (rightRotate_64((a), 22))
#define rightRotate23_64(a) (rightRotate_64((a), 23))
#define rightRotate24_64(a) (rightRotate_64((a), 24))
#define rightRotate25_64(a) (rightRotate_64((a), 25))
#define rightRotate26_64(a) (rightRotate_64((a), 26))
#define rightRotate27_64(a) (rightRotate_64((a), 27))
#define rightRotate28_64(a) (rightRotate_64((a), 28))
#define rightRotate29_64(a) (rightRotate_64((a), 29))
#define rightRotate30_64(a) (rightRotate_64((a), 30))
#define rightRotate31_64(a) (rightRotate_64((a), 31))
#define rightRotate32_64(a) (rightRotate_64((a), 32))
#define rightRotate33_64(a) (rightRotate_64((a), 33))
#define rightRotate34_64(a) (rightRotate_64((a), 34))
#define rightRotate35_64(a) (rightRotate_64((a), 35))
#define rightRotate36_64(a) (rightRotate_64((a), 36))
#define rightRotate37_64(a) (rightRotate_64((a), 37))
#define rightRotate38_64(a) (rightRotate_64((a), 38))
#define rightRotate39_64(a) (rightRotate_64((a), 39))
#define rightRotate40_64(a) (rightRotate_64((a), 40))
#define rightRotate41_64(a) (rightRotate_64((a), 41))
#define rightRotate42_64(a) (rightRotate_64((a), 42))
#define rightRotate43_64(a) (rightRotate_64((a), 43))
#define rightRotate44_64(a) (rightRotate_64((a), 44))
#define rightRotate45_64(a) (rightRotate_64((a), 45))
#define rightRotate46_64(a) (rightRotate_64((a), 46))
#define rightRotate47_64(a) (rightRotate_64((a), 47))
#define rightRotate48_64(a) (rightRotate_64((a), 48))
#define rightRotate49_64(a) (rightRotate_64((a), 49))
#define rightRotate50_64(a) (rightRotate_64((a), 50))
#define rightRotate51_64(a) (rightRotate_64((a), 51))
#define rightRotate52_64(a) (rightRotate_64((a), 52))
#define rightRotate53_64(a) (rightRotate_64((a), 53))
#define rightRotate54_64(a) (rightRotate_64((a), 54))
#define rightRotate55_64(a) (rightRotate_64((a), 55))
#define rightRotate56_64(a) (rightRotate_64((a), 56))
#define rightRotate57_64(a) (rightRotate_64((a), 57))
#define rightRotate58_64(a) (rightRotate_64((a), 58))
#define rightRotate59_64(a) (rightRotate_64((a), 59))
#define rightRotate60_64(a) (rightRotate_64((a), 60))
#define rightRotate61_64(a) (rightRotate_64((a), 61))
#define rightRotate62_64(a) (rightRotate_64((a), 62))
#define rightRotate63_64(a) (rightRotate_64((a), 63))
#endif // !CRYPTO_ROTATE64_COMPOSED
#endif