From 002c30ccd41933d200617311eaa63b091eaf793c Mon Sep 17 00:00:00 2001 From: Cyberes Date: Sun, 30 Jun 2024 19:31:13 -0600 Subject: [PATCH] update readme, reorganize files --- README.md | 32 +- esp32/README.md | 4 - .../libraries/crypto/AuthenticatedCipher.cpp | 130 +++ esp32/libraries/crypto/AuthenticatedCipher.h | 42 + esp32/libraries/crypto/BigNumberUtil.cpp | 769 ++++++++++++++++++ esp32/libraries/crypto/BigNumberUtil.h | 110 +++ esp32/libraries/crypto/ChaCha.cpp | 281 +++++++ esp32/libraries/crypto/ChaCha.h | 64 ++ esp32/libraries/crypto/ChaChaPoly.cpp | 170 ++++ esp32/libraries/crypto/ChaChaPoly.h | 65 ++ esp32/libraries/crypto/Cipher.cpp | 154 ++++ esp32/libraries/crypto/Cipher.h | 47 ++ esp32/libraries/crypto/Crypto.cpp | 114 +++ esp32/libraries/crypto/Crypto.h | 46 ++ esp32/libraries/crypto/Poly1305.cpp | 345 ++++++++ esp32/libraries/crypto/Poly1305.h | 54 ++ esp32/libraries/crypto/utility/EndianUtil.h | 77 ++ esp32/libraries/crypto/utility/LimbUtil.h | 70 ++ esp32/libraries/crypto/utility/ProgMemUtil.h | 62 ++ esp32/libraries/crypto/utility/RotateUtil.h | 696 ++++++++++++++++ esp32/telelogger/config.h | 2 +- server/config.sample.yml | 9 +- server/freematics-encrypt.service | 12 + server/src/server.go | 4 +- 24 files changed, 3347 insertions(+), 12 deletions(-) delete mode 100644 esp32/README.md create mode 100644 esp32/libraries/crypto/AuthenticatedCipher.cpp create mode 100644 esp32/libraries/crypto/AuthenticatedCipher.h create mode 100644 esp32/libraries/crypto/BigNumberUtil.cpp create mode 100644 esp32/libraries/crypto/BigNumberUtil.h create mode 100644 esp32/libraries/crypto/ChaCha.cpp create mode 100644 esp32/libraries/crypto/ChaCha.h create mode 100644 esp32/libraries/crypto/ChaChaPoly.cpp create mode 100644 esp32/libraries/crypto/ChaChaPoly.h create mode 100644 esp32/libraries/crypto/Cipher.cpp create mode 100644 esp32/libraries/crypto/Cipher.h create mode 100644 esp32/libraries/crypto/Crypto.cpp create mode 100644 esp32/libraries/crypto/Crypto.h create mode 100644 esp32/libraries/crypto/Poly1305.cpp create mode 100644 esp32/libraries/crypto/Poly1305.h create mode 100644 esp32/libraries/crypto/utility/EndianUtil.h create mode 100644 esp32/libraries/crypto/utility/LimbUtil.h create mode 100644 esp32/libraries/crypto/utility/ProgMemUtil.h create mode 100644 esp32/libraries/crypto/utility/RotateUtil.h create mode 100644 server/freematics-encrypt.service diff --git a/README.md b/README.md index b7ce2be..7c84f9f 100644 --- a/README.md +++ b/README.md @@ -2,5 +2,33 @@ _A proxy to encrypt the Traccar Freematics protocol._ -Inspired by previous work: -https://github.com/rfhigler/Freematics/commit/25cf781ca9fecc3e3082348ce9d28e4d69ff7764 +This is an implementation of the ChaCha20-Poly1305 algorithm into +the [Freematics vehicle tracker](https://freematics.com/products/freematics-one-plus-model-b/) for the Traccar server. + +It consists of 2 parts: + +1. A simple server written in Go that handles encryption and proxies messages to Traccar. +2. Modified firmware for the Freematics device that implements encryption. + +The server is protocol-independant and only manages encryption, meaning it can serve other protocols besides Freematics. +It can also listen on multiple ports for multiple destinations. + +### Install + +#### Client + +1. Run `server/generate-key.sh` script to generate your encryption key. +2. Open the modified firmware in Visual Studio Code with the PlatformIO extension. +3. Enter your encryption key under `CHACHA20_KEY` in `config.h`. +4. Upload the firmware to the device. + +#### Server + +1. Download the latest binary from [releases](https://git.evulid.cc/cyberes/freematics-traccar-encrypted/releases) or + build it yourself using `./build.sh`. +2. Copy `config.sample.yml` to `config.yml` +3. Enter your encryption key in `config.yml` under `chacha_key`. +4. Fill our your forwarding destinations under `destinations`. +5. Start the server with `./freematics-encrypt --config config.yml` + +A sample systemd service file is provided. \ No newline at end of file diff --git a/esp32/README.md b/esp32/README.md deleted file mode 100644 index 23877e8..0000000 --- a/esp32/README.md +++ /dev/null @@ -1,4 +0,0 @@ -```shell -git clone https://github.com/rweather/arduinolibs -cp -r arduinolibs/libraries/Crypto Freematics/firmware_v5/telelogger/lib -``` \ No newline at end of file diff --git a/esp32/libraries/crypto/AuthenticatedCipher.cpp b/esp32/libraries/crypto/AuthenticatedCipher.cpp new file mode 100644 index 0000000..6184aa8 --- /dev/null +++ b/esp32/libraries/crypto/AuthenticatedCipher.cpp @@ -0,0 +1,130 @@ +/* + * 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 "AuthenticatedCipher.h" + +/** + * \class AuthenticatedCipher AuthenticatedCipher.h + * \brief Abstract base class for authenticated ciphers. + * + * This class abstracts the details of algorithms that provide Authenticated + * Encryption with Associated Data (AEAD). Such algorithms combine + * encryption with message authentication to provide a single primitive. + * + * Authenticated ciphers have four parameters: the secret key, an + * initialization vector (called a "nonce" in the literature), the + * plaintext, and some associated data which is to be authenticated + * with the plaintext but not encrypted. Associated data might be + * sequence numbers, IP addresses, protocol versions, or other information + * that is not secret but is important and unique to the session. + * + * Subclasses encrypt the plaintext content and output the ciphertext. + * Once all plaintext has been processed, the caller should invoke + * computeTag() to obtain the authentication tag to transmit with + * the ciphertext. When the ciphertext is later decrypted, the checkTag() + * function can be used to check that the data is authentic. + * + * Reference: RFC 5116 + * + * \sa Cipher + */ + +/** + * \brief Constructs a new authenticated cipher. + */ +AuthenticatedCipher::AuthenticatedCipher() +{ +} + +/** + * \brief Destroys this authenticated cipher. + */ +AuthenticatedCipher::~AuthenticatedCipher() +{ +} + +/** + * \fn size_t AuthenticatedCipher::tagSize() const + * \brief Returns the size of the authentication tag. + * + * \return The size of the authentication tag in bytes. + * + * By default this function should return the largest tag size supported + * by the authenticated cipher. + * + * \sa computeTag() + */ + +/** + * \fn void AuthenticatedCipher::addAuthData(const void *data, size_t len) + * \brief Adds extra data that will be authenticated but not encrypted. + * + * \param data The extra data to be authenticated. + * \param len The number of bytes of extra data to be authenticated. + * + * This function must be called before the first call to encrypt() or + * decrypt(). That is, it is assumed that all extra data for authentication + * is available before the first payload data block and that it will be + * prepended to the payload for authentication. If the subclass needs to + * process the extra data after the payload, then it is responsible for saving + * \a data away until it is needed during computeTag() or checkTag(). + * + * This function can be called multiple times with separate extra data + * blocks for authentication. All such data will be concatenated into a + * single block for authentication purposes. + */ + +/** + * \fn void AuthenticatedCipher::computeTag(void *tag, size_t len) + * \brief Finalizes the encryption process and computes the authentication tag. + * + * \param tag Points to the buffer to write the tag to. + * \param len The length of the tag, which may be less than tagSize() to + * truncate the tag to the first \a len bytes. + * + * \sa checkTag() + */ + +/** + * \fn bool AuthenticatedCipher::checkTag(const void *tag, size_t len) + * \brief Finalizes the decryption process and checks the authentication tag. + * + * \param tag The tag value from the incoming ciphertext to be checked. + * \param len The length of the tag value in bytes, which may be less + * than tagSize(). + * + * \return Returns true if the \a tag is identical to the first \a len + * bytes of the authentication tag that was calculated during the + * decryption process. Returns false otherwise. + * + * This function must be called after the final block of ciphertext is + * passed to decrypt() to determine if the data could be authenticated. + * + * \note Authenticated cipher modes usually require that if the tag could + * not be verified, then all of the data that was previously decrypted + * must be discarded. It is unwise to use the decrypted data for + * any purpose before it can be verified. Callers are responsible for + * ensuring that any data returned via previous calls to decrypt() is + * discarded if checkTag() returns false. + * + * \sa computeTag() + */ diff --git a/esp32/libraries/crypto/AuthenticatedCipher.h b/esp32/libraries/crypto/AuthenticatedCipher.h new file mode 100644 index 0000000..de419d0 --- /dev/null +++ b/esp32/libraries/crypto/AuthenticatedCipher.h @@ -0,0 +1,42 @@ +/* + * 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_AUTHENTICATEDCIPHER_h +#define CRYPTO_AUTHENTICATEDCIPHER_h + +#include "Cipher.h" + +class AuthenticatedCipher : public Cipher +{ +public: + AuthenticatedCipher(); + virtual ~AuthenticatedCipher(); + + virtual size_t tagSize() const = 0; + + virtual void addAuthData(const void *data, size_t len) = 0; + + virtual void computeTag(void *tag, size_t len) = 0; + virtual bool checkTag(const void *tag, size_t len) = 0; +}; + +#endif diff --git a/esp32/libraries/crypto/BigNumberUtil.cpp b/esp32/libraries/crypto/BigNumberUtil.cpp new file mode 100644 index 0000000..976603c --- /dev/null +++ b/esp32/libraries/crypto/BigNumberUtil.cpp @@ -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 + +/** + * \class BigNumberUtil 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); +} diff --git a/esp32/libraries/crypto/BigNumberUtil.h b/esp32/libraries/crypto/BigNumberUtil.h new file mode 100644 index 0000000..2212cbb --- /dev/null +++ b/esp32/libraries/crypto/BigNumberUtil.h @@ -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 +#include + +// 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 diff --git a/esp32/libraries/crypto/ChaCha.cpp b/esp32/libraries/crypto/ChaCha.cpp new file mode 100644 index 0000000..b12b1a8 --- /dev/null +++ b/esp32/libraries/crypto/ChaCha.cpp @@ -0,0 +1,281 @@ +/* + * 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 "ChaCha.h" +#include "Crypto.h" +#include "utility/RotateUtil.h" +#include "utility/EndianUtil.h" +#include "utility/ProgMemUtil.h" +#include + +/** + * \class ChaCha ChaCha.h + * \brief ChaCha stream cipher. + * + * ChaCha is a stream cipher that takes a key, an 8-byte nonce/IV, and a + * counter and hashes them to generate a keystream to XOR with the plaintext. + * Variations on the ChaCha cipher use 8, 12, or 20 rounds of hashing + * operations with either 128-bit or 256-bit keys. + * + * Reference: http://cr.yp.to/chacha.html + */ + +/** + * \brief Constructs a new ChaCha stream cipher. + * + * \param numRounds Number of encryption rounds to use; usually 8, 12, or 20. + */ +ChaCha::ChaCha(uint8_t numRounds) + : rounds(numRounds) + , posn(64) +{ +} + +ChaCha::~ChaCha() +{ + clean(block); + clean(stream); +} + +size_t ChaCha::keySize() const +{ + // Default key size is 256-bit, but any key size is allowed. + return 32; +} + +size_t ChaCha::ivSize() const +{ + // We return 8 but we also support 12-byte nonces in setIV(). + return 8; +} + +/** + * \fn uint8_t ChaCha::numRounds() const + * \brief Returns the number of encryption rounds; usually 8, 12, or 20. + * + * \sa setNumRounds() + */ + +/** + * \fn void ChaCha::setNumRounds(uint8_t numRounds) + * \brief Sets the number of encryption rounds. + * + * \param numRounds The number of encryption rounds; usually 8, 12, or 20. + * + * \sa numRounds() + */ + +bool ChaCha::setKey(const uint8_t *key, size_t len) +{ + static const char tag128[] PROGMEM = "expand 16-byte k"; + static const char tag256[] PROGMEM = "expand 32-byte k"; + if (len <= 16) { + memcpy_P(block, tag128, 16); + memcpy(block + 16, key, len); + memcpy(block + 32, key, len); + if (len < 16) { + memset(block + 16 + len, 0, 16 - len); + memset(block + 32 + len, 0, 16 - len); + } + } else { + if (len > 32) + len = 32; + memcpy_P(block, tag256, 16); + memcpy(block + 16, key, len); + if (len < 32) + memset(block + 16 + len, 0, 32 - len); + } + posn = 64; + return true; +} + +bool ChaCha::setIV(const uint8_t *iv, size_t len) +{ + // From draft-nir-cfrg-chacha20-poly1305-10.txt, we can use either + // 64-bit or 96-bit nonces. The 96-bit nonce consists of the high + // word of the counter prepended to a regular 64-bit nonce for ChaCha. + if (len == 8) { + memset(block + 48, 0, 8); + memcpy(block + 56, iv, len); + posn = 64; + return true; + } else if (len == 12) { + memset(block + 48, 0, 4); + memcpy(block + 52, iv, len); + posn = 64; + return true; + } else { + return false; + } +} + +/** + * \brief Sets the starting counter for encryption. + * + * \param counter A 4-byte or 8-byte value to use for the starting counter + * instead of the default value of zero. + * \param len The length of the counter, which must be 4 or 8. + * \return Returns false if \a len is not 4 or 8. + * + * This function must be called after setIV() and before the first call + * to encrypt(). It is used to specify a different starting value than + * zero for the counter portion of the hash input. + * + * \sa setIV() + */ +bool ChaCha::setCounter(const uint8_t *counter, size_t len) +{ + // Normally both the IV and the counter are 8 bytes in length. + // However, if the IV was 12 bytes, then a 4 byte counter can be used. + if (len == 4 || len == 8) { + memcpy(block + 48, counter, len); + posn = 64; + return true; + } else { + return false; + } +} + +void ChaCha::encrypt(uint8_t *output, const uint8_t *input, size_t len) +{ + while (len > 0) { + if (posn >= 64) { + // Generate a new encrypted counter block. + hashCore((uint32_t *)stream, (const uint32_t *)block, rounds); + posn = 0; + + // Increment the counter, taking care not to reveal + // any timing information about the starting value. + // We iterate through the entire counter region even + // if we could stop earlier because a byte is non-zero. + uint16_t temp = 1; + uint8_t index = 48; + while (index < 56) { + temp += block[index]; + block[index] = (uint8_t)temp; + temp >>= 8; + ++index; + } + } + uint8_t templen = 64 - posn; + if (templen > len) + templen = len; + len -= templen; + while (templen > 0) { + *output++ = *input++ ^ stream[posn++]; + --templen; + } + } +} + +void ChaCha::decrypt(uint8_t *output, const uint8_t *input, size_t len) +{ + encrypt(output, input, len); +} + +/** + * \brief Generates a single block of output direct from the keystream. + * + * \param output The output buffer to fill with keystream bytes. + * + * Unlike encrypt(), this function does not XOR the keystream with + * plaintext data. Instead it generates the keystream directly into + * the caller-supplied buffer. This is useful if the caller knows + * that the plaintext is all-zeroes. + * + * \sa encrypt() + */ +void ChaCha::keystreamBlock(uint32_t *output) +{ + // Generate the hash output directly into the caller-supplied buffer. + hashCore(output, (const uint32_t *)block, rounds); + posn = 64; + + // Increment the lowest counter byte. We are assuming that the caller + // is ChaChaPoly::setKey() and that the previous counter value was zero. + block[48] = 1; +} + +void ChaCha::clear() +{ + clean(block); + clean(stream); + posn = 64; +} + +// Perform a ChaCha quarter round operation. +#define quarterRound(a, b, c, d) \ + do { \ + uint32_t _b = (b); \ + uint32_t _a = (a) + _b; \ + uint32_t _d = leftRotate((d) ^ _a, 16); \ + uint32_t _c = (c) + _d; \ + _b = leftRotate12(_b ^ _c); \ + _a += _b; \ + (d) = _d = leftRotate(_d ^ _a, 8); \ + _c += _d; \ + (a) = _a; \ + (b) = leftRotate7(_b ^ _c); \ + (c) = _c; \ + } while (0) + +/** + * \brief Executes the ChaCha hash core on an input memory block. + * + * \param output Output memory block, must be at least 16 words in length + * and must not overlap with \a input. + * \param input Input memory block, must be at least 16 words in length. + * \param rounds Number of ChaCha rounds to perform; usually 8, 12, or 20. + * + * This function is provided for the convenience of applications that need + * access to the ChaCha hash core without the higher-level processing that + * turns the core into a stream cipher. + */ +void ChaCha::hashCore(uint32_t *output, const uint32_t *input, uint8_t rounds) +{ + uint8_t posn; + + // Copy the input buffer to the output prior to the first round + // and convert from little-endian to host byte order. + for (posn = 0; posn < 16; ++posn) + output[posn] = le32toh(input[posn]); + + // Perform the ChaCha rounds in sets of two. + for (; rounds >= 2; rounds -= 2) { + // Column round. + quarterRound(output[0], output[4], output[8], output[12]); + quarterRound(output[1], output[5], output[9], output[13]); + quarterRound(output[2], output[6], output[10], output[14]); + quarterRound(output[3], output[7], output[11], output[15]); + + // Diagonal round. + quarterRound(output[0], output[5], output[10], output[15]); + quarterRound(output[1], output[6], output[11], output[12]); + quarterRound(output[2], output[7], output[8], output[13]); + quarterRound(output[3], output[4], output[9], output[14]); + } + + // Add the original input to the final output, convert back to + // little-endian, and return the result. + for (posn = 0; posn < 16; ++posn) + output[posn] = htole32(output[posn] + le32toh(input[posn])); +} diff --git a/esp32/libraries/crypto/ChaCha.h b/esp32/libraries/crypto/ChaCha.h new file mode 100644 index 0000000..8c05cd4 --- /dev/null +++ b/esp32/libraries/crypto/ChaCha.h @@ -0,0 +1,64 @@ +/* + * 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_CHACHA_h +#define CRYPTO_CHACHA_h + +#include "Cipher.h" + +class ChaChaPoly; + +class ChaCha : public Cipher +{ +public: + explicit ChaCha(uint8_t numRounds = 20); + virtual ~ChaCha(); + + size_t keySize() const; + size_t ivSize() const; + + uint8_t numRounds() const { return rounds; } + void setNumRounds(uint8_t numRounds) { rounds = numRounds; } + + bool setKey(const uint8_t *key, size_t len); + bool setIV(const uint8_t *iv, size_t len); + bool setCounter(const uint8_t *counter, size_t len); + + void encrypt(uint8_t *output, const uint8_t *input, size_t len); + void decrypt(uint8_t *output, const uint8_t *input, size_t len); + + void clear(); + + static void hashCore(uint32_t *output, const uint32_t *input, uint8_t rounds); + +private: + uint8_t block[64]; + uint8_t stream[64]; + uint8_t rounds; + uint8_t posn; + + void keystreamBlock(uint32_t *output); + + friend class ChaChaPoly; +}; + +#endif diff --git a/esp32/libraries/crypto/ChaChaPoly.cpp b/esp32/libraries/crypto/ChaChaPoly.cpp new file mode 100644 index 0000000..c6cb301 --- /dev/null +++ b/esp32/libraries/crypto/ChaChaPoly.cpp @@ -0,0 +1,170 @@ +/* + * 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 "ChaChaPoly.h" +#include "Crypto.h" +#include "utility/EndianUtil.h" +#include + +/** + * \class ChaChaPoly ChaChaPoly.h + * \brief Authenticated cipher based on ChaCha and Poly1305 + * + * ChaChaPoly is an authenticated cipher based on a combination of + * ChaCha with 20 rounds for encryption and Poly1305 for authentication. + * The resulting cipher has a 256-bit key, a 64-bit or 96-bit + * initialization vector, and a 128-bit authentication tag. + * + * Reference: https://tools.ietf.org/html/draft-irtf-cfrg-chacha20-poly1305-10 + * + * \sa ChaCha, Poly1305, AuthenticatedCipher + */ + +/** + * \brief Constructs a new ChaChaPoly authenticated cipher. + */ +ChaChaPoly::ChaChaPoly() +{ + state.authSize = 0; + state.dataSize = 0; + state.dataStarted = false; + state.ivSize = 8; +} + +/** + * \brief Destroys this ChaChaPoly authenticated cipher. + */ +ChaChaPoly::~ChaChaPoly() +{ + clean(state); +} + +size_t ChaChaPoly::keySize() const +{ + // Default key size is 256-bit, but any key size is allowed. + return 32; +} + +size_t ChaChaPoly::ivSize() const +{ + // Return 8 but we also support 12-byte nonces in setIV(). + return 8; +} + +size_t ChaChaPoly::tagSize() const +{ + // Any tag size between 1 and 16 is supported. + return 16; +} + +bool ChaChaPoly::setKey(const uint8_t *key, size_t len) +{ + return chacha.setKey(key, len); +} + +bool ChaChaPoly::setIV(const uint8_t *iv, size_t len) +{ + // ChaCha::setIV() supports both 64-bit and 96-bit nonces. + if (!chacha.setIV(iv, len)) + return false; + + // Generate the key and nonce to use for Poly1305. + uint32_t data[16]; + chacha.keystreamBlock(data); + poly1305.reset(data); + memcpy(state.nonce, data + 4, 16); + clean(data); + + // Reset the size counters for the auth data and payload. + state.authSize = 0; + state.dataSize = 0; + state.dataStarted = false; + state.ivSize = len; + return true; +} + +void ChaChaPoly::encrypt(uint8_t *output, const uint8_t *input, size_t len) +{ + if (!state.dataStarted) { + poly1305.pad(); + state.dataStarted = true; + } + chacha.encrypt(output, input, len); + poly1305.update(output, len); + state.dataSize += len; +} + +void ChaChaPoly::decrypt(uint8_t *output, const uint8_t *input, size_t len) +{ + if (!state.dataStarted) { + poly1305.pad(); + state.dataStarted = true; + } + poly1305.update(input, len); + chacha.encrypt(output, input, len); // encrypt() is the same as decrypt() + state.dataSize += len; +} + +void ChaChaPoly::addAuthData(const void *data, size_t len) +{ + if (!state.dataStarted) { + poly1305.update(data, len); + state.authSize += len; + } +} + +void ChaChaPoly::computeTag(void *tag, size_t len) +{ + uint64_t sizes[2]; + + // Pad the final Poly1305 block and then hash the sizes. + poly1305.pad(); + sizes[0] = htole64(state.authSize); + sizes[1] = htole64(state.dataSize); + poly1305.update(sizes, sizeof(sizes)); + + // Compute the tag and copy it to the return buffer. + poly1305.finalize(state.nonce, tag, len); + clean(sizes); +} + +bool ChaChaPoly::checkTag(const void *tag, size_t len) +{ + // Can never match if the expected tag length is too long. + if (len > 16) + return false; + + // Compute the tag and check it. + uint8_t temp[16]; + computeTag(temp, len); + bool equal = secure_compare(temp, tag, len); + clean(temp); + return equal; +} + +void ChaChaPoly::clear() +{ + chacha.clear(); + poly1305.clear(); + clean(state); + state.ivSize = 8; +} diff --git a/esp32/libraries/crypto/ChaChaPoly.h b/esp32/libraries/crypto/ChaChaPoly.h new file mode 100644 index 0000000..2e7247e --- /dev/null +++ b/esp32/libraries/crypto/ChaChaPoly.h @@ -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_CHACHAPOLY_H +#define CRYPTO_CHACHAPOLY_H + +#include "AuthenticatedCipher.h" +#include "ChaCha.h" +#include "Poly1305.h" + +class ChaChaPoly : public AuthenticatedCipher +{ +public: + ChaChaPoly(); + virtual ~ChaChaPoly(); + + size_t keySize() const; + size_t ivSize() const; + size_t tagSize() const; + + bool setKey(const uint8_t *key, size_t len); + bool setIV(const uint8_t *iv, size_t len); + + void encrypt(uint8_t *output, const uint8_t *input, size_t len); + void decrypt(uint8_t *output, const uint8_t *input, size_t len); + + void addAuthData(const void *data, size_t len); + + void computeTag(void *tag, size_t len); + bool checkTag(const void *tag, size_t len); + + void clear(); + +private: + ChaCha chacha; + Poly1305 poly1305; + struct { + uint8_t nonce[16]; + uint64_t authSize; + uint64_t dataSize; + bool dataStarted; + uint8_t ivSize; + } state; +}; + +#endif diff --git a/esp32/libraries/crypto/Cipher.cpp b/esp32/libraries/crypto/Cipher.cpp new file mode 100644 index 0000000..f91a14a --- /dev/null +++ b/esp32/libraries/crypto/Cipher.cpp @@ -0,0 +1,154 @@ +/* + * 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 "Cipher.h" + +/** + * \class Cipher Cipher.h + * \brief Abstract base class for stream ciphers. + * + * This class is intended for implementing ciphers that operate on arbitrary + * amounts of data. In particular, stream ciphers where the number of + * bytes that are input to encrypt() or decrypt() is exactly the same as + * the number of bytes that are output. + * + * All of the stream ciphers such as ChaCha inherit directly from this class, + * together with block cipher modes such as CTR and CFB. + */ + +/** + * \brief Constructs a new cipher object. + */ +Cipher::Cipher() +{ +} + +/** + * \brief Destroys this cipher object. + * + * Subclasses are responsible for clearing temporary key schedules + * and other buffers so as to avoid leaking sensitive information. + * + * \sa clear() + */ +Cipher::~Cipher() +{ +} + +/** + * \fn size_t Cipher::keySize() const + * \brief Default size of the key for this cipher, in bytes. + * + * If the cipher supports variable-sized keys, keySize() indicates the + * default or recommended key size. The cipher may support other key sizes. + * + * \sa setKey(), ivSize() + */ + +/** + * \fn size_t Cipher::ivSize() const + * \brief Size of the initialization vector for this cipher, in bytes. + * + * If the cipher does not need an initialization vector, this function + * will return zero. + */ + +/** + * \fn bool Cipher::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 in bytes. + * \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. + * + * Calling setKey() resets the cipher. Any temporary data that was being + * retained for encrypting partial blocks will be abandoned. + * + * \sa keySize(), clear() + */ + +/** + * \fn bool Cipher::setIV(const uint8_t *iv, size_t len) + * \brief Sets the initialization vector to use for future encryption and + * decryption operations. + * + * \param iv The initialization vector to use. + * \param len The length of the initialization vector in bytes. + * \return Returns false if the length is not supported. + * + * Initialization vectors should be set before the first call to + * encrypt() or decrypt() after a setKey() call. If the initialization + * vector is changed after encryption or decryption begins, + * then the behaviour is undefined. + * + * \note The IV is not encoded into the output stream by encrypt(). + * The caller is responsible for communicating the IV to the other party. + * + * \sa ivSize() + */ + +/** + * \fn void Cipher::encrypt(uint8_t *output, const uint8_t *input, size_t len) + * \brief Encrypts an input buffer and writes the ciphertext to an + * output buffer. + * + * \param output The output buffer to write to, which may be the same + * buffer as \a input. The \a output buffer must have at least as many + * bytes as the \a input buffer. + * \param input The input buffer to read from. + * \param len The number of bytes to encrypt. + * + * The encrypt() function can be called multiple times with different + * regions of the plaintext data. + * + * \sa decrypt() + */ + +/** + * \fn void Cipher::decrypt(uint8_t *output, const uint8_t *input, size_t len) + * \brief Decrypts an input buffer and writes the plaintext to an + * output buffer. + * + * \param output The output buffer to write to, which may be the same + * buffer as \a input. The \a output buffer must have at least as many + * bytes as the \a input buffer. + * \param input The input buffer to read from. + * \param len The number of bytes to decrypt. + * + * The decrypt() function can be called multiple times with different + * regions of the ciphertext data. + * + * \sa encrypt() + */ + +/** + * \fn void Cipher::clear() + * \brief Clears all security-sensitive state from this cipher. + * + * Security-sensitive information includes key schedules, initialization + * vectors, and any temporary state that is used by encrypt() or decrypt() + * which is stored in the cipher itself. + */ diff --git a/esp32/libraries/crypto/Cipher.h b/esp32/libraries/crypto/Cipher.h new file mode 100644 index 0000000..8d498d8 --- /dev/null +++ b/esp32/libraries/crypto/Cipher.h @@ -0,0 +1,47 @@ +/* + * 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_CIPHER_h +#define CRYPTO_CIPHER_h + +#include +#include + +class Cipher +{ +public: + Cipher(); + virtual ~Cipher(); + + virtual size_t keySize() const = 0; + virtual size_t ivSize() const = 0; + + virtual bool setKey(const uint8_t *key, size_t len) = 0; + virtual bool setIV(const uint8_t *iv, size_t len) = 0; + + virtual void encrypt(uint8_t *output, const uint8_t *input, size_t len) = 0; + virtual void decrypt(uint8_t *output, const uint8_t *input, size_t len) = 0; + + virtual void clear() = 0; +}; + +#endif diff --git a/esp32/libraries/crypto/Crypto.cpp b/esp32/libraries/crypto/Crypto.cpp new file mode 100644 index 0000000..6c537ba --- /dev/null +++ b/esp32/libraries/crypto/Crypto.cpp @@ -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; +} diff --git a/esp32/libraries/crypto/Crypto.h b/esp32/libraries/crypto/Crypto.h new file mode 100644 index 0000000..b780f25 --- /dev/null +++ b/esp32/libraries/crypto/Crypto.h @@ -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 +#include + +void clean(void *dest, size_t size); + +template +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 diff --git a/esp32/libraries/crypto/Poly1305.cpp b/esp32/libraries/crypto/Poly1305.cpp new file mode 100644 index 0000000..414163c --- /dev/null +++ b/esp32/libraries/crypto/Poly1305.cpp @@ -0,0 +1,345 @@ +/* + * 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 "Poly1305.h" +#include "Crypto.h" +#include "utility/EndianUtil.h" +#include "utility/LimbUtil.h" +#include + +/** + * \class Poly1305 Poly1305.h + * \brief Poly1305 message authenticator + * + * Poly1305 is a message authenticator designed by Daniel J. Bernstein. + * An arbitrary-length message is broken up into 16-byte chunks and fed + * into a polynomial mod 2130 - 5 based on the 16-byte + * authentication key. The final polynomial value is then combined with a + * 16-byte nonce to create the authentication token. + * + * The following example demonstrates how to compute an authentication token + * for a message made up of several blocks under a specific key and nonce: + * + * \code + * Poly1305 poly1305; + * uint8_t token[16]; + * poly1305.reset(key); + * poly1305.update(block1, sizeof(block1)); + * poly1305.update(block2, sizeof(block2)); + * ... + * poly1305.update(blockN, sizeof(blockN)); + * poly1305.finalize(nonce, token, sizeof(token)); + * \endcode + * + * In the original Poly1305 specification, the nonce was encrypted with AES + * and a second 16-byte key. Since then, common practice has been for the + * caller to encrypt the nonce which gives the caller more flexibility as + * to how to derive and/or encrypt the nonce. + * + * References: http://en.wikipedia.org/wiki/Poly1305-AES, + * http://cr.yp.to/mac.html + */ + +// Limb array with enough space for 130 bits. +#define NUM_LIMBS_130BIT (NUM_LIMBS_128BIT + 1) + +// Endian helper macros for limbs and arrays of limbs. +#if BIGNUMBER_LIMB_8BIT +#define lelimbtoh(x) (x) +#define htolelimb(x) (x) +#elif BIGNUMBER_LIMB_16BIT +#define lelimbtoh(x) (le16toh((x))) +#define htolelimb(x) (htole16((x))) +#elif BIGNUMBER_LIMB_32BIT +#define lelimbtoh(x) (le32toh((x))) +#define htolelimb(x) (htole32((x))) +#elif BIGNUMBER_LIMB_64BIT +#define lelimbtoh(x) (le64toh((x))) +#define htolelimb(x) (htole64((x))) +#endif +#if defined(CRYPTO_LITTLE_ENDIAN) +#define littleToHost(r,size) do { ; } while (0) +#else +#define littleToHost(r,size) \ + do { \ + for (uint8_t i = 0; i < (size); ++i) \ + (r)[i] = lelimbtoh((r)[i]); \ + } while (0) +#endif + +/** + * \brief Constructs a new Poly1305 message authenticator. + */ +Poly1305::Poly1305() +{ + state.chunkSize = 0; +} + +/** + * \brief Destroys this Poly1305 message authenticator after clearing all + * sensitive information. + */ +Poly1305::~Poly1305() +{ + clean(state); +} + +/** + * \brief Resets the Poly1305 message authenticator for a new session. + * + * \param key Points to the 16 byte authentication key. + * + * \sa update(), finalize() + */ +void Poly1305::reset(const void *key) +{ + // Copy the key into place and clear the bits we don't need. + uint8_t *r = (uint8_t *)state.r; + memcpy(r, key, 16); + r[3] &= 0x0F; + r[4] &= 0xFC; + r[7] &= 0x0F; + r[8] &= 0xFC; + r[11] &= 0x0F; + r[12] &= 0xFC; + r[15] &= 0x0F; + + // Convert into little-endian if necessary. + littleToHost(state.r, NUM_LIMBS_128BIT); + + // Reset the hashing process. + state.chunkSize = 0; + memset(state.h, 0, sizeof(state.h)); +} + +/** + * \brief Updates the message authenticator 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 authentication process. + * + * \sa pad(), reset(), finalize() + */ +void Poly1305::update(const void *data, size_t len) +{ + // Break the input up into 128-bit chunks and process each in turn. + const uint8_t *d = (const uint8_t *)data; + while (len > 0) { + uint8_t size = 16 - state.chunkSize; + if (size > len) + size = len; + memcpy(((uint8_t *)state.c) + state.chunkSize, d, size); + state.chunkSize += size; + len -= size; + d += size; + if (state.chunkSize == 16) { + littleToHost(state.c, NUM_LIMBS_128BIT); + state.c[NUM_LIMBS_128BIT] = 1; + processChunk(); + state.chunkSize = 0; + } + } +} + +/** + * \brief Finalizes the authentication process and returns the token. + * + * \param nonce Points to the 16-byte nonce to combine with the token. + * \param token The buffer to return the token value in. + * \param len The length of the \a token buffer between 0 and 16. + * + * If \a len is less than 16, then the token value will be truncated to + * the first \a len bytes. If \a len is greater than 16, then the remaining + * bytes will left unchanged. + * + * If finalize() is called again, then the returned \a token value is + * undefined. Call reset() first to start a new authentication process. + * + * \sa reset(), update() + */ +void Poly1305::finalize(const void *nonce, void *token, size_t len) +{ + dlimb_t carry; + uint8_t i; + limb_t t[NUM_LIMBS_256BIT + 1]; + + // Pad and flush the final chunk. + if (state.chunkSize > 0) { + uint8_t *c = (uint8_t *)state.c; + c[state.chunkSize] = 1; + memset(c + state.chunkSize + 1, 0, 16 - state.chunkSize - 1); + littleToHost(state.c, NUM_LIMBS_128BIT); + state.c[NUM_LIMBS_128BIT] = 0; + processChunk(); + } + + // At this point, processChunk() has left h as a partially reduced + // result that is less than (2^130 - 5) * 6. Perform one more + // reduction and a trial subtraction to produce the final result. + + // Multiply the high bits of h by 5 and add them to the 130 low bits. + carry = (dlimb_t)((state.h[NUM_LIMBS_128BIT] >> 2) + + (state.h[NUM_LIMBS_128BIT] & ~((limb_t)3))); + state.h[NUM_LIMBS_128BIT] &= 0x0003; + for (i = 0; i < NUM_LIMBS_128BIT; ++i) { + carry += state.h[i]; + state.h[i] = (limb_t)carry; + carry >>= LIMB_BITS; + } + state.h[i] += (limb_t)carry; + + // Subtract (2^130 - 5) from h by computing t = h + 5 - 2^130. + // The "minus 2^130" step is implicit. + carry = 5; + for (i = 0; i < NUM_LIMBS_130BIT; ++i) { + carry += state.h[i]; + t[i] = (limb_t)carry; + carry >>= LIMB_BITS; + } + + // Borrow occurs if bit 2^130 of the previous t result is zero. + // Carefully turn this into a selection mask so we can select either + // h or t as the final result. We don't care about the highest word + // of the result because we are about to drop it in the next step. + // We have to do it this way to avoid giving away any information + // about the value of h in the instruction timing. + limb_t mask = (~((t[NUM_LIMBS_128BIT] >> 2) & 1)) + 1; + limb_t nmask = ~mask; + for (i = 0; i < NUM_LIMBS_128BIT; ++i) { + state.h[i] = (state.h[i] & nmask) | (t[i] & mask); + } + + // Add the encrypted nonce and format the final hash. + memcpy(state.c, nonce, 16); + littleToHost(state.c, NUM_LIMBS_128BIT); + carry = 0; + for (i = 0; i < NUM_LIMBS_128BIT; ++i) { + carry += state.h[i]; + carry += state.c[i]; + state.h[i] = htolelimb((limb_t)carry); + carry >>= LIMB_BITS; + } + if (len > 16) + len = 16; + memcpy(token, state.h, len); +} + +/** + * \brief Pads the input stream with zero bytes to a multiple of 16. + * + * \sa update() + */ +void Poly1305::pad() +{ + if (state.chunkSize != 0) { + memset(((uint8_t *)state.c) + state.chunkSize, 0, 16 - state.chunkSize); + littleToHost(state.c, NUM_LIMBS_128BIT); + state.c[NUM_LIMBS_128BIT] = 1; + processChunk(); + state.chunkSize = 0; + } +} + +/** + * \brief Clears the authenticator's state, removing all sensitive data. + */ +void Poly1305::clear() +{ + clean(state); +} + +/** + * \brief Processes a single 128-bit chunk of input data. + */ +void Poly1305::processChunk() +{ + limb_t t[NUM_LIMBS_256BIT + 1]; + + // Compute h = ((h + c) * r) mod (2^130 - 5). + + // Start with h += c. We assume that h is less than (2^130 - 5) * 6 + // and that c is less than 2^129, so the result will be less than 2^133. + dlimb_t carry = 0; + uint8_t i, j; + for (i = 0; i < NUM_LIMBS_130BIT; ++i) { + carry += state.h[i]; + carry += state.c[i]; + state.h[i] = (limb_t)carry; + carry >>= LIMB_BITS; + } + + // Multiply h by r. We know that r is less than 2^124 because the + // top 4 bits were AND-ed off by reset(). That makes h * r less + // than 2^257. Which is less than the (2^130 - 6)^2 we want for + // the modulo reduction step that follows. + carry = 0; + limb_t word = state.r[0]; + for (i = 0; i < NUM_LIMBS_130BIT; ++i) { + carry += ((dlimb_t)(state.h[i])) * word; + t[i] = (limb_t)carry; + carry >>= LIMB_BITS; + } + t[NUM_LIMBS_130BIT] = (limb_t)carry; + for (i = 1; i < NUM_LIMBS_128BIT; ++i) { + word = state.r[i]; + carry = 0; + for (j = 0; j < NUM_LIMBS_130BIT; ++j) { + carry += ((dlimb_t)(state.h[j])) * word; + carry += t[i + j]; + t[i + j] = (limb_t)carry; + carry >>= LIMB_BITS; + } + t[i + NUM_LIMBS_130BIT] = (limb_t)carry; + } + + // Reduce h * r modulo (2^130 - 5) by multiplying the high 130 bits by 5 + // and adding them to the low 130 bits. See the explaination in the + // comments for Curve25519::reduce() for a description of how this works. + carry = ((dlimb_t)(t[NUM_LIMBS_128BIT] >> 2)) + + (t[NUM_LIMBS_128BIT] & ~((limb_t)3)); + t[NUM_LIMBS_128BIT] &= 0x0003; + for (i = 0; i < NUM_LIMBS_128BIT; ++i) { + // Shift the next word of t up by (LIMB_BITS - 2) bits and then + // multiply it by 5. Breaking it down, we can add the results + // of shifting up by LIMB_BITS and shifting up by (LIMB_BITS - 2). + // The main wrinkle here is that this can result in an intermediate + // carry that is (LIMB_BITS * 2 + 1) bits in size which doesn't + // fit within a dlimb_t variable. However, we can defer adding + // (word << LIMB_BITS) until after the "carry >>= LIMB_BITS" step + // because it won't affect the low bits of the carry. + word = t[i + NUM_LIMBS_130BIT]; + carry += ((dlimb_t)word) << (LIMB_BITS - 2); + carry += t[i]; + state.h[i] = (limb_t)carry; + carry >>= LIMB_BITS; + carry += word; + } + state.h[i] = (limb_t)(carry + t[NUM_LIMBS_128BIT]); + + // At this point, h is either the answer of reducing modulo (2^130 - 5) + // or it is at most 5 subtractions away from the answer we want. + // Leave it as-is for now with h less than (2^130 - 5) * 6. It is + // still within a range where the next h * r step will not overflow. +} diff --git a/esp32/libraries/crypto/Poly1305.h b/esp32/libraries/crypto/Poly1305.h new file mode 100644 index 0000000..ae1e453 --- /dev/null +++ b/esp32/libraries/crypto/Poly1305.h @@ -0,0 +1,54 @@ +/* + * 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_POLY1305_h +#define CRYPTO_POLY1305_h + +#include "BigNumberUtil.h" +#include + +class Poly1305 +{ +public: + Poly1305(); + ~Poly1305(); + + void reset(const void *key); + void update(const void *data, size_t len); + void finalize(const void *nonce, void *token, size_t len); + + void pad(); + + void clear(); + +private: + struct { + limb_t h[(16 / sizeof(limb_t)) + 1]; + limb_t c[(16 / sizeof(limb_t)) + 1]; + limb_t r[(16 / sizeof(limb_t))]; + uint8_t chunkSize; + } state; + + void processChunk(); +}; + +#endif diff --git a/esp32/libraries/crypto/utility/EndianUtil.h b/esp32/libraries/crypto/utility/EndianUtil.h new file mode 100644 index 0000000..b4e31aa --- /dev/null +++ b/esp32/libraries/crypto/utility/EndianUtil.h @@ -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 + +#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 +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define CRYPTO_LITTLE_ENDIAN 1 +#endif + +#endif // HOST_BUILD + +#endif diff --git a/esp32/libraries/crypto/utility/LimbUtil.h b/esp32/libraries/crypto/utility/LimbUtil.h new file mode 100644 index 0000000..2451f43 --- /dev/null +++ b/esp32/libraries/crypto/utility/LimbUtil.h @@ -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 diff --git a/esp32/libraries/crypto/utility/ProgMemUtil.h b/esp32/libraries/crypto/utility/ProgMemUtil.h new file mode 100644 index 0000000..023154b --- /dev/null +++ b/esp32/libraries/crypto/utility/ProgMemUtil.h @@ -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 +#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 +#define pgm_read_qword(x) \ + (__extension__ ({ \ + const uint32_t *_temp = (const uint32_t *)(x); \ + ((uint64_t)pgm_read_dword(_temp)) | \ + (((uint64_t)pgm_read_dword(_temp + 1)) << 32); \ + })) +#else +#include +#define PROGMEM +#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 diff --git a/esp32/libraries/crypto/utility/RotateUtil.h b/esp32/libraries/crypto/utility/RotateUtil.h new file mode 100644 index 0000000..fcabc82 --- /dev/null +++ b/esp32/libraries/crypto/utility/RotateUtil.h @@ -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 + +// 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 diff --git a/esp32/telelogger/config.h b/esp32/telelogger/config.h index 3d3da3c..f32331d 100644 --- a/esp32/telelogger/config.h +++ b/esp32/telelogger/config.h @@ -96,7 +96,7 @@ #endif #define SERVER_ENCRYPTION_ENABLE 1 -#define CHACHA20_KEY "d38a3b96a26d0b1139bd30c174884f5dbc8eaaf492493725633ecebfa4ab19e9" +#define CHACHA20_KEY "your encryption key here" #ifndef CONFIG_MBEDTLS_CHACHAPOLY_C #define CONFIG_MBEDTLS_CHACHAPOLY_C y diff --git a/server/config.sample.yml b/server/config.sample.yml index c0bc22b..6c5187c 100644 --- a/server/config.sample.yml +++ b/server/config.sample.yml @@ -1,6 +1,9 @@ +# Your encryption key. chacha_key: example123 +# Destinations to forward messages to. +# Multiple destinations are supported. destinations: - 5171: - address: 192.168.1.200 - port: 5171 \ No newline at end of file + 5171: # What port to listen on + address: 192.168.1.200 # The destination address of your Traccar server where messages should be forwared to. + port: 5171 # The destination port Traccar is listening. \ No newline at end of file diff --git a/server/freematics-encrypt.service b/server/freematics-encrypt.service new file mode 100644 index 0000000..313bdf2 --- /dev/null +++ b/server/freematics-encrypt.service @@ -0,0 +1,12 @@ +[Unit] +Description=Freematics Encryption Server +After=network.target + +[Service] +SyslogIdentifier=freematics-encrypt +User=freematics +ExecStart=/srv/freematics/freematics-encrypt -d --config /srv/freematics/config.yml +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/server/src/server.go b/server/src/server.go index 73df44a..060e2a4 100644 --- a/server/src/server.go +++ b/server/src/server.go @@ -52,7 +52,7 @@ func main() { // Validate destinations for port, dest := range config.Destinations { if dest.Address == "" || dest.Port == 0 { - logger.Fatalln("Invalid destination for port %s\n", port) + logger.Fatalln("Invalid destination for port %s", port) } } @@ -73,7 +73,7 @@ func main() { } defer conn.Close() - logger.Infof("Listening on 0.0.0.0:%s\n", port) + logger.Infof("Listening on 0.0.0.0:%s", port) for { buf := make([]byte, 1500) // 1500 is the standard internet MTU.