Compare commits

..

7 Commits

Author SHA1 Message Date
Cyberes 8fae0cd5db fix some things 2024-07-03 19:01:19 -06:00
Cyberes 09602b2745 update gitignore 2024-07-02 22:09:02 -06:00
Cyberes 06d0c28499 adjust a few encryption things 2024-07-02 21:18:25 -06:00
Cyberes 28603b2a2e payload checksum must always be 2 symbols
ad300ec784
2024-07-02 18:24:25 -06:00
Cyberes 19066c2a83 update readme 2024-06-30 19:44:30 -06:00
Cyberes 61075a5e03 option to disable beep, adjust server logging 2024-06-30 19:41:00 -06:00
Cyberes 002c30ccd4 update readme, reorganize files 2024-06-30 19:31:13 -06:00
30 changed files with 3415 additions and 76 deletions

3
.gitignore vendored
View File

@ -1,6 +1,7 @@
.idea .idea
config.yml server/config.yml
.vscode .vscode
*.ino.cpp
# ---> Python # ---> Python
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files

View File

@ -2,5 +2,35 @@
_A proxy to encrypt the Traccar Freematics protocol._ _A proxy to encrypt the Traccar Freematics protocol._
Inspired by previous work: This is an implementation of the ChaCha20-Poly1305 algorithm into
https://github.com/rfhigler/Freematics/commit/25cf781ca9fecc3e3082348ce9d28e4d69ff7764 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.
[Inspired by soshial's great writeup on the Freematics device.](https://gist.github.com/soshial/d07919e0fac67f5501a38fe3c39be416)
### 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.

View File

@ -1,4 +0,0 @@
```shell
git clone https://github.com/rweather/arduinolibs
cp -r arduinolibs/libraries/Crypto Freematics/firmware_v5/telelogger/lib
```

View File

@ -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 <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: <a href="http://tools.ietf.org/html/rfc5116">RFC 5116</a>
*
* \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
* <i>must</i> 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()
*/

View File

@ -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

View File

@ -0,0 +1,769 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "BigNumberUtil.h"
#include "utility/EndianUtil.h"
#include "utility/LimbUtil.h"
#include <string.h>
/**
* \class BigNumberUtil BigNumberUtil.h <BigNumberUtil.h>
* \brief Utilities to assist with implementing big number arithmetic.
*
* Big numbers are represented as arrays of limb_t words, which may be
* 8 bits, 16 bits, or 32 bits in size depending upon how the library
* was configured. For AVR, 16 bit limbs usually give the best performance.
*
* Limb arrays are ordered from the least significant word to the most
* significant.
*/
/**
* \brief Unpacks the little-endian byte representation of a big number
* into a limb array.
*
* \param limbs The limb array, starting with the least significant word.
* \param count The number of elements in the \a limbs array.
* \param bytes The bytes to unpack.
* \param len The number of bytes to unpack.
*
* If \a len is shorter than the length of \a limbs, then the high bytes
* will be filled with zeroes. If \a len is longer than the length of
* \a limbs, then the high bytes will be truncated and lost.
*
* \sa packLE(), unpackBE()
*/
void BigNumberUtil::unpackLE(limb_t *limbs, size_t count,
const uint8_t *bytes, size_t len)
{
#if BIGNUMBER_LIMB_8BIT
if (len < count) {
memcpy(limbs, bytes, len);
memset(limbs + len, 0, count - len);
} else {
memcpy(limbs, bytes, count);
}
#elif CRYPTO_LITTLE_ENDIAN
count *= sizeof(limb_t);
if (len < count) {
memcpy(limbs, bytes, len);
memset(((uint8_t *)limbs) + len, 0, count - len);
} else {
memcpy(limbs, bytes, count);
}
#elif BIGNUMBER_LIMB_16BIT
while (count > 0 && len >= 2) {
*limbs++ = ((limb_t)(bytes[0])) |
(((limb_t)(bytes[1])) << 8);
bytes += 2;
--count;
len -= 2;
}
if (count > 0 && len == 1) {
*limbs++ = ((limb_t)(bytes[0]));
--count;
}
while (count > 0) {
*limbs++ = 0;
--count;
}
#elif BIGNUMBER_LIMB_32BIT
while (count > 0 && len >= 4) {
*limbs++ = ((limb_t)(bytes[0])) |
(((limb_t)(bytes[1])) << 8) |
(((limb_t)(bytes[2])) << 16) |
(((limb_t)(bytes[3])) << 24);
bytes += 4;
--count;
len -= 4;
}
if (count > 0 && len > 0) {
if (len == 3) {
*limbs++ = ((limb_t)(bytes[0])) |
(((limb_t)(bytes[1])) << 8) |
(((limb_t)(bytes[2])) << 16);
} else if (len == 2) {
*limbs++ = ((limb_t)(bytes[0])) |
(((limb_t)(bytes[1])) << 8);
} else {
*limbs++ = ((limb_t)(bytes[0]));
}
--count;
}
while (count > 0) {
*limbs++ = 0;
--count;
}
#elif BIGNUMBER_LIMB_64BIT
while (count > 0 && len >= 8) {
*limbs++ = ((limb_t)(bytes[0])) |
(((limb_t)(bytes[1])) << 8) |
(((limb_t)(bytes[2])) << 16) |
(((limb_t)(bytes[3])) << 24) |
(((limb_t)(bytes[4])) << 32) |
(((limb_t)(bytes[5])) << 40) |
(((limb_t)(bytes[6])) << 48) |
(((limb_t)(bytes[7])) << 56);
bytes += 8;
--count;
len -= 8;
}
if (count > 0 && len > 0) {
limb_t word = 0;
uint8_t shift = 0;
while (len > 0 && shift < 64) {
word |= (((limb_t)(*bytes++)) << shift);
shift += 8;
--len;
}
*limbs++ = word;
--count;
}
while (count > 0) {
*limbs++ = 0;
--count;
}
#endif
}
/**
* \brief Unpacks the big-endian byte representation of a big number
* into a limb array.
*
* \param limbs The limb array, starting with the least significant word.
* \param count The number of elements in the \a limbs array.
* \param bytes The bytes to unpack.
* \param len The number of bytes to unpack.
*
* If \a len is shorter than the length of \a limbs, then the high bytes
* will be filled with zeroes. If \a len is longer than the length of
* \a limbs, then the high bytes will be truncated and lost.
*
* \sa packBE(), unpackLE()
*/
void BigNumberUtil::unpackBE(limb_t *limbs, size_t count,
const uint8_t *bytes, size_t len)
{
#if BIGNUMBER_LIMB_8BIT
while (count > 0 && len > 0) {
--count;
--len;
*limbs++ = bytes[len];
}
memset(limbs, 0, count);
#elif BIGNUMBER_LIMB_16BIT
bytes += len;
while (count > 0 && len >= 2) {
--count;
bytes -= 2;
len -= 2;
*limbs++ = ((limb_t)(bytes[1])) |
(((limb_t)(bytes[0])) << 8);
}
if (count > 0 && len == 1) {
--count;
--bytes;
*limbs++ = (limb_t)(bytes[0]);
}
memset(limbs, 0, count * sizeof(limb_t));
#elif BIGNUMBER_LIMB_32BIT
bytes += len;
while (count > 0 && len >= 4) {
--count;
bytes -= 4;
len -= 4;
*limbs++ = ((limb_t)(bytes[3])) |
(((limb_t)(bytes[2])) << 8) |
(((limb_t)(bytes[1])) << 16) |
(((limb_t)(bytes[0])) << 24);
}
if (count > 0) {
if (len == 3) {
--count;
bytes -= 3;
*limbs++ = ((limb_t)(bytes[2])) |
(((limb_t)(bytes[1])) << 8) |
(((limb_t)(bytes[0])) << 16);
} else if (len == 2) {
--count;
bytes -= 2;
*limbs++ = ((limb_t)(bytes[1])) |
(((limb_t)(bytes[0])) << 8);
} else if (len == 1) {
--count;
--bytes;
*limbs++ = (limb_t)(bytes[0]);
}
}
memset(limbs, 0, count * sizeof(limb_t));
#elif BIGNUMBER_LIMB_64BIT
bytes += len;
while (count > 0 && len >= 8) {
--count;
bytes -= 8;
len -= 8;
*limbs++ = ((limb_t)(bytes[7])) |
(((limb_t)(bytes[6])) << 8) |
(((limb_t)(bytes[5])) << 16) |
(((limb_t)(bytes[4])) << 24) |
(((limb_t)(bytes[3])) << 32) |
(((limb_t)(bytes[2])) << 40) |
(((limb_t)(bytes[1])) << 48) |
(((limb_t)(bytes[0])) << 56);
}
if (count > 0 && len > 0) {
limb_t word = 0;
uint8_t shift = 0;
while (len > 0 && shift < 64) {
word |= (((limb_t)(*(--bytes))) << shift);
shift += 8;
--len;
}
*limbs++ = word;
--count;
}
memset(limbs, 0, count * sizeof(limb_t));
#endif
}
/**
* \brief Packs the little-endian byte representation of a big number
* into a byte array.
*
* \param bytes The byte array to pack into.
* \param len The number of bytes in the destination \a bytes array.
* \param limbs The limb array representing the big number, starting with
* the least significant word.
* \param count The number of elements in the \a limbs array.
*
* If \a len is shorter than the length of \a limbs, then the number will
* be truncated to the least significant \a len bytes. If \a len is longer
* than the length of \a limbs, then the high bytes will be filled with zeroes.
*
* \sa unpackLE(), packBE()
*/
void BigNumberUtil::packLE(uint8_t *bytes, size_t len,
const limb_t *limbs, size_t count)
{
#if BIGNUMBER_LIMB_8BIT
if (len <= count) {
memcpy(bytes, limbs, len);
} else {
memcpy(bytes, limbs, count);
memset(bytes + count, 0, len - count);
}
#elif CRYPTO_LITTLE_ENDIAN
count *= sizeof(limb_t);
if (len <= count) {
memcpy(bytes, limbs, len);
} else {
memcpy(bytes, limbs, count);
memset(bytes + count, 0, len - count);
}
#elif BIGNUMBER_LIMB_16BIT
limb_t word;
while (count > 0 && len >= 2) {
word = *limbs++;
bytes[0] = (uint8_t)word;
bytes[1] = (uint8_t)(word >> 8);
--count;
len -= 2;
bytes += 2;
}
if (count > 0 && len == 1) {
bytes[0] = (uint8_t)(*limbs);
--len;
++bytes;
}
memset(bytes, 0, len);
#elif BIGNUMBER_LIMB_32BIT
limb_t word;
while (count > 0 && len >= 4) {
word = *limbs++;
bytes[0] = (uint8_t)word;
bytes[1] = (uint8_t)(word >> 8);
bytes[2] = (uint8_t)(word >> 16);
bytes[3] = (uint8_t)(word >> 24);
--count;
len -= 4;
bytes += 4;
}
if (count > 0) {
if (len == 3) {
word = *limbs;
bytes[0] = (uint8_t)word;
bytes[1] = (uint8_t)(word >> 8);
bytes[2] = (uint8_t)(word >> 16);
len -= 3;
bytes += 3;
} else if (len == 2) {
word = *limbs;
bytes[0] = (uint8_t)word;
bytes[1] = (uint8_t)(word >> 8);
len -= 2;
bytes += 2;
} else if (len == 1) {
bytes[0] = (uint8_t)(*limbs);
--len;
++bytes;
}
}
memset(bytes, 0, len);
#elif BIGNUMBER_LIMB_64BIT
limb_t word;
while (count > 0 && len >= 8) {
word = *limbs++;
bytes[0] = (uint8_t)word;
bytes[1] = (uint8_t)(word >> 8);
bytes[2] = (uint8_t)(word >> 16);
bytes[3] = (uint8_t)(word >> 24);
bytes[4] = (uint8_t)(word >> 32);
bytes[5] = (uint8_t)(word >> 40);
bytes[6] = (uint8_t)(word >> 48);
bytes[7] = (uint8_t)(word >> 56);
--count;
len -= 8;
bytes += 8;
}
if (count > 0) {
word = *limbs;
while (len > 0) {
*bytes++ = (uint8_t)word;
word >>= 8;
--len;
}
}
memset(bytes, 0, len);
#endif
}
/**
* \brief Packs the big-endian byte representation of a big number
* into a byte array.
*
* \param bytes The byte array to pack into.
* \param len The number of bytes in the destination \a bytes array.
* \param limbs The limb array representing the big number, starting with
* the least significant word.
* \param count The number of elements in the \a limbs array.
*
* If \a len is shorter than the length of \a limbs, then the number will
* be truncated to the least significant \a len bytes. If \a len is longer
* than the length of \a limbs, then the high bytes will be filled with zeroes.
*
* \sa unpackLE(), packBE()
*/
void BigNumberUtil::packBE(uint8_t *bytes, size_t len,
const limb_t *limbs, size_t count)
{
#if BIGNUMBER_LIMB_8BIT
if (len > count) {
size_t size = len - count;
memset(bytes, 0, size);
len -= size;
bytes += size;
} else if (len < count) {
count = len;
}
limbs += count;
while (count > 0) {
--count;
*bytes++ = *(--limbs);
}
#elif BIGNUMBER_LIMB_16BIT
size_t countBytes = count * sizeof(limb_t);
limb_t word;
if (len >= countBytes) {
size_t size = len - countBytes;
memset(bytes, 0, size);
len -= size;
bytes += size;
limbs += count;
} else {
count = len / sizeof(limb_t);
limbs += count;
if ((len & 1) != 0)
*bytes++ = (uint8_t)(*limbs);
}
while (count > 0) {
--count;
word = *(--limbs);
*bytes++ = (uint8_t)(word >> 8);
*bytes++ = (uint8_t)word;
}
#elif BIGNUMBER_LIMB_32BIT
size_t countBytes = count * sizeof(limb_t);
limb_t word;
if (len >= countBytes) {
size_t size = len - countBytes;
memset(bytes, 0, size);
len -= size;
bytes += size;
limbs += count;
} else {
count = len / sizeof(limb_t);
limbs += count;
if ((len & 3) == 3) {
word = *limbs;
*bytes++ = (uint8_t)(word >> 16);
*bytes++ = (uint8_t)(word >> 8);
*bytes++ = (uint8_t)word;
} else if ((len & 3) == 2) {
word = *limbs;
*bytes++ = (uint8_t)(word >> 8);
*bytes++ = (uint8_t)word;
} else if ((len & 3) == 1) {
*bytes++ = (uint8_t)(*limbs);
}
}
while (count > 0) {
--count;
word = *(--limbs);
*bytes++ = (uint8_t)(word >> 24);
*bytes++ = (uint8_t)(word >> 16);
*bytes++ = (uint8_t)(word >> 8);
*bytes++ = (uint8_t)word;
}
#elif BIGNUMBER_LIMB_64BIT
size_t countBytes = count * sizeof(limb_t);
limb_t word;
if (len >= countBytes) {
size_t size = len - countBytes;
memset(bytes, 0, size);
len -= size;
bytes += size;
limbs += count;
} else {
count = len / sizeof(limb_t);
limbs += count;
uint8_t size = len & 7;
uint8_t shift = size * 8;
word = *limbs;
while (size > 0) {
shift -= 8;
*bytes++ = (uint8_t)(word >> shift);
--size;
}
}
while (count > 0) {
--count;
word = *(--limbs);
*bytes++ = (uint8_t)(word >> 56);
*bytes++ = (uint8_t)(word >> 48);
*bytes++ = (uint8_t)(word >> 40);
*bytes++ = (uint8_t)(word >> 32);
*bytes++ = (uint8_t)(word >> 24);
*bytes++ = (uint8_t)(word >> 16);
*bytes++ = (uint8_t)(word >> 8);
*bytes++ = (uint8_t)word;
}
#endif
}
/**
* \brief Adds two big numbers.
*
* \param result The result of the addition. This can be the same
* as either \a x or \a y.
* \param x The first big number.
* \param y The second big number.
* \param size The size of the values in limbs.
*
* \return Returns 1 if there was a carry out or 0 if there was no carry out.
*
* \sa sub(), mul()
*/
limb_t BigNumberUtil::add(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
dlimb_t carry = 0;
while (size > 0) {
carry += *x++;
carry += *y++;
*result++ = (limb_t)carry;
carry >>= LIMB_BITS;
--size;
}
return (limb_t)carry;
}
/**
* \brief Subtracts one big number from another.
*
* \param result The result of the subtraction. This can be the same
* as either \a x or \a y.
* \param x The first big number.
* \param y The second big number to subtract from \a x.
* \param size The size of the values in limbs.
*
* \return Returns 1 if there was a borrow, or 0 if there was no borrow.
*
* \sa add(), mul()
*/
limb_t BigNumberUtil::sub(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
dlimb_t borrow = 0;
while (size > 0) {
borrow = ((dlimb_t)(*x++)) - (*y++) - ((borrow >> LIMB_BITS) & 0x01);
*result++ = (limb_t)borrow;
--size;
}
return ((limb_t)(borrow >> LIMB_BITS)) & 0x01;
}
/**
* \brief Multiplies two big numbers.
*
* \param result The result of the multiplication. The array must be
* \a xcount + \a ycount limbs in size.
* \param x Points to the first value to multiply.
* \param xcount The number of limbs in \a x.
* \param y Points to the second value to multiply.
* \param ycount The number of limbs in \a y.
*
* \sa mul_P()
*/
void BigNumberUtil::mul(limb_t *result, const limb_t *x, size_t xcount,
const limb_t *y, size_t ycount)
{
size_t i, j;
dlimb_t carry;
limb_t word;
const limb_t *xx;
limb_t *rr;
// Multiply the lowest limb of y by x.
carry = 0;
word = y[0];
xx = x;
rr = result;
for (i = 0; i < xcount; ++i) {
carry += ((dlimb_t)(*xx++)) * word;
*rr++ = (limb_t)carry;
carry >>= LIMB_BITS;
}
*rr = (limb_t)carry;
// Multiply and add the remaining limbs of y by x.
for (i = 1; i < ycount; ++i) {
word = y[i];
carry = 0;
xx = x;
rr = result + i;
for (j = 0; j < xcount; ++j) {
carry += ((dlimb_t)(*xx++)) * word;
carry += *rr;
*rr++ = (limb_t)carry;
carry >>= LIMB_BITS;
}
*rr = (limb_t)carry;
}
}
/**
* \brief Reduces \a x modulo \a y using subtraction.
*
* \param result The result of the reduction. This can be the
* same as \a x.
* \param x The number to be reduced.
* \param y The base to use for the modulo reduction.
* \param size The size of the values in limbs.
*
* It is assumed that \a x is less than \a y * 2 so that a single
* conditional subtraction will bring it down below \a y. The reduction
* is performed in constant time.
*
* \sa reduceQuick_P()
*/
void BigNumberUtil::reduceQuick(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
// Subtract "y" from "x" and turn the borrow into an AND mask.
limb_t mask = sub(result, x, y, size);
mask = (~mask) + 1;
// Add "y" back to the result if the mask is non-zero.
dlimb_t carry = 0;
while (size > 0) {
carry += *result;
carry += (*y++ & mask);
*result++ = (limb_t)carry;
carry >>= LIMB_BITS;
--size;
}
}
/**
* \brief Adds two big numbers where one of them is in program memory.
*
* \param result The result of the addition. This can be the same as \a x.
* \param x The first big number.
* \param y The second big number. This must point into program memory.
* \param size The size of the values in limbs.
*
* \return Returns 1 if there was a carry out or 0 if there was no carry out.
*
* \sa sub_P(), mul_P()
*/
limb_t BigNumberUtil::add_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
dlimb_t carry = 0;
while (size > 0) {
carry += *x++;
carry += pgm_read_limb(y++);
*result++ = (limb_t)carry;
carry >>= LIMB_BITS;
--size;
}
return (limb_t)carry;
}
/**
* \brief Subtracts one big number from another where one is in program memory.
*
* \param result The result of the subtraction. This can be the same as \a x.
* \param x The first big number.
* \param y The second big number to subtract from \a x. This must point
* into program memory.
* \param size The size of the values in limbs.
*
* \return Returns 1 if there was a borrow, or 0 if there was no borrow.
*
* \sa add_P(), mul_P()
*/
limb_t BigNumberUtil::sub_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
dlimb_t borrow = 0;
while (size > 0) {
borrow = ((dlimb_t)(*x++)) - pgm_read_limb(y++) - ((borrow >> LIMB_BITS) & 0x01);
*result++ = (limb_t)borrow;
--size;
}
return ((limb_t)(borrow >> LIMB_BITS)) & 0x01;
}
/**
* \brief Multiplies two big numbers where one is in program memory.
*
* \param result The result of the multiplication. The array must be
* \a xcount + \a ycount limbs in size.
* \param x Points to the first value to multiply.
* \param xcount The number of limbs in \a x.
* \param y Points to the second value to multiply. This must point
* into program memory.
* \param ycount The number of limbs in \a y.
*
* \sa mul()
*/
void BigNumberUtil::mul_P(limb_t *result, const limb_t *x, size_t xcount,
const limb_t *y, size_t ycount)
{
size_t i, j;
dlimb_t carry;
limb_t word;
const limb_t *xx;
limb_t *rr;
// Multiply the lowest limb of y by x.
carry = 0;
word = pgm_read_limb(&(y[0]));
xx = x;
rr = result;
for (i = 0; i < xcount; ++i) {
carry += ((dlimb_t)(*xx++)) * word;
*rr++ = (limb_t)carry;
carry >>= LIMB_BITS;
}
*rr = (limb_t)carry;
// Multiply and add the remaining limb of y by x.
for (i = 1; i < ycount; ++i) {
word = pgm_read_limb(&(y[i]));
carry = 0;
xx = x;
rr = result + i;
for (j = 0; j < xcount; ++j) {
carry += ((dlimb_t)(*xx++)) * word;
carry += *rr;
*rr++ = (limb_t)carry;
carry >>= LIMB_BITS;
}
*rr = (limb_t)carry;
}
}
/**
* \brief Reduces \a x modulo \a y using subtraction where \a y is
* in program memory.
*
* \param result The result of the reduction. This can be the
* same as \a x.
* \param x The number to be reduced.
* \param y The base to use for the modulo reduction. This must point
* into program memory.
* \param size The size of the values in limbs.
*
* It is assumed that \a x is less than \a y * 2 so that a single
* conditional subtraction will bring it down below \a y. The reduction
* is performed in constant time.
*
* \sa reduceQuick()
*/
void BigNumberUtil::reduceQuick_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size)
{
// Subtract "y" from "x" and turn the borrow into an AND mask.
limb_t mask = sub_P(result, x, y, size);
mask = (~mask) + 1;
// Add "y" back to the result if the mask is non-zero.
dlimb_t carry = 0;
while (size > 0) {
carry += *result;
carry += (pgm_read_limb(y++) & mask);
*result++ = (limb_t)carry;
carry >>= LIMB_BITS;
--size;
}
}
/**
* \brief Determine if a big number is zero.
*
* \param x Points to the number to test.
* \param size The number of limbs in \a x.
* \return Returns 1 if \a x is zero or 0 otherwise.
*
* This function attempts to make the determination in constant time.
*/
limb_t BigNumberUtil::isZero(const limb_t *x, size_t size)
{
limb_t word = 0;
while (size > 0) {
word |= *x++;
--size;
}
return (limb_t)(((((dlimb_t)1) << LIMB_BITS) - word) >> LIMB_BITS);
}

View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CRYPTO_BIGNUMBERUTIL_h
#define CRYPTO_BIGNUMBERUTIL_h
#include <inttypes.h>
#include <stddef.h>
// Define exactly one of these to 1 to set the size of the basic limb type.
#if defined(__AVR__) || defined(ESP8266)
// 16-bit limbs seem to give the best performance on 8-bit AVR micros.
// They also seem to give better performance on ESP8266 as well.
#define BIGNUMBER_LIMB_8BIT 0
#define BIGNUMBER_LIMB_16BIT 1
#define BIGNUMBER_LIMB_32BIT 0
#define BIGNUMBER_LIMB_64BIT 0
#elif defined(__GNUC__) && __WORDSIZE == 64
// 64-bit system with 128-bit double limbs.
#define BIGNUMBER_LIMB_8BIT 0
#define BIGNUMBER_LIMB_16BIT 0
#define BIGNUMBER_LIMB_32BIT 0
#define BIGNUMBER_LIMB_64BIT 1
#else
// On all other platforms, assume 32-bit is best.
#define BIGNUMBER_LIMB_8BIT 0
#define BIGNUMBER_LIMB_16BIT 0
#define BIGNUMBER_LIMB_32BIT 1
#define BIGNUMBER_LIMB_64BIT 0
#endif
// Define the limb types to use on this platform.
#if BIGNUMBER_LIMB_8BIT
typedef uint8_t limb_t;
typedef int8_t slimb_t;
typedef uint16_t dlimb_t;
#elif BIGNUMBER_LIMB_16BIT
typedef uint16_t limb_t;
typedef int16_t slimb_t;
typedef uint32_t dlimb_t;
#elif BIGNUMBER_LIMB_32BIT
typedef uint32_t limb_t;
typedef int32_t slimb_t;
typedef uint64_t dlimb_t;
#elif BIGNUMBER_LIMB_64BIT
typedef uint64_t limb_t;
typedef int64_t slimb_t;
typedef unsigned __int128 dlimb_t;
#else
#error "limb_t must be 8, 16, 32, or 64 bits in size"
#endif
class BigNumberUtil
{
public:
static void unpackLE(limb_t *limbs, size_t count,
const uint8_t *bytes, size_t len);
static void unpackBE(limb_t *limbs, size_t count,
const uint8_t *bytes, size_t len);
static void packLE(uint8_t *bytes, size_t len,
const limb_t *limbs, size_t count);
static void packBE(uint8_t *bytes, size_t len,
const limb_t *limbs, size_t count);
static limb_t add(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static limb_t sub(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static void mul(limb_t *result, const limb_t *x, size_t xcount,
const limb_t *y, size_t ycount);
static void reduceQuick(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static limb_t add_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static limb_t sub_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static void mul_P(limb_t *result, const limb_t *x, size_t xcount,
const limb_t *y, size_t ycount);
static void reduceQuick_P(limb_t *result, const limb_t *x,
const limb_t *y, size_t size);
static limb_t isZero(const limb_t *x, size_t size);
private:
// Constructor and destructor are private - cannot instantiate this class.
BigNumberUtil() {}
~BigNumberUtil() {}
};
#endif

View File

@ -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 <string.h>
/**
* \class ChaCha ChaCha.h <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]));
}

View File

@ -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

View File

@ -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 <string.h>
/**
* \class ChaChaPoly ChaChaPoly.h <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;
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CRYPTO_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

View File

@ -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 <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.
*/

View File

@ -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 <inttypes.h>
#include <stddef.h>
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

View File

@ -0,0 +1,114 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "Crypto.h"
/**
* \brief Cleans a block of bytes.
*
* \param dest The destination block to be cleaned.
* \param size The size of the destination to be cleaned in bytes.
*
* Unlike memset(), this function attempts to prevent the compiler
* from optimizing away the clear on a memory buffer.
*/
void clean(void *dest, size_t size)
{
// Force the use of volatile so that we actually clear the memory.
// Otherwise the compiler might optimise the entire contents of this
// function away, which will not be secure.
volatile uint8_t *d = (volatile uint8_t *)dest;
while (size > 0) {
*d++ = 0;
--size;
}
}
/**
* \fn void clean(T &var)
* \brief Template function that cleans a variable.
*
* \param var A reference to the variable to clean.
*
* The variable will be cleared to all-zeroes in a secure manner.
* Unlike memset(), this function attempts to prevent the compiler
* from optimizing away the variable clear.
*/
/**
* \brief Compares two memory blocks for equality.
*
* \param data1 Points to the first memory block.
* \param data2 Points to the second memory block.
* \param len The size of the memory blocks in bytes.
*
* Unlike memcmp(), this function attempts to compare the two memory blocks
* in a way that will not reveal the contents in the instruction timing.
* In particular, this function will not stop early if a byte is different.
* It will instead continue onto the end of the array.
*/
bool secure_compare(const void *data1, const void *data2, size_t len)
{
uint8_t result = 0;
const uint8_t *d1 = (const uint8_t *)data1;
const uint8_t *d2 = (const uint8_t *)data2;
while (len > 0) {
result |= (*d1++ ^ *d2++);
--len;
}
return (bool)((((uint16_t)0x0100) - result) >> 8);
}
/**
* \brief Calculates the CRC-8 value over an array in memory.
*
* \param tag Starting tag to distinguish this calculation.
* \param data The data to checksum.
* \param size The number of bytes to checksum.
* \return The CRC-8 value over the data.
*
* This function does not provide any real security. It is a simple
* check that seed values have been initialized within EEPROM or Flash.
* If the CRC-8 check fails, then it is assumed that the EEPROM/Flash
* contents are invalid and should be re-initialized.
*
* Reference: http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html#ch4
*/
uint8_t crypto_crc8(uint8_t tag, const void *data, unsigned size)
{
const uint8_t *d = (const uint8_t *)data;
uint8_t crc = 0xFF ^ tag;
uint8_t bit;
while (size > 0) {
crc ^= *d++;
for (bit = 0; bit < 8; ++bit) {
// if (crc & 0x80)
// crc = (crc << 1) ^ 0x1D;
// else
// crc = (crc << 1);
uint8_t generator = (uint8_t)((((int8_t)crc) >> 7) & 0x1D);
crc = (crc << 1) ^ generator;
}
--size;
}
return crc;
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CRYPTO_h
#define CRYPTO_h
#include <inttypes.h>
#include <stddef.h>
void clean(void *dest, size_t size);
template <typename T>
inline void clean(T &var)
{
clean(&var, sizeof(T));
}
bool secure_compare(const void *data1, const void *data2, size_t len);
#if defined(ESP8266)
extern "C" void system_soft_wdt_feed(void);
#define crypto_feed_watchdog() system_soft_wdt_feed()
#else
#define crypto_feed_watchdog() do { ; } while (0)
#endif
#endif

View File

@ -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 <string.h>
/**
* \class Poly1305 Poly1305.h <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 2<sup>130</sup> - 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.
}

View File

@ -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 <stddef.h>
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

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CRYPTO_ENDIANUTIL_H
#define CRYPTO_ENDIANUTIL_H
#include <inttypes.h>
#if !defined(HOST_BUILD)
// CPU is assumed to be little endian. Edit this file if you
// need to port this library to a big endian CPU.
#define CRYPTO_LITTLE_ENDIAN 1
#define htole16(x) (x)
#define le16toh(x) (x)
#define htobe16(x) \
(__extension__ ({ \
uint16_t _temp = (x); \
((_temp >> 8) & 0x00FF) | \
((_temp << 8) & 0xFF00); \
}))
#define be16toh(x) (htobe16((x)))
#define htole32(x) (x)
#define le32toh(x) (x)
#define htobe32(x) \
(__extension__ ({ \
uint32_t _temp = (x); \
((_temp >> 24) & 0x000000FF) | \
((_temp >> 8) & 0x0000FF00) | \
((_temp << 8) & 0x00FF0000) | \
((_temp << 24) & 0xFF000000); \
}))
#define be32toh(x) (htobe32((x)))
#define htole64(x) (x)
#define le64toh(x) (x)
#define htobe64(x) \
(__extension__ ({ \
uint64_t __temp = (x); \
uint32_t __low = htobe32((uint32_t)__temp); \
uint32_t __high = htobe32((uint32_t)(__temp >> 32)); \
(((uint64_t)__low) << 32) | __high; \
}))
#define be64toh(x) (htobe64((x)))
#else // HOST_BUILD
#include <endian.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define CRYPTO_LITTLE_ENDIAN 1
#endif
#endif // HOST_BUILD
#endif

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CRYPTO_LIMBUTIL_H
#define CRYPTO_LIMBUTIL_H
#include "ProgMemUtil.h"
// Number of limbs in a big number value of various sizes.
#define NUM_LIMBS_BITS(n) \
(((n) + sizeof(limb_t) * 8 - 1) / (8 * sizeof(limb_t)))
#define NUM_LIMBS_128BIT NUM_LIMBS_BITS(128)
#define NUM_LIMBS_256BIT NUM_LIMBS_BITS(256)
#define NUM_LIMBS_512BIT NUM_LIMBS_BITS(512)
// The number of bits in a limb.
#define LIMB_BITS (8 * sizeof(limb_t))
// Read a limb-sized quantity from program memory.
#if BIGNUMBER_LIMB_8BIT
#define pgm_read_limb(x) (pgm_read_byte((x)))
#elif BIGNUMBER_LIMB_16BIT
#define pgm_read_limb(x) (pgm_read_word((x)))
#elif BIGNUMBER_LIMB_32BIT
#define pgm_read_limb(x) (pgm_read_dword((x)))
#elif BIGNUMBER_LIMB_64BIT
#define pgm_read_limb(x) (pgm_read_qword((x)))
#endif
// Expand a 32-bit value into a set of limbs depending upon the limb size.
// This is used when initializing constant big number values in the code.
// For 64-bit system compatibility it is necessary to use LIMB_PAIR(x, y).
#if BIGNUMBER_LIMB_8BIT
#define LIMB(value) ((uint8_t)(value)), \
((uint8_t)((value) >> 8)), \
((uint8_t)((value) >> 16)), \
((uint8_t)((value) >> 24))
#define LIMB_PAIR(x,y) LIMB((x)), LIMB((y))
#elif BIGNUMBER_LIMB_16BIT
#define LIMB(value) ((uint16_t)(value)), \
((uint16_t)(((uint32_t)(value)) >> 16))
#define LIMB_PAIR(x,y) LIMB((x)), LIMB((y))
#elif BIGNUMBER_LIMB_32BIT
#define LIMB(value) (value)
#define LIMB_PAIR(x,y) LIMB((x)), LIMB((y))
#elif BIGNUMBER_LIMB_64BIT
#define LIMB(value) (value)
#define LIMB_PAIR(x,y) ((((uint64_t)(y)) << 32) | ((uint64_t)(x)))
#endif
#endif

View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CRYPTO_PROGMEMUTIL_H
#define CRYPTO_PROGMEMUTIL_H
#if defined(__AVR__)
#include <avr/pgmspace.h>
#define pgm_read_qword(x) \
(__extension__ ({ \
const uint32_t *_temp = (const uint32_t *)(x); \
((uint64_t)pgm_read_dword(_temp)) | \
(((uint64_t)pgm_read_dword(_temp + 1)) << 32); \
}))
#elif defined(ESP8266) || defined(ESP32)
#include <pgmspace.h>
#define pgm_read_qword(x) \
(__extension__ ({ \
const uint32_t *_temp = (const uint32_t *)(x); \
((uint64_t)pgm_read_dword(_temp)) | \
(((uint64_t)pgm_read_dword(_temp + 1)) << 32); \
}))
#else
#include <string.h>
#define PROGMEM
#ifndef pgm_read_byte
# define pgm_read_byte(x) (*(x))
#endif
#ifndef pgm_read_word
# define pgm_read_word(x) (*(x))
#endif
#ifndef pgm_read_dword
# define pgm_read_dword(x) (*(x))
#endif
#ifndef pgm_read_qword
# define pgm_read_qword(x) (*(x))
#endif
#ifndef memcpy_P
# define memcpy_P(d,s,l) memcpy((d), (s), (l))
#endif
#endif
#endif

View File

@ -0,0 +1,696 @@
/*
* Copyright (C) 2015 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CRYPTO_ROTATEUTIL_H
#define CRYPTO_ROTATEUTIL_H
#include <inttypes.h>
// Rotation functions that are optimised for best performance on AVR.
// The most efficient rotations are where the number of bits is 1 or a
// multiple of 8, so we compose the efficient rotations to produce all
// other rotation counts of interest.
#if defined(__AVR__)
#define CRYPTO_ROTATE32_COMPOSED 1
#define CRYPTO_ROTATE64_COMPOSED 0
#else
#define CRYPTO_ROTATE32_COMPOSED 0
#define CRYPTO_ROTATE64_COMPOSED 0
#endif
#if CRYPTO_ROTATE32_COMPOSED
// Rotation macros for 32-bit arguments.
// Generic left rotate - best performance when "bits" is 1 or a multiple of 8.
#define leftRotate(a, bits) \
(__extension__ ({ \
uint32_t _temp = (a); \
(_temp << (bits)) | (_temp >> (32 - (bits))); \
}))
// Generic right rotate - best performance when "bits" is 1 or a multiple of 8.
#define rightRotate(a, bits) \
(__extension__ ({ \
uint32_t _temp = (a); \
(_temp >> (bits)) | (_temp << (32 - (bits))); \
}))
// Left rotate by 1.
#define leftRotate1(a) (leftRotate((a), 1))
// Left rotate by 2.
#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1))
// Left rotate by 3.
#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1))
// Left rotate by 4.
#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1))
// Left rotate by 5: Rotate left by 8, then right by 3.
#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1))
// Left rotate by 6: Rotate left by 8, then right by 2.
#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1))
// Left rotate by 7: Rotate left by 8, then right by 1.
#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1))
// Left rotate by 8.
#define leftRotate8(a) (leftRotate((a), 8))
// Left rotate by 9: Rotate left by 8, then left by 1.
#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1))
// Left rotate by 10: Rotate left by 8, then left by 2.
#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1))
// Left rotate by 11: Rotate left by 8, then left by 3.
#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1))
// Left rotate by 12: Rotate left by 16, then right by 4.
#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1))
// Left rotate by 13: Rotate left by 16, then right by 3.
#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1))
// Left rotate by 14: Rotate left by 16, then right by 2.
#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1))
// Left rotate by 15: Rotate left by 16, then right by 1.
#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1))
// Left rotate by 16.
#define leftRotate16(a) (leftRotate((a), 16))
// Left rotate by 17: Rotate left by 16, then left by 1.
#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1))
// Left rotate by 18: Rotate left by 16, then left by 2.
#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1))
// Left rotate by 19: Rotate left by 16, then left by 3.
#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1))
// Left rotate by 20: Rotate left by 16, then left by 4.
#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1))
// Left rotate by 21: Rotate left by 24, then right by 3.
#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1))
// Left rotate by 22: Rotate left by 24, then right by 2.
#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1))
// Left rotate by 23: Rotate left by 24, then right by 1.
#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1))
// Left rotate by 24.
#define leftRotate24(a) (leftRotate((a), 24))
// Left rotate by 25: Rotate left by 24, then left by 1.
#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1))
// Left rotate by 26: Rotate left by 24, then left by 2.
#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1))
// Left rotate by 27: Rotate left by 24, then left by 3.
#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1))
// Left rotate by 28: Rotate right by 4.
#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1))
// Left rotate by 29: Rotate right by 3.
#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1))
// Left rotate by 30: Rotate right by 2.
#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1))
// Left rotate by 31: Rotate right by 1.
#define leftRotate31(a) (rightRotate((a), 1))
// Define the 32-bit right rotations in terms of left rotations.
#define rightRotate1(a) (leftRotate31((a)))
#define rightRotate2(a) (leftRotate30((a)))
#define rightRotate3(a) (leftRotate29((a)))
#define rightRotate4(a) (leftRotate28((a)))
#define rightRotate5(a) (leftRotate27((a)))
#define rightRotate6(a) (leftRotate26((a)))
#define rightRotate7(a) (leftRotate25((a)))
#define rightRotate8(a) (leftRotate24((a)))
#define rightRotate9(a) (leftRotate23((a)))
#define rightRotate10(a) (leftRotate22((a)))
#define rightRotate11(a) (leftRotate21((a)))
#define rightRotate12(a) (leftRotate20((a)))
#define rightRotate13(a) (leftRotate19((a)))
#define rightRotate14(a) (leftRotate18((a)))
#define rightRotate15(a) (leftRotate17((a)))
#define rightRotate16(a) (leftRotate16((a)))
#define rightRotate17(a) (leftRotate15((a)))
#define rightRotate18(a) (leftRotate14((a)))
#define rightRotate19(a) (leftRotate13((a)))
#define rightRotate20(a) (leftRotate12((a)))
#define rightRotate21(a) (leftRotate11((a)))
#define rightRotate22(a) (leftRotate10((a)))
#define rightRotate23(a) (leftRotate9((a)))
#define rightRotate24(a) (leftRotate8((a)))
#define rightRotate25(a) (leftRotate7((a)))
#define rightRotate26(a) (leftRotate6((a)))
#define rightRotate27(a) (leftRotate5((a)))
#define rightRotate28(a) (leftRotate4((a)))
#define rightRotate29(a) (leftRotate3((a)))
#define rightRotate30(a) (leftRotate2((a)))
#define rightRotate31(a) (leftRotate1((a)))
#else // !CRYPTO_ROTATE32_COMPOSED
// Generic rotation functions. All bit shifts are considered to have
// similar performance. Usually true of 32-bit and higher platforms.
// Rotation macros for 32-bit arguments.
// Generic left rotate.
#define leftRotate(a, bits) \
(__extension__ ({ \
uint32_t _temp = (a); \
(_temp << (bits)) | (_temp >> (32 - (bits))); \
}))
// Generic right rotate.
#define rightRotate(a, bits) \
(__extension__ ({ \
uint32_t _temp = (a); \
(_temp >> (bits)) | (_temp << (32 - (bits))); \
}))
// Left rotate by a specific number of bits.
#define leftRotate1(a) (leftRotate((a), 1))
#define leftRotate2(a) (leftRotate((a), 2))
#define leftRotate3(a) (leftRotate((a), 3))
#define leftRotate4(a) (leftRotate((a), 4))
#define leftRotate5(a) (leftRotate((a), 5))
#define leftRotate6(a) (leftRotate((a), 6))
#define leftRotate7(a) (leftRotate((a), 7))
#define leftRotate8(a) (leftRotate((a), 8))
#define leftRotate9(a) (leftRotate((a), 9))
#define leftRotate10(a) (leftRotate((a), 10))
#define leftRotate11(a) (leftRotate((a), 11))
#define leftRotate12(a) (leftRotate((a), 12))
#define leftRotate13(a) (leftRotate((a), 13))
#define leftRotate14(a) (leftRotate((a), 14))
#define leftRotate15(a) (leftRotate((a), 15))
#define leftRotate16(a) (leftRotate((a), 16))
#define leftRotate17(a) (leftRotate((a), 17))
#define leftRotate18(a) (leftRotate((a), 18))
#define leftRotate19(a) (leftRotate((a), 19))
#define leftRotate20(a) (leftRotate((a), 20))
#define leftRotate21(a) (leftRotate((a), 21))
#define leftRotate22(a) (leftRotate((a), 22))
#define leftRotate23(a) (leftRotate((a), 23))
#define leftRotate24(a) (leftRotate((a), 24))
#define leftRotate25(a) (leftRotate((a), 25))
#define leftRotate26(a) (leftRotate((a), 26))
#define leftRotate27(a) (leftRotate((a), 27))
#define leftRotate28(a) (leftRotate((a), 28))
#define leftRotate29(a) (leftRotate((a), 29))
#define leftRotate30(a) (leftRotate((a), 30))
#define leftRotate31(a) (leftRotate((a), 31))
// Right rotate by a specific number of bits.
#define rightRotate1(a) (rightRotate((a), 1))
#define rightRotate2(a) (rightRotate((a), 2))
#define rightRotate3(a) (rightRotate((a), 3))
#define rightRotate4(a) (rightRotate((a), 4))
#define rightRotate5(a) (rightRotate((a), 5))
#define rightRotate6(a) (rightRotate((a), 6))
#define rightRotate7(a) (rightRotate((a), 7))
#define rightRotate8(a) (rightRotate((a), 8))
#define rightRotate9(a) (rightRotate((a), 9))
#define rightRotate10(a) (rightRotate((a), 10))
#define rightRotate11(a) (rightRotate((a), 11))
#define rightRotate12(a) (rightRotate((a), 12))
#define rightRotate13(a) (rightRotate((a), 13))
#define rightRotate14(a) (rightRotate((a), 14))
#define rightRotate15(a) (rightRotate((a), 15))
#define rightRotate16(a) (rightRotate((a), 16))
#define rightRotate17(a) (rightRotate((a), 17))
#define rightRotate18(a) (rightRotate((a), 18))
#define rightRotate19(a) (rightRotate((a), 19))
#define rightRotate20(a) (rightRotate((a), 20))
#define rightRotate21(a) (rightRotate((a), 21))
#define rightRotate22(a) (rightRotate((a), 22))
#define rightRotate23(a) (rightRotate((a), 23))
#define rightRotate24(a) (rightRotate((a), 24))
#define rightRotate25(a) (rightRotate((a), 25))
#define rightRotate26(a) (rightRotate((a), 26))
#define rightRotate27(a) (rightRotate((a), 27))
#define rightRotate28(a) (rightRotate((a), 28))
#define rightRotate29(a) (rightRotate((a), 29))
#define rightRotate30(a) (rightRotate((a), 30))
#define rightRotate31(a) (rightRotate((a), 31))
#endif // !CRYPTO_ROTATE32_COMPOSED
#if CRYPTO_ROTATE64_COMPOSED
// Rotation macros for 64-bit arguments.
// Generic left rotate - best performance when "bits" is 1 or a multiple of 8.
#define leftRotate_64(a, bits) \
(__extension__ ({ \
uint64_t _temp = (a); \
(_temp << (bits)) | (_temp >> (64 - (bits))); \
}))
// Generic right rotate - best performance when "bits" is 1 or a multiple of 8.
#define rightRotate_64(a, bits) \
(__extension__ ({ \
uint64_t _temp = (a); \
(_temp >> (bits)) | (_temp << (64 - (bits))); \
}))
// Left rotate by 1.
#define leftRotate1_64(a) (leftRotate_64((a), 1))
// Left rotate by 2.
#define leftRotate2_64(a) (leftRotate_64(leftRotate_64((a), 1), 1))
// Left rotate by 3.
#define leftRotate3_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 1), 1), 1))
// Left rotate by 4.
#define leftRotate4_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 1), 1), 1), 1))
// Left rotate by 5: Rotate left by 8, then right by 3.
#define leftRotate5_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 8), 1), 1), 1))
// Left rotate by 6: Rotate left by 8, then right by 2.
#define leftRotate6_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 8), 1), 1))
// Left rotate by 7: Rotate left by 8, then right by 1.
#define leftRotate7_64(a) (rightRotate_64(leftRotate_64((a), 8), 1))
// Left rotate by 8.
#define leftRotate8_64(a) (leftRotate_64((a), 8))
// Left rotate by 9: Rotate left by 8, then left by 1.
#define leftRotate9_64(a) (leftRotate_64(leftRotate_64((a), 8), 1))
// Left rotate by 10: Rotate left by 8, then left by 2.
#define leftRotate10_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 8), 1), 1))
// Left rotate by 11: Rotate left by 8, then left by 3.
#define leftRotate11_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 8), 1), 1), 1))
// Left rotate by 12: Rotate left by 16, then right by 4.
#define leftRotate12_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 16), 1), 1), 1), 1))
// Left rotate by 13: Rotate left by 16, then right by 3.
#define leftRotate13_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 16), 1), 1), 1))
// Left rotate by 14: Rotate left by 16, then right by 2.
#define leftRotate14_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 16), 1), 1))
// Left rotate by 15: Rotate left by 16, then right by 1.
#define leftRotate15_64(a) (rightRotate_64(leftRotate_64((a), 16), 1))
// Left rotate by 16.
#define leftRotate16_64(a) (leftRotate_64((a), 16))
// Left rotate by 17: Rotate left by 16, then left by 1.
#define leftRotate17_64(a) (leftRotate_64(leftRotate_64((a), 16), 1))
// Left rotate by 18: Rotate left by 16, then left by 2.
#define leftRotate18_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 16), 1), 1))
// Left rotate by 19: Rotate left by 16, then left by 3.
#define leftRotate19_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 16), 1), 1), 1))
// Left rotate by 20: Rotate left by 16, then left by 4.
#define leftRotate20_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 16), 1), 1), 1), 1))
// Left rotate by 21: Rotate left by 24, then right by 3.
#define leftRotate21_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 24), 1), 1), 1))
// Left rotate by 22: Rotate left by 24, then right by 2.
#define leftRotate22_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 24), 1), 1))
// Left rotate by 23: Rotate left by 24, then right by 1.
#define leftRotate23_64(a) (rightRotate_64(leftRotate_64((a), 24), 1))
// Left rotate by 24.
#define leftRotate24_64(a) (leftRotate_64((a), 24))
// Left rotate by 25: Rotate left by 24, then left by 1.
#define leftRotate25_64(a) (leftRotate_64(leftRotate_64((a), 24), 1))
// Left rotate by 26: Rotate left by 24, then left by 2.
#define leftRotate26_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 24), 1), 1))
// Left rotate by 27: Rotate left by 24, then left by 3.
#define leftRotate27_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 24), 1), 1), 1))
// Left rotate by 28: Rotate left by 24, then left by 4.
#define leftRotate28_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 24), 1), 1), 1), 1))
// Left rotate by 29: Rotate left by 32, then right by 3.
#define leftRotate29_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 32), 1), 1), 1))
// Left rotate by 30: Rotate left by 32, then right by 2.
#define leftRotate30_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 32), 1), 1))
// Left rotate by 31: Rotate left by 32, then right by 1.
#define leftRotate31_64(a) (rightRotate_64(leftRotate_64((a), 32), 1))
// Left rotate by 32.
#define leftRotate32_64(a) (leftRotate_64((a), 32))
// Left rotate by 33: Rotate left by 32, then left by 1.
#define leftRotate33_64(a) (leftRotate_64(leftRotate_64((a), 32), 1))
// Left rotate by 34: Rotate left by 32, then left by 2.
#define leftRotate34_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 32), 1), 1))
// Left rotate by 35: Rotate left by 32, then left by 3.
#define leftRotate35_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 32), 1), 1), 1))
// Left rotate by 36: Rotate left by 32, then left by 4.
#define leftRotate36_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 32), 1), 1), 1), 1))
// Left rotate by 37: Rotate left by 40, then right by 3.
#define leftRotate37_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 40), 1), 1), 1))
// Left rotate by 38: Rotate left by 40, then right by 2.
#define leftRotate38_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 40), 1), 1))
// Left rotate by 39: Rotate left by 40, then right by 1.
#define leftRotate39_64(a) (rightRotate_64(leftRotate_64((a), 40), 1))
// Left rotate by 40.
#define leftRotate40_64(a) (leftRotate_64((a), 40))
// Left rotate by 41: Rotate left by 40, then left by 1.
#define leftRotate41_64(a) (leftRotate_64(leftRotate_64((a), 40), 1))
// Left rotate by 42: Rotate left by 40, then left by 2.
#define leftRotate42_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 40), 1), 1))
// Left rotate by 43: Rotate left by 40, then left by 3.
#define leftRotate43_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 40), 1), 1), 1))
// Left rotate by 44: Rotate left by 40, then left by 4.
#define leftRotate44_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 40), 1), 1), 1), 1))
// Left rotate by 45: Rotate left by 48, then right by 3.
#define leftRotate45_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 48), 1), 1), 1))
// Left rotate by 46: Rotate left by 48, then right by 2.
#define leftRotate46_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 48), 1), 1))
// Left rotate by 47: Rotate left by 48, then right by 1.
#define leftRotate47_64(a) (rightRotate_64(leftRotate_64((a), 48), 1))
// Left rotate by 48.
#define leftRotate48_64(a) (leftRotate_64((a), 48))
// Left rotate by 49: Rotate left by 48, then left by 1.
#define leftRotate49_64(a) (leftRotate_64(leftRotate_64((a), 48), 1))
// Left rotate by 50: Rotate left by 48, then left by 2.
#define leftRotate50_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 48), 1), 1))
// Left rotate by 51: Rotate left by 48, then left by 3.
#define leftRotate51_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 48), 1), 1), 1))
// Left rotate by 52: Rotate left by 48, then left by 4.
#define leftRotate52_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 48), 1), 1), 1), 1))
// Left rotate by 53: Rotate left by 56, then right by 3.
#define leftRotate53_64(a) (rightRotate_64(rightRotate_64(rightRotate_64(leftRotate_64((a), 56), 1), 1), 1))
// Left rotate by 54: Rotate left by 56, then right by 2.
#define leftRotate54_64(a) (rightRotate_64(rightRotate_64(leftRotate_64((a), 56), 1), 1))
// Left rotate by 55: Rotate left by 56, then right by 1.
#define leftRotate55_64(a) (rightRotate_64(leftRotate_64((a), 56), 1))
// Left rotate by 56.
#define leftRotate56_64(a) (leftRotate_64((a), 56))
// Left rotate by 57: Rotate left by 56, then left by 1.
#define leftRotate57_64(a) (leftRotate_64(leftRotate_64((a), 56), 1))
// Left rotate by 58: Rotate left by 56, then left by 2.
#define leftRotate58_64(a) (leftRotate_64(leftRotate_64(leftRotate_64((a), 56), 1), 1))
// Left rotate by 59: Rotate left by 56, then left by 3.
#define leftRotate59_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 56), 1), 1), 1))
// Left rotate by 60: Rotate left by 60, then left by 4.
#define leftRotate60_64(a) (leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64(leftRotate_64((a), 56), 1), 1), 1), 1))
// Left rotate by 61: Rotate right by 3.
#define leftRotate61_64(a) (rightRotate_64(rightRotate_64(rightRotate_64((a), 1), 1), 1))
// Left rotate by 62: Rotate right by 2.
#define leftRotate62_64(a) (rightRotate_64(rightRotate_64((a), 1), 1))
// Left rotate by 63: Rotate right by 1.
#define leftRotate63_64(a) (rightRotate_64((a), 1))
// Define the 64-bit right rotations in terms of left rotations.
#define rightRotate1_64(a) (leftRotate63_64((a)))
#define rightRotate2_64(a) (leftRotate62_64((a)))
#define rightRotate3_64(a) (leftRotate61_64((a)))
#define rightRotate4_64(a) (leftRotate60_64((a)))
#define rightRotate5_64(a) (leftRotate59_64((a)))
#define rightRotate6_64(a) (leftRotate58_64((a)))
#define rightRotate7_64(a) (leftRotate57_64((a)))
#define rightRotate8_64(a) (leftRotate56_64((a)))
#define rightRotate9_64(a) (leftRotate55_64((a)))
#define rightRotate10_64(a) (leftRotate54_64((a)))
#define rightRotate11_64(a) (leftRotate53_64((a)))
#define rightRotate12_64(a) (leftRotate52_64((a)))
#define rightRotate13_64(a) (leftRotate51_64((a)))
#define rightRotate14_64(a) (leftRotate50_64((a)))
#define rightRotate15_64(a) (leftRotate49_64((a)))
#define rightRotate16_64(a) (leftRotate48_64((a)))
#define rightRotate17_64(a) (leftRotate47_64((a)))
#define rightRotate18_64(a) (leftRotate46_64((a)))
#define rightRotate19_64(a) (leftRotate45_64((a)))
#define rightRotate20_64(a) (leftRotate44_64((a)))
#define rightRotate21_64(a) (leftRotate43_64((a)))
#define rightRotate22_64(a) (leftRotate42_64((a)))
#define rightRotate23_64(a) (leftRotate41_64((a)))
#define rightRotate24_64(a) (leftRotate40_64((a)))
#define rightRotate25_64(a) (leftRotate39_64((a)))
#define rightRotate26_64(a) (leftRotate38_64((a)))
#define rightRotate27_64(a) (leftRotate37_64((a)))
#define rightRotate28_64(a) (leftRotate36_64((a)))
#define rightRotate29_64(a) (leftRotate35_64((a)))
#define rightRotate30_64(a) (leftRotate34_64((a)))
#define rightRotate31_64(a) (leftRotate33_64((a)))
#define rightRotate32_64(a) (leftRotate32_64((a)))
#define rightRotate33_64(a) (leftRotate31_64((a)))
#define rightRotate34_64(a) (leftRotate30_64((a)))
#define rightRotate35_64(a) (leftRotate29_64((a)))
#define rightRotate36_64(a) (leftRotate28_64((a)))
#define rightRotate37_64(a) (leftRotate27_64((a)))
#define rightRotate38_64(a) (leftRotate26_64((a)))
#define rightRotate39_64(a) (leftRotate25_64((a)))
#define rightRotate40_64(a) (leftRotate24_64((a)))
#define rightRotate41_64(a) (leftRotate23_64((a)))
#define rightRotate42_64(a) (leftRotate22_64((a)))
#define rightRotate43_64(a) (leftRotate21_64((a)))
#define rightRotate44_64(a) (leftRotate20_64((a)))
#define rightRotate45_64(a) (leftRotate19_64((a)))
#define rightRotate46_64(a) (leftRotate18_64((a)))
#define rightRotate47_64(a) (leftRotate17_64((a)))
#define rightRotate48_64(a) (leftRotate16_64((a)))
#define rightRotate49_64(a) (leftRotate15_64((a)))
#define rightRotate50_64(a) (leftRotate14_64((a)))
#define rightRotate51_64(a) (leftRotate13_64((a)))
#define rightRotate52_64(a) (leftRotate12_64((a)))
#define rightRotate53_64(a) (leftRotate11_64((a)))
#define rightRotate54_64(a) (leftRotate10_64((a)))
#define rightRotate55_64(a) (leftRotate9_64((a)))
#define rightRotate56_64(a) (leftRotate8_64((a)))
#define rightRotate57_64(a) (leftRotate7_64((a)))
#define rightRotate58_64(a) (leftRotate6_64((a)))
#define rightRotate59_64(a) (leftRotate5_64((a)))
#define rightRotate60_64(a) (leftRotate4_64((a)))
#define rightRotate61_64(a) (leftRotate3_64((a)))
#define rightRotate62_64(a) (leftRotate2_64((a)))
#define rightRotate63_64(a) (leftRotate1_64((a)))
#else // !CRYPTO_ROTATE64_COMPOSED
// Rotation macros for 64-bit arguments.
// Generic left rotate.
#define leftRotate_64(a, bits) \
(__extension__ ({ \
uint64_t _temp = (a); \
(_temp << (bits)) | (_temp >> (64 - (bits))); \
}))
// Generic right rotate.
#define rightRotate_64(a, bits) \
(__extension__ ({ \
uint64_t _temp = (a); \
(_temp >> (bits)) | (_temp << (64 - (bits))); \
}))
// Left rotate by a specific number of bits.
#define leftRotate1_64(a) (leftRotate_64((a), 1))
#define leftRotate2_64(a) (leftRotate_64((a), 2))
#define leftRotate3_64(a) (leftRotate_64((a), 3))
#define leftRotate4_64(a) (leftRotate_64((a), 4))
#define leftRotate5_64(a) (leftRotate_64((a), 5))
#define leftRotate6_64(a) (leftRotate_64((a), 6))
#define leftRotate7_64(a) (leftRotate_64((a), 7))
#define leftRotate8_64(a) (leftRotate_64((a), 8))
#define leftRotate9_64(a) (leftRotate_64((a), 9))
#define leftRotate10_64(a) (leftRotate_64((a), 10))
#define leftRotate11_64(a) (leftRotate_64((a), 11))
#define leftRotate12_64(a) (leftRotate_64((a), 12))
#define leftRotate13_64(a) (leftRotate_64((a), 13))
#define leftRotate14_64(a) (leftRotate_64((a), 14))
#define leftRotate15_64(a) (leftRotate_64((a), 15))
#define leftRotate16_64(a) (leftRotate_64((a), 16))
#define leftRotate17_64(a) (leftRotate_64((a), 17))
#define leftRotate18_64(a) (leftRotate_64((a), 18))
#define leftRotate19_64(a) (leftRotate_64((a), 19))
#define leftRotate20_64(a) (leftRotate_64((a), 20))
#define leftRotate21_64(a) (leftRotate_64((a), 21))
#define leftRotate22_64(a) (leftRotate_64((a), 22))
#define leftRotate23_64(a) (leftRotate_64((a), 23))
#define leftRotate24_64(a) (leftRotate_64((a), 24))
#define leftRotate25_64(a) (leftRotate_64((a), 25))
#define leftRotate26_64(a) (leftRotate_64((a), 26))
#define leftRotate27_64(a) (leftRotate_64((a), 27))
#define leftRotate28_64(a) (leftRotate_64((a), 28))
#define leftRotate29_64(a) (leftRotate_64((a), 29))
#define leftRotate30_64(a) (leftRotate_64((a), 30))
#define leftRotate31_64(a) (leftRotate_64((a), 31))
#define leftRotate32_64(a) (leftRotate_64((a), 32))
#define leftRotate33_64(a) (leftRotate_64((a), 33))
#define leftRotate34_64(a) (leftRotate_64((a), 34))
#define leftRotate35_64(a) (leftRotate_64((a), 35))
#define leftRotate36_64(a) (leftRotate_64((a), 36))
#define leftRotate37_64(a) (leftRotate_64((a), 37))
#define leftRotate38_64(a) (leftRotate_64((a), 38))
#define leftRotate39_64(a) (leftRotate_64((a), 39))
#define leftRotate40_64(a) (leftRotate_64((a), 40))
#define leftRotate41_64(a) (leftRotate_64((a), 41))
#define leftRotate42_64(a) (leftRotate_64((a), 42))
#define leftRotate43_64(a) (leftRotate_64((a), 43))
#define leftRotate44_64(a) (leftRotate_64((a), 44))
#define leftRotate45_64(a) (leftRotate_64((a), 45))
#define leftRotate46_64(a) (leftRotate_64((a), 46))
#define leftRotate47_64(a) (leftRotate_64((a), 47))
#define leftRotate48_64(a) (leftRotate_64((a), 48))
#define leftRotate49_64(a) (leftRotate_64((a), 49))
#define leftRotate50_64(a) (leftRotate_64((a), 50))
#define leftRotate51_64(a) (leftRotate_64((a), 51))
#define leftRotate52_64(a) (leftRotate_64((a), 52))
#define leftRotate53_64(a) (leftRotate_64((a), 53))
#define leftRotate54_64(a) (leftRotate_64((a), 54))
#define leftRotate55_64(a) (leftRotate_64((a), 55))
#define leftRotate56_64(a) (leftRotate_64((a), 56))
#define leftRotate57_64(a) (leftRotate_64((a), 57))
#define leftRotate58_64(a) (leftRotate_64((a), 58))
#define leftRotate59_64(a) (leftRotate_64((a), 59))
#define leftRotate60_64(a) (leftRotate_64((a), 60))
#define leftRotate61_64(a) (leftRotate_64((a), 61))
#define leftRotate62_64(a) (leftRotate_64((a), 62))
#define leftRotate63_64(a) (leftRotate_64((a), 63))
// Right rotate by a specific number of bits.
#define rightRotate1_64(a) (rightRotate_64((a), 1))
#define rightRotate2_64(a) (rightRotate_64((a), 2))
#define rightRotate3_64(a) (rightRotate_64((a), 3))
#define rightRotate4_64(a) (rightRotate_64((a), 4))
#define rightRotate5_64(a) (rightRotate_64((a), 5))
#define rightRotate6_64(a) (rightRotate_64((a), 6))
#define rightRotate7_64(a) (rightRotate_64((a), 7))
#define rightRotate8_64(a) (rightRotate_64((a), 8))
#define rightRotate9_64(a) (rightRotate_64((a), 9))
#define rightRotate10_64(a) (rightRotate_64((a), 10))
#define rightRotate11_64(a) (rightRotate_64((a), 11))
#define rightRotate12_64(a) (rightRotate_64((a), 12))
#define rightRotate13_64(a) (rightRotate_64((a), 13))
#define rightRotate14_64(a) (rightRotate_64((a), 14))
#define rightRotate15_64(a) (rightRotate_64((a), 15))
#define rightRotate16_64(a) (rightRotate_64((a), 16))
#define rightRotate17_64(a) (rightRotate_64((a), 17))
#define rightRotate18_64(a) (rightRotate_64((a), 18))
#define rightRotate19_64(a) (rightRotate_64((a), 19))
#define rightRotate20_64(a) (rightRotate_64((a), 20))
#define rightRotate21_64(a) (rightRotate_64((a), 21))
#define rightRotate22_64(a) (rightRotate_64((a), 22))
#define rightRotate23_64(a) (rightRotate_64((a), 23))
#define rightRotate24_64(a) (rightRotate_64((a), 24))
#define rightRotate25_64(a) (rightRotate_64((a), 25))
#define rightRotate26_64(a) (rightRotate_64((a), 26))
#define rightRotate27_64(a) (rightRotate_64((a), 27))
#define rightRotate28_64(a) (rightRotate_64((a), 28))
#define rightRotate29_64(a) (rightRotate_64((a), 29))
#define rightRotate30_64(a) (rightRotate_64((a), 30))
#define rightRotate31_64(a) (rightRotate_64((a), 31))
#define rightRotate32_64(a) (rightRotate_64((a), 32))
#define rightRotate33_64(a) (rightRotate_64((a), 33))
#define rightRotate34_64(a) (rightRotate_64((a), 34))
#define rightRotate35_64(a) (rightRotate_64((a), 35))
#define rightRotate36_64(a) (rightRotate_64((a), 36))
#define rightRotate37_64(a) (rightRotate_64((a), 37))
#define rightRotate38_64(a) (rightRotate_64((a), 38))
#define rightRotate39_64(a) (rightRotate_64((a), 39))
#define rightRotate40_64(a) (rightRotate_64((a), 40))
#define rightRotate41_64(a) (rightRotate_64((a), 41))
#define rightRotate42_64(a) (rightRotate_64((a), 42))
#define rightRotate43_64(a) (rightRotate_64((a), 43))
#define rightRotate44_64(a) (rightRotate_64((a), 44))
#define rightRotate45_64(a) (rightRotate_64((a), 45))
#define rightRotate46_64(a) (rightRotate_64((a), 46))
#define rightRotate47_64(a) (rightRotate_64((a), 47))
#define rightRotate48_64(a) (rightRotate_64((a), 48))
#define rightRotate49_64(a) (rightRotate_64((a), 49))
#define rightRotate50_64(a) (rightRotate_64((a), 50))
#define rightRotate51_64(a) (rightRotate_64((a), 51))
#define rightRotate52_64(a) (rightRotate_64((a), 52))
#define rightRotate53_64(a) (rightRotate_64((a), 53))
#define rightRotate54_64(a) (rightRotate_64((a), 54))
#define rightRotate55_64(a) (rightRotate_64((a), 55))
#define rightRotate56_64(a) (rightRotate_64((a), 56))
#define rightRotate57_64(a) (rightRotate_64((a), 57))
#define rightRotate58_64(a) (rightRotate_64((a), 58))
#define rightRotate59_64(a) (rightRotate_64((a), 59))
#define rightRotate60_64(a) (rightRotate_64((a), 60))
#define rightRotate61_64(a) (rightRotate_64((a), 61))
#define rightRotate62_64(a) (rightRotate_64((a), 62))
#define rightRotate63_64(a) (rightRotate_64((a), 63))
#endif // !CRYPTO_ROTATE64_COMPOSED
#endif

View File

@ -95,8 +95,11 @@
#define SERVER_PROTOCOL PROTOCOL_UDP #define SERVER_PROTOCOL PROTOCOL_UDP
#endif #endif
// Custom options from this fork
#define SERVER_ENCRYPTION_ENABLE 1 #define SERVER_ENCRYPTION_ENABLE 1
#define CHACHA20_KEY "d38a3b96a26d0b1139bd30c174884f5dbc8eaaf492493725633ecebfa4ab19e9" #define CHACHA20_KEY "your encryption key here"
#define ENABLE_BEEPING 0
// End custom options
#ifndef CONFIG_MBEDTLS_CHACHAPOLY_C #ifndef CONFIG_MBEDTLS_CHACHAPOLY_C
#define CONFIG_MBEDTLS_CHACHAPOLY_C y #define CONFIG_MBEDTLS_CHACHAPOLY_C y

View File

@ -257,11 +257,10 @@ bool TeleClientUDP::notify(byte event, const char* payload)
if (wifi.connected()) if (wifi.connected())
{ {
#if SERVER_ENCRYPTION_ENABLE == 1 #if SERVER_ENCRYPTION_ENABLE == 1
char *orig_send_buf = netbuf.buffer(); unsigned int encrypted_len;
unsigned int orig_send_buf_len = netbuf.length(); unsigned char* encrypted_buf = encrypt_buffer(netbuf.buffer(), netbuf.length(), &encrypted_len);
unsigned char encrypted_buf[12 + orig_send_buf_len + 16]; bool wifi_send = wifi.send((const char *)encrypted_buf, encrypted_len);
encrypt_string((unsigned char *)orig_send_buf, orig_send_buf_len, encrypted_buf); free(encrypted_buf);
if (!wifi.send((const char *)encrypted_buf, sizeof(encrypted_buf))) break;
#else #else
if (!wifi.send(netbuf.buffer(), netbuf.length())) break; if (!wifi.send(netbuf.buffer(), netbuf.length())) break;
#endif #endif
@ -270,11 +269,11 @@ bool TeleClientUDP::notify(byte event, const char* payload)
#endif #endif
{ {
#if SERVER_ENCRYPTION_ENABLE == 1 #if SERVER_ENCRYPTION_ENABLE == 1
char *orig_send_buf = netbuf.buffer(); unsigned int encrypted_len;
unsigned int orig_send_buf_len = netbuf.length(); unsigned char* encrypted_buf = encrypt_buffer(netbuf.buffer(), netbuf.length(), &encrypted_len);
unsigned char encrypted_buf[12 + orig_send_buf_len + 16]; bool cell_send = cell.send((const char *)encrypted_buf, encrypted_len);
encrypt_string((unsigned char *)orig_send_buf, orig_send_buf_len, encrypted_buf); free(encrypted_buf);
if (!cell.send((const char *)encrypted_buf, sizeof(encrypted_buf))) break; if (!cell_send) break;
#else #else
if (!cell.send(netbuf.buffer(), netbuf.length())) break; if (!cell.send(netbuf.buffer(), netbuf.length())) break;
#endif #endif

View File

@ -66,32 +66,10 @@ void decrypt_string(const unsigned char *input, size_t length, unsigned char *ou
size_t decryptedLength = length - sizeof(nonce) - chachaPoly.tagSize(); size_t decryptedLength = length - sizeof(nonce) - chachaPoly.tagSize();
chachaPoly.decrypt(output, input + sizeof(nonce), decryptedLength); chachaPoly.decrypt(output, input + sizeof(nonce), decryptedLength);
// String decryptedString = "";
// for (size_t i = 0; i < decryptedLength; i++) {
// decryptedString += (char)output[i];
// }
// Serial.println(decryptedString);
const unsigned char *tagPtr = input + sizeof(nonce) + decryptedLength; // actual tag const unsigned char *tagPtr = input + sizeof(nonce) + decryptedLength; // actual tag
uint8_t computedTag[16]; // computed tag uint8_t computedTag[16]; // computed tag
chachaPoly.computeTag(computedTag, sizeof(computedTag)); chachaPoly.computeTag(computedTag, sizeof(computedTag));
// Serial.print("Tag: ");
// for (size_t i = 0; i < chachaPoly.tagSize(); i++) {
// Serial.print(tagPtr[i], HEX);
// Serial.print(" ");
// }
// Serial.println();
// Serial.print("Computed Tag: ");
// for (size_t i = 0; i < sizeof(computedTag); i++) {
// Serial.print(computedTag[i], HEX);
// Serial.print(" ");
// }
// Serial.println();
///// BEGIN TAG VERIFY
// The crypto library implementation of tag verification crashes.
// Can never match if the expected tag length is too long. // Can never match if the expected tag length is too long.
if (chachaPoly.tagSize() > 16) { if (chachaPoly.tagSize() > 16) {
Serial.println("[CHACHA] Authentication failed: expected tag length is too long"); Serial.println("[CHACHA] Authentication failed: expected tag length is too long");
@ -100,17 +78,28 @@ void decrypt_string(const unsigned char *input, size_t length, unsigned char *ou
} }
// Compute the tag and check it. // Compute the tag and check it.
// The crypto library implementation of tag verification crashes.
bool equal = secure_compare(computedTag, tagPtr, chachaPoly.tagSize()); bool equal = secure_compare(computedTag, tagPtr, chachaPoly.tagSize());
clean(computedTag); clean(computedTag);
if (!equal) { if (!equal) {
Serial.println("[CHACHA] Authentication failed!"); Serial.println("[CHACHA] Authentication failed!");
output[0] = '\0'; output[0] = '\0';
return; return;
} }
///// END TAG VERIFY
output[decryptedLength] = '\0'; output[decryptedLength] = '\0';
chachaPoly.clear(); chachaPoly.clear();
} }
unsigned char* encrypt_buffer(char* buf, unsigned int len, unsigned int* encrypted_len) {
// Increase the size of encrypted_buf to hold the nonce, the encrypted data, and the authentication tag.
unsigned char* encrypted_buf = (unsigned char*)malloc(12 + len + 16); // 12 bytes for nonce and 16 bytes for tag
if(!encrypted_buf) {
// handle error
return NULL;
}
encrypt_string((unsigned char *)buf, len, encrypted_buf);
*encrypted_len = 12 + len + 16;
return encrypted_buf;
}

View File

@ -7,3 +7,4 @@
void encrypt_string(const unsigned char *input, size_t length, unsigned char *output); void encrypt_string(const unsigned char *input, size_t length, unsigned char *output);
void decrypt_string(const unsigned char *input, size_t length, unsigned char *output); void decrypt_string(const unsigned char *input, size_t length, unsigned char *output);
void print_hex(const unsigned char *data, size_t length); void print_hex(const unsigned char *data, size_t length);
unsigned char* encrypt_buffer(char* buf, unsigned int len, unsigned int* encrypted_len);

View File

@ -62,6 +62,12 @@ PID_POLLING_INFO obdData[]= {
{PID_TIMING_ADVANCE, 2}, {PID_TIMING_ADVANCE, 2},
{PID_COOLANT_TEMP, 3}, {PID_COOLANT_TEMP, 3},
{PID_INTAKE_TEMP, 3}, {PID_INTAKE_TEMP, 3},
{PID_ODOMETER, 3},
{PID_DISTANCE, 3},
{PID_AMBIENT_TEMP, 2},
{PID_ENGINE_OIL_TEMP, 2},
{PID_FUEL_LEVEL, 1}
}; };
CBufferManager bufman; CBufferManager bufman;
@ -175,11 +181,13 @@ void printTimeoutStats()
void beep(int duration) void beep(int duration)
{ {
#if ENABLE_BEEPING
// turn on buzzer at 2000Hz frequency // turn on buzzer at 2000Hz frequency
sys.buzzer(2000); sys.buzzer(2000);
delay(duration); delay(duration);
// turn off buzzer // turn off buzzer
sys.buzzer(0); sys.buzzer(0);
#endif
} }
#if LOG_EXT_SENSORS #if LOG_EXT_SENSORS
@ -1005,12 +1013,11 @@ void telemetry(void* inst)
#endif #endif
#if SERVER_ENCRYPTION_ENABLE == 1 #if SERVER_ENCRYPTION_ENABLE == 1
char *orig_send_buf = store.buffer(); unsigned int encrypted_len;
unsigned int orig_send_buf_len = store.length(); unsigned char* encrypted_buf = encrypt_buffer(store.buffer(), store.length(), &encrypted_len);
// Increase the size of encrypted_buf to hold the nonce, the encrypted data, and the authentication tag. bool transmit_success = teleClient.transmit((const char *)encrypted_buf, encrypted_len);
unsigned char encrypted_buf[12 + orig_send_buf_len + 16]; // 12 bytes for nonce and 16 bytes for tag free(encrypted_buf);
encrypt_string((unsigned char *)orig_send_buf, orig_send_buf_len, encrypted_buf); if (transmit_success) {
if (teleClient.transmit((const char *)encrypted_buf, sizeof(encrypted_buf))) {
#else #else
if (teleClient.transmit(store.buffer(), store.length())) { if (teleClient.transmit(store.buffer(), store.length())) {
#endif #endif

View File

@ -107,7 +107,7 @@ void CStorageRAM::header(const char* devid)
void CStorageRAM::tailer() void CStorageRAM::tailer()
{ {
if (m_cache[m_cacheBytes - 1] == ',') m_cacheBytes--; if (m_cache[m_cacheBytes - 1] == ',') m_cacheBytes--;
m_cacheBytes += sprintf(m_cache + m_cacheBytes, "*%X", (unsigned int)checksum(m_cache, m_cacheBytes)); m_cacheBytes += sprintf(m_cache + m_cacheBytes, "*%02X", (unsigned int)checksum(m_cache, m_cacheBytes));
} }
void CStorageRAM::untailer() void CStorageRAM::untailer()

View File

@ -1,6 +1,9 @@
# Your encryption key.
chacha_key: example123 chacha_key: example123
# Destinations to forward messages to.
# Multiple destinations are supported.
destinations: destinations:
5171: 5171: # What port to listen on
address: 192.168.1.200 address: 192.168.1.200 # The destination address of your Traccar server where messages should be forwared to.
port: 5171 port: 5171 # The destination port Traccar is listening.

View File

@ -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

View File

@ -52,7 +52,7 @@ func main() {
// Validate destinations // Validate destinations
for port, dest := range config.Destinations { for port, dest := range config.Destinations {
if dest.Address == "" || dest.Port == 0 { 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() 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 { for {
buf := make([]byte, 1500) // 1500 is the standard internet MTU. buf := make([]byte, 1500) // 1500 is the standard internet MTU.
@ -84,19 +84,22 @@ func main() {
// Handle the message. // Handle the message.
go func(addr *net.UDPAddr, buf []byte, n int) { go func(addr *net.UDPAddr, buf []byte, n int) {
// Do the decryption.
var plaintext []byte var plaintext []byte
if len(buf[:n]) > 0 { shouldEncrypt := true
plaintext, err = encryption.Decrypt(key, buf[:n]) // Use only the part of the buffer that has data. recievedContent := buf[:n]
if len(recievedContent) > 0 {
plaintext, err = encryption.Decrypt(key, recievedContent) // Use only the part of the buffer that has data.
if err != nil { if err != nil {
rawHex := hex.EncodeToString(buf[:n]) logger.Warningf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf(`Error decrypting message: %s. Length: %d, Raw: "%s"`, err, len(recievedContent), recievedContent)))
logger.Warnf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf(`Error decrypting message: %s. Length: %d, Raw: "%s"`, err, len(rawHex), rawHex))) plaintext = recievedContent // Don't bother with decryption.
// Forward the raw message to the backend without bothering with decryption. shouldEncrypt = false
plaintext = buf[:n] } else {
logger.Infof(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, string(plaintext)))
} }
} else { } else {
plaintext = buf[:n] // If empty message.
logger.Warningln("Got unencrypted message!") plaintext = recievedContent
shouldEncrypt = false
} }
forwardAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", dest.Address, dest.Port)) forwardAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", dest.Address, dest.Port))
@ -105,14 +108,12 @@ func main() {
return return
} }
// Create a new UDP address for listening to the backend server's response.
listenAddr, err := net.ResolveUDPAddr("udp", ":0") // Let the OS pick a free port. listenAddr, err := net.ResolveUDPAddr("udp", ":0") // Let the OS pick a free port.
if err != nil { if err != nil {
logger.Fatalln("Error resolving listen address:", err) logger.Fatalln("Error resolving listen address:", err)
return return
} }
// Create a new UDP listener for the backend server's response.
listenConn, err := net.ListenUDP("udp", listenAddr) listenConn, err := net.ListenUDP("udp", listenAddr)
if err != nil { if err != nil {
logger.Fatalln("Error listening for backend response:", err) logger.Fatalln("Error listening for backend response:", err)
@ -120,7 +121,6 @@ func main() {
} }
defer listenConn.Close() defer listenConn.Close()
// Dial the backend server without binding a local address.
forwardConn, err := net.DialUDP("udp", nil, forwardAddr) forwardConn, err := net.DialUDP("udp", nil, forwardAddr)
if err != nil { if err != nil {
logger.Fatalln("Error dialing to forward address:", err) logger.Fatalln("Error dialing to forward address:", err)
@ -143,11 +143,15 @@ func main() {
return return
} }
// Encrypt the backend's response. var encryptedBackendResponse []byte
encryptedBackendResponse, err := encryption.Encrypt(key, backendResponse[:n]) if shouldEncrypt {
if err != nil { encryptedBackendResponse, err = encryption.Encrypt(key, backendResponse[:n])
logger.Errorf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error encrypting response: %s", err))) if err != nil {
return logger.Errorf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error encrypting response: %s", err)))
return
}
} else {
encryptedBackendResponse = backendResponse
} }
// Forward the encrypted backend response to the client. // Forward the encrypted backend response to the client.
@ -156,8 +160,6 @@ func main() {
logger.Errorf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error forwarding response to client: %s", err))) logger.Errorf(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, fmt.Sprintf("Error forwarding response to client: %s", err)))
return return
} }
logger.Infof(formatLogMsg(addr.IP.String(), dest.Address, dest.Port, string(plaintext)))
}(addr, buf, n) }(addr, buf, n)
} }
}(port, dest) }(port, dest)