diff --git a/README.md b/README.md index cbfd75c7..b1e8c85f 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,12 @@ improvements, please contact the author Rhys Weatherley via Recent significant changes to the library ----------------------------------------- +XXX 2018: + +* KeyRing for storing key pairs and other key material in EEPROM or Flash. +* Add better functions to Curve25519 and Ed25519 for generating key pairs. +* Noise and NoiseLink protocols. + Apr 2018: * Acorn128 and Ascon128 authenticated ciphers (finalists in the CAESAR AEAD diff --git a/doc/Doxyfile b/doc/Doxyfile index 4c60b831..55b4818f 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -661,6 +661,7 @@ INPUT = ../libraries/Crypto \ ../libraries/NewHope \ ../libraries/RingOscillatorNoiseSource \ ../libraries/TransistorNoiseSource \ + ../libraries/NoiseProtocol/src \ . # This tag can be used to specify the character encoding of the source files diff --git a/doc/crypto.dox b/doc/crypto.dox index bc20712c..fb89fd2e 100644 --- a/doc/crypto.dox +++ b/doc/crypto.dox @@ -43,6 +43,7 @@ in the repository: \li Message authenticators: Poly1305, GHASH, OMAC \li Public key algorithms: Curve25519, Ed25519, P521 \li Random number generation: \link RNGClass RNG\endlink +\li Storage of key pairs and other key material in EEPROM or Flash: KeyRing Reduced memory versions of some algorithms (encryption is slower, but the RAM required for the key schedule is less): diff --git a/host/Crypto/Makefile b/host/Crypto/Makefile index 7ac0189a..27acb308 100644 --- a/host/Crypto/Makefile +++ b/host/Crypto/Makefile @@ -6,12 +6,14 @@ SRCDIR = $(TOPDIR)/libraries/Crypto SRCDIR2 = $(TOPDIR)/libraries/NewHope SRCDIR3 = $(TOPDIR)/libraries/CryptoLW SRCDIR4 = $(TOPDIR)/libraries/CryptoLegacy +SRCDIR5 = $(TOPDIR)/libraries/NoiseProtocol #VPATH = $(SRCDIR) vpath %.cpp $(SRCDIR) vpath %.cpp $(SRCDIR2) vpath %.cpp $(SRCDIR3)/src vpath %.cpp $(SRCDIR4)/src +vpath %.cpp $(SRCDIR5)/src vpath %.o . vpath %.ino $(SRCDIR)/examples vpath %.ino $(SRCDIR2)/examples @@ -27,6 +29,7 @@ CPPFLAGS = \ -I$(TOPDIR)/libraries/CryptoLW/src \ -I$(TOPDIR)/libraries/CryptoLegacy/src \ -I$(TOPDIR)/libraries/NewHope \ + -I$(TOPDIR)/libraries/NoiseProtocol \ -DHOST_BUILD CXXFLAGS = -g -Wall $(CPPFLAGS) @@ -58,6 +61,7 @@ SOURCES = \ GHASH.cpp \ Hash.cpp \ KeccakCore.cpp \ + KeyRing.cpp \ NewHope.cpp \ NoiseSource.cpp \ OFB.cpp \ @@ -76,6 +80,39 @@ SOURCES = \ XOF.cpp \ XTS.cpp +SOURCES += \ + NoiseCipherState_AESGCM.cpp \ + NoiseCipherState_ChaChaPoly.cpp \ + NoiseCipherState.cpp \ + NoiseDHState_Curve25519.cpp \ + NoiseDHState.cpp \ + NoiseHandshakeState.cpp \ + Noise_IK_25519_AESGCM_SHA256.cpp \ + Noise_IK_25519_ChaChaPoly_BLAKE2s.cpp \ + Noise_IK_25519_ChaChaPoly_SHA256.cpp \ + Noise_IK.cpp \ + NoiseNamespace.cpp \ + Noise_NNpsk0_25519_AESGCM_SHA256.cpp \ + Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.cpp \ + Noise_NNpsk0_25519_ChaChaPoly_SHA256.cpp \ + Noise_NNpsk0.cpp \ + Noise_Pipes_25519_AESGCM_SHA256.cpp \ + Noise_Pipes_25519_ChaChaPoly_BLAKE2s.cpp \ + Noise_Pipes_25519_ChaChaPoly_SHA256.cpp \ + NoiseProtocolDescriptor.cpp \ + NoiseSymmetricState_AESGCM_SHA256.cpp \ + NoiseSymmetricState_ChaChaPoly_BLAKE2s.cpp \ + NoiseSymmetricState_ChaChaPoly_SHA256.cpp \ + NoiseSymmetricState.cpp \ + Noise_XX_25519_AESGCM_SHA256.cpp \ + Noise_XX_25519_ChaChaPoly_BLAKE2s.cpp \ + Noise_XX_25519_ChaChaPoly_SHA256.cpp \ + Noise_XX.cpp \ + Noise_XXfallback_25519_AESGCM_SHA256.cpp \ + Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.cpp \ + Noise_XXfallback_25519_ChaChaPoly_SHA256.cpp \ + Noise_XXfallback.cpp + SKETCHES = \ TestAcorn/TestAcorn.ino \ TestAES/TestAES.ino \ diff --git a/libraries/Crypto/Curve25519.cpp b/libraries/Crypto/Curve25519.cpp index 84744f04..78f853d2 100644 --- a/libraries/Crypto/Curve25519.cpp +++ b/libraries/Crypto/Curve25519.cpp @@ -70,12 +70,15 @@ * algorithms with the curve. Normally applications should use dh1() * and dh2() directly instead. * + * The secret \a s value may point to a key pair that was generated by the + * Curve25519::generateKeyPair() function. + * * \return Returns true if the function was evaluated; false if \a x is * not a proper member of the field modulo (2^255 - 19). * * Reference: RFC 7748 * - * \sa dh1(), dh2() + * \sa dh1(), dh2(), generateKeyPair() */ bool Curve25519::eval(uint8_t result[32], const uint8_t s[32], const uint8_t x[32]) { @@ -297,6 +300,19 @@ bool Curve25519::dh2(uint8_t k[32], uint8_t f[32]) return (bool)((weak ^ 0x01) & 0x01); } +/** + * \brief Generatea a key pair for the Curve25519 algorithm. + * + * \param keyPair Buffer that returns the key pair, consisting of the + * 32-byte private key followed by the 32-byte public key. + * + * \sa eval() + */ +void Curve25519::generateKeyPair(uint8_t keyPair[64]) +{ + dh1(keyPair + 32, keyPair); +} + /** * \brief Determines if a Curve25519 point is weak for contributory behaviour. * diff --git a/libraries/Crypto/Curve25519.h b/libraries/Crypto/Curve25519.h index b95a9fae..74cc1abd 100644 --- a/libraries/Crypto/Curve25519.h +++ b/libraries/Crypto/Curve25519.h @@ -35,6 +35,8 @@ public: static void dh1(uint8_t k[32], uint8_t f[32]); static bool dh2(uint8_t k[32], uint8_t f[32]); + static void generateKeyPair(uint8_t keyPair[64]); + #if defined(TEST_CURVE25519_FIELD_OPS) public: #else diff --git a/libraries/Crypto/Ed25519.cpp b/libraries/Crypto/Ed25519.cpp index 5732e73b..acb5a28e 100644 --- a/libraries/Crypto/Ed25519.cpp +++ b/libraries/Crypto/Ed25519.cpp @@ -64,6 +64,19 @@ * } * \endcode * + * As an alternative, the private and public components of the key pair + * can be generated as a single 64-byte value: + * + * \code + * uint8_t keyPair[64]; + * Ed25519::generateKeyPair(keyPair); + * Ed25519::sign(signature, keyPair, message, N); + * \endcode + * + * The 64-byte key pair consists of the 32-byte private key followed by + * the 32-byte public key. This should be compatible with other libraries + * that produce and use 64-byte Ed25519 key values. + * * \note The public functions in this class need a substantial amount of * stack space to store intermediate results while the curve function is * being evaluated. About 1.5k of free stack space is recommended for safety. @@ -173,6 +186,18 @@ void Ed25519::sign(uint8_t signature[64], const uint8_t privateKey[32], clean(rB); } +/** + * \fn void Ed25519::sign(uint8_t signature[64], const uint8_t keyPair[64], const void *message, size_t len) + * \brief Signs a message using a specific Ed25519 key pair. + * + * \param signature The signature value. + * \param keyPair The key pair to use to sign the message. + * \param message Points to the message to be signed. + * \param len The length of the \a message to be signed. + * + * \sa verify(), generateKeyPair() + */ + /** * \brief Verifies a signature using a specific Ed25519 public key. * @@ -271,6 +296,20 @@ void Ed25519::derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32 clean(ptA); } +/** + * \brief Generatea a key pair for the Ed25519 algorithm. + * + * \param keyPair Buffer that returns the key pair, consisting of the + * 32-byte private key followed by the 32-byte public key. + * + * \sa sign() + */ +void Ed25519::generateKeyPair(uint8_t keyPair[64]) +{ + generatePrivateKey(keyPair); + derivePublicKey(keyPair + 32, keyPair); +} + /** * \brief Reduces a number modulo q that was specified in a 512 bit buffer. * diff --git a/libraries/Crypto/Ed25519.h b/libraries/Crypto/Ed25519.h index bbdd9f20..b15844cb 100644 --- a/libraries/Crypto/Ed25519.h +++ b/libraries/Crypto/Ed25519.h @@ -32,12 +32,16 @@ public: static void sign(uint8_t signature[64], const uint8_t privateKey[32], const uint8_t publicKey[32], const void *message, size_t len); + static void sign(uint8_t signature[64], const uint8_t keyPair[64], + const void *message, size_t len); static bool verify(const uint8_t signature[64], const uint8_t publicKey[32], const void *message, size_t len); static void generatePrivateKey(uint8_t privateKey[32]); static void derivePublicKey(uint8_t publicKey[32], const uint8_t privateKey[32]); + static void generateKeyPair(uint8_t keyPair[64]); + private: // Constructor and destructor are private - cannot instantiate this class. Ed25519(); @@ -68,4 +72,10 @@ private: static void deriveKeys(SHA512 *hash, limb_t *a, const uint8_t privateKey[32]); }; +inline void Ed25519::sign(uint8_t signature[64], const uint8_t keyPair[64], + const void *message, size_t len) +{ + sign(signature, keyPair, keyPair + 32, message, len); +} + #endif diff --git a/libraries/Crypto/KeyRing.cpp b/libraries/Crypto/KeyRing.cpp new file mode 100644 index 00000000..9ea99159 --- /dev/null +++ b/libraries/Crypto/KeyRing.cpp @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "KeyRing.h" + +/** + * \class KeyRing KeyRing.h + * \brief Permanent storage for key material. + * + * This class provides permanent storage for local key pairs, remote public + * keys, shared symmetric keys, and other data on a device. Other data may + * be certificates, configuration data, or any other information that + * isn't strictly key material. + * + * As an example, the following code will generate a new Curve25519 + * key pair and save it into permanent storage as the default key pair + * for the device: + * + * \code + * uint8_t keyPair[64]; + * Curve25519::generateKeyPair(keyPair); + * KeyRing::setLocalKeyPair(KeyRing::LocalCurve25519Default, keyPair, 64); + * \endcode + * + * Later, when the application needs the key pair it does the following: + * + * \code + * uint8_t keyPair[64]; + * if (!KeyRing::getLocalKeyPair(KeyRing::LocalCurve25519Default, keyPair, 64)) { + * Serial.println("Curve25519 key pair not found!"); + * } else { + * // Make use of the key pair. + * ... + * } + * \endcode + * + * The key ring data is not encrypted in the permanent storage, so the + * data may be compromised if the device is captured. The application can + * arrange to encrypt the values separately before calling the set functions + * in this class. + * + * The data is not encrypted by default because it creates a chicken-and-egg + * problem: where is the encryption key itself stored if the device does + * not have some way to enter a passphrase at runtime? We therefore leave + * the issue of key ring encryption up to the application. + * + * The amount of key data that can be stored is limited by the size of + * the permanent storage mechanism on the device: + * + * \li AVR devices will use no more than 1/2 of the available EEPROM + * space, starting at the end of EEPROM and working backwards. + * \li Arduino Due and ESP8266 allocate up to 8K of flash memory for key data. + * \li ESP32 storage is built on top of that chip's Non-Volatile Storage (NVS) + * mechanism, and is limited only by the maximum NVS size. + * + * If a device is not currently supported, then requests to store values + * in the key ring will fail. Requests to retrieve values from the key + * ring will return nothing. + */ + +/** + * \var KeyRing::LocalCurve25519Default + * \brief Identifier for the default local Curve25519 key pair on the device. + */ + +/** + * \var KeyRing::RemoteCurve25519Default + * \brief Identifier for the default remote Curve25519 public key for the + * primary remote device that this device will be communicating with. + */ + +/** + * \var KeyRing::LocalEd25519Default + * \brief Identifier for the default local Ed25519 key pair on the device. + */ + +/** + * \var KeyRing::RemoteEd25519Default + * \brief Identifier for the default remote Ed25519 public key for the + * primary remote device that this device will be communicating with. + */ + +/** + * \fn bool KeyRing::setLocalKeyPair(uint16_t id, const void *pair, size_t size) + * \brief Sets a local key pair in permanent storage. + * + * \param id Identifier for the key pair to distinguish multiple key pairs + * in the permanent storage. + * \param pair Points to the key pair value, which is assumed to be the + * private key followed by the public key. + * \param size Size of the key pair, including both the private and public + * components. + * + * \return Returns true if the key pair was stored, or false if there is + * insufficient space to store the key pair, or this platform does not have + * permanent storage available. + * + * \sa getLocalKeyPair() + */ + +/** + * \fn size_t KeyRing::getLocalKeyPair(uint16_t id, void *pair, size_t maxSize) + * \brief Gets a local key pair from permanent storage. + * + * \param id Identifier for the key pair to distinguish multiple key pairs + * in the permanent storage. + * \param pair Points to the buffer to retrieve the key pair value, which + * is assumed to consist of the private key followed by the public key. + * \param maxSize Maximum size of the \a pair buffer which may be larger + * than the actual key pair size, to support the retrieval of variable-length + * key pairs. + * + * \return The actual number of bytes in the key pair, or zero if the key + * pair was not found. + * + * The companion function getLocalKeyPairSize() can be used to query the + * size of the key pair before it is retrieved. + * + * \sa getLocalKeyPairSize(), setLocalKeyPair() + */ + +/** + * \fn size_t KeyRing::getLocalKeyPairSize(uint16_t id) + * \brief Gets the size of a local key pair in permanent storage. + * + * \param id Identifier for the key pair to distinguish multiple key pairs + * in the permanent storage. + * + * \return The number of bytes of data that are stored for the key pair, + * or zero if there is no key pair currently associated with \a id. + * + * \sa getLocalKeyPair() + */ + +/** + * \fn void KeyRing::removeLocalKeyPair(uint16_t id) + * \brief Removes a local key pair from permanent storage. + * + * \param id Identifier for the key pair to distinguish multiple key pairs + * in the permanent storage. + * + * The key pair value will be overwritten with 0xFF bytes to erase it. + * However, this may not be sufficient to completely remove all trace of + * the key pair from flash memory or EEPROM. If the underlying storage + * mechanism is performing wear-levelling, then it may leave older copies + * of the value in unused pages when new values are written. + */ + +/** + * \fn bool KeyRing::setRemotePublicKey(uint16_t id, const void *key, size_t size) + * \brief Sets a remote public key in permanent storage. + * + * \param id Identifier for the remote public key to distinguish multiple + * public keys in the permanent storage. + * \param key Points to the public key value. + * \param size Size of the public key value in bytes. + * + * \return Returns true if the public key was stored, or false if there is + * insufficient space to store the public key, or this platform does not have + * permanent storage available. + * + * \sa getRemotePublicKey() + */ + +/** + * \fn size_t KeyRing::getRemotePublicKey(uint16_t id, void *key, size_t maxSize) + * \brief Gets a remote public key from permanent storage. + * + * \param id Identifier for the remote public key to distinguish multiple + * public keys in the permanent storage. + * \param key Points to the buffer to retrieve the public key value. + * \param maxSize Maximum size of the \a key buffer which may be larger + * than the actual public key size, to support the retrieval of + * variable-length public keys. + * + * \return The actual number of bytes in the public key, or zero if the + * public key was not found. + * + * The companion function getRemotePublicKeySize() can be used to query the + * size of the public key before it is retrieved. + * + * \sa getRemotePublicKeySize(), setRemotePublicKey() + */ + +/** + * \fn size_t KeyRing::getRemotePublicKeySize(uint16_t id) + * \brief Gets the size of a remote public key in permanent storage. + * + * \param id Identifier for the remote public key to distinguish multiple + * public keys in the permanent storage. + * + * \return The number of bytes of data that are stored for the public key, + * or zero if there is no public key currently associated with \a id. + * + * \sa getRemotePublicKey() + */ + +/** + * \fn void KeyRing::removeRemotePublicKey(uint16_t id) + * \brief Removes a remote public key from permanent storage. + * + * \param id Identifier for the remote public key to distinguish multiple + * public keys in the permanent storage. + */ + +/** + * \fn bool KeyRing::setSharedSymmetricKey(uint16_t id, const void *key, size_t size) + * \brief Sets a shared symmetric key in permanent storage. + * + * \param id Identifier for the shared symmetric key to distinguish multiple + * keys in the permanent storage. + * \param key Points to the shared symmetric key value. + * \param size Size of the shared symmetric key value in bytes. + * + * \return Returns true if the shared symmetric key was stored, or false if + * there is insufficient space to store the key, or this platform does not + * have permanent storage available. + * + * \sa getSharedSymmetricKey() + */ + +/** + * \fn size_t KeyRing::getSharedSymmetricKey(uint16_t id, void *key, size_t maxSize) + * \brief Gets a shared symmetric key from permanent storage. + * + * \param id Identifier for the shared symmetric key to distinguish multiple + * keys in the permanent storage. + * \param key Points to the buffer to retrieve the shared symmetric key value. + * \param maxSize Maximum size of the \a key buffer which may be larger + * than the actual shared symmetric key size, to support the retrieval of + * variable-length keys. + * + * \return The actual number of bytes in the shared symmetric key, + * or zero if the key was not found. + * + * The companion function getSharedSymmetricKeySize() can be used to + * query the size of the shared symmetric key before it is retrieved. + * + * \sa getSharedSymmetricKeySize(), setSharedSymmetricKey() + */ + +/** + * \fn size_t KeyRing::getSharedSymmetricKeySize(uint16_t id) + * \brief Gets the size of a shared symmetric key in permanent storage. + * + * \param id Identifier for the shared symmetric key to distinguish multiple + * keys in the permanent storage. + * + * \return The number of bytes of data that are stored for the shared + * symmetric key, or zero if there is no key currently associated with \a id. + * + * \sa getSharedSymmetricKey() + */ + +/** + * \fn void KeyRing::removeSharedSymmetricKey(uint16_t id) + * \brief Removes a shared symmetric key from permanent storage. + * + * \param id Identifier for the shared symmetric key to distinguish multiple + * keys in the permanent storage. + * + * The symmetric key value will be overwritten with 0xFF bytes to erase it. + * However, this may not be sufficient to completely remove all trace of + * the key from flash memory or EEPROM. If the underlying storage mechanism + * is performing wear-levelling, then it may leave older copies of the value + * in unused pages when new values are written. + */ + +/** + * \fn bool KeyRing::setOtherData(uint16_t id, const void *data, size_t size); + * \brief Sets an arbitrary data value in permanent storage. + * + * \param id Identifier for the data value to distinguish multiple values + * in the permanent storage. + * \param data Points to the data value to store. + * \param size Size of the data value in bytes. + * + * \return Returns true if the data value was stored, or false if there is + * insufficient space to store the value, or this platform does not have + * permanent storage available. + * + * \sa getOtherData() + */ + +/** + * \fn size_t KeyRing::getOtherData(uint16_t id, void *data, size_t maxSize) + * \brief Gets an arbitrary data value from permanent storage. + * + * \param id Identifier for the data value to distinguish multiple values + * in the permanent storage. + * \param data Points to the buffer to retrieve the data value. + * \param maxSize Maximum size of the \a data buffer which may be larger + * than the actual data value size, to support the retrieval of + * variable-length values. + * + * \return The actual number of bytes in the data value, or zero if the value + * was not found. + * + * The companion function getOtherDataSize() can be used to query the size of + * the data value before it is retrieved. + * + * \sa getOtherDataSize(), setOtherData() + */ + +/** + * \fn size_t KeyRing::getOtherDataSize(uint16_t id) + * \brief Gets the size of an arbitrary data value in permanent storage. + * + * \param id Identifier for the data value to distinguish multiple values + * in the permanent storage. + * + * \return The number of bytes of data that are stored for the value, + * or zero if there is no value currently associated with \a id. + * + * \sa getOtherData() + */ + +/** + * \fn void KeyRing::removeOtherData(uint16_t id) + * \brief Removes an arbitrary data value from permanent storage. + * + * \param id Identifier for the data value to distinguish multiple values + * in the permanent storage. + */ + +bool KeyRing::set(uint16_t id, uint8_t type, const void *data, size_t size) +{ + // TODO + return false; +} + +size_t KeyRing::get(uint16_t id, uint8_t type, void *data, size_t maxSize) +{ + // TODO + return 0; +} + +size_t KeyRing::getSize(uint16_t id, uint8_t type) +{ + // TODO + return 0; +} + +void KeyRing::remove(uint16_t id, uint8_t type) +{ + // TODO +} diff --git a/libraries/Crypto/KeyRing.h b/libraries/Crypto/KeyRing.h new file mode 100644 index 00000000..906cda6c --- /dev/null +++ b/libraries/Crypto/KeyRing.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef KEY_RING_h +#define KEY_RING_h + +#include +#include + +class KeyRing +{ +private: + KeyRing() {} + ~KeyRing() {} + +public: + static bool setLocalKeyPair + (uint16_t id, const void *pair, size_t size); + static size_t getLocalKeyPair + (uint16_t id, void *pair, size_t maxSize); + static size_t getLocalKeyPairSize(uint16_t id); + static void removeLocalKeyPair(uint16_t id); + + static bool setRemotePublicKey + (uint16_t id, const void *key, size_t size); + static size_t getRemotePublicKey + (uint16_t id, void *key, size_t maxSize); + static size_t getRemotePublicKeySize(uint16_t id); + static void removeRemotePublicKey(uint16_t id); + + static bool setSharedSymmetricKey + (uint16_t id, const void *key, size_t size); + static size_t getSharedSymmetricKey + (uint16_t id, void *key, size_t maxSize); + static size_t getSharedSymmetricKeySize(uint16_t id); + static void removeSharedSymmetricKey(uint16_t id); + + static bool setOtherData + (uint16_t id, const void *data, size_t size); + static size_t getOtherData + (uint16_t id, void *data, size_t maxSize); + static size_t getOtherDataSize(uint16_t id); + static void removeOtherData(uint16_t id); + + static const uint16_t LocalCurve25519Default = 0x4301; // 'C', 0x01 + static const uint16_t RemoteCurve25519Default = 0x6301; // 'c', 0x01 + + static const uint16_t LocalEd25519Default = 0x4501; // 'E', 0x01 + static const uint16_t RemoteEd25519Default = 0x6501; // 'e', 0x01 + +private: + static bool set(uint16_t id, uint8_t type, const void *data, size_t size); + static size_t get(uint16_t id, uint8_t type, void *data, size_t maxSize); + static size_t getSize(uint16_t id, uint8_t type); + static void remove(uint16_t id, uint8_t type); +}; + +inline bool KeyRing::setLocalKeyPair + (uint16_t id, const void *pair, size_t size) +{ + return set(id, 0, pair, size); +} + +inline size_t KeyRing::getLocalKeyPair + (uint16_t id, void *pair, size_t maxSize) +{ + return get(id, 0, pair, maxSize); +} + +inline size_t KeyRing::getLocalKeyPairSize(uint16_t id) +{ + return getSize(id, 0); +} + +inline void KeyRing::removeLocalKeyPair(uint16_t id) +{ + remove(id, 0); +} + +inline bool KeyRing::setRemotePublicKey + (uint16_t id, const void *key, size_t size) +{ + return set(id, 1, key, size); +} + +inline size_t KeyRing::getRemotePublicKey + (uint16_t id, void *key, size_t maxSize) +{ + return get(id, 1, key, maxSize); +} + +inline size_t KeyRing::getRemotePublicKeySize(uint16_t id) +{ + return getSize(id, 1); +} + +inline void KeyRing::removeRemotePublicKey(uint16_t id) +{ + remove(id, 1); +} + +inline bool KeyRing::setSharedSymmetricKey + (uint16_t id, const void *key, size_t size) +{ + return set(id, 2, key, size); +} + +inline size_t KeyRing::getSharedSymmetricKey + (uint16_t id, void *key, size_t maxSize) +{ + return get(id, 2, key, maxSize); +} + +inline size_t KeyRing::getSharedSymmetricKeySize(uint16_t id) +{ + return getSize(id, 2); +} + +inline void KeyRing::removeSharedSymmetricKey(uint16_t id) +{ + remove(id, 2); +} + +inline bool KeyRing::setOtherData + (uint16_t id, const void *data, size_t size) +{ + return set(id, 3, data, size); +} + +inline size_t KeyRing::getOtherData + (uint16_t id, void *data, size_t maxSize) +{ + return get(id, 3, data, maxSize); +} + +inline size_t KeyRing::getOtherDataSize(uint16_t id) +{ + return getSize(id, 3); +} + +inline void KeyRing::removeOtherData(uint16_t id) +{ + remove(id, 3); +} + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseCipherState.cpp b/libraries/NoiseProtocol/src/NoiseCipherState.cpp new file mode 100644 index 00000000..36f76d2a --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseCipherState.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseCipherState.h" + +/** + * \class NoiseCipherState NoiseCipherState.h + * \brief Abstract base class for the Noise protocol's cipher state. + * + * This class is abstract. The caller should instantiate a subclass like + * NoiseCipherState_ChaChaPoly or NoiseCipherState_AESGCM to choose the + * specific algorithm to use in the cipher state. + * + * Normally the application will not instantiate instances of this + * class or its subclasses directly. Instead, it will call + * NoiseHandshakeState::split() at the end of the handshake phase + * of a connection. + */ + +/** + * \fn NoiseCipherState::NoiseCipherState() + * \brief Constructs a new cipher object. + */ + +/** + * \brief Destroys this cipher object. + */ +NoiseCipherState::~NoiseCipherState() +{ +} + +/** + * \fn void NoiseCipherState::setNonce(uint64_t nonce) + * \brief Sets the nonce value for the next packet to be encrypted or + * decrypted. + * + * \param nonce The nonce value between 0 and 2^64 - 2. + * + * You won't need to use this function on reliable transports like TCP. + * You may need to use this function on unreliable transports like UDP. + * Care must be taken not to use the same nonce with multiple packets, + * and to reject duplicate packets. + */ + +/** + * \fn int NoiseCipherState::encryptPacket(void *output, size_t outputSize, const void *input, size_t inputSize) + * \brief Encrypts a packet in a Noise transport session. + * + * \param output Output buffer to write the ciphertext and MAC to. + * \param outputSize Available space in the \a output buffer. + * \param input Input buffer containing the plaintext to be encrypted. + * \param inputSize Number of bytes of plaintext. + * + * \return The number of bytes that were written to \a output. + * \return -1 if \a outputSize is not large enough to contain the + * ciphertext and MAC. + * + * MAC values will add an extra 16 bytes to the size of the packet. + * + * \sa decryptPacket() + */ + +/** + * \fn int NoiseCipherState::decryptPacket(void *output, size_t outputSize, const void *input, size_t inputSize) + * \brief Decrypts a packet in a Noise transport session. + * + * \param output Output buffer to write the plaintext to. + * \param outputSize Available space in the \a output buffer. + * \param input Input buffer containing the ciphertext and MAC. + * \param inputSize Number of bytes of ciphertext plus the MAC. + * + * \return The number of bytes that were written to \a output. + * \return -1 if \a outputSize is not large enough to contain the plaintext. + * \return -1 if the MAC check failed; the plaintext output will be invalid. + * + * \sa encryptPacket() + */ + +/** + * \fn void NoiseCipherState::rekey() + * \brief Rekey the cipher object. + * + * This function should be called periodically to refresh the key that is + * used to encrypt data. This avoids the same key being used over and over + * as the more data that is encrypted with the same key, the more likely + * statistical trends may reveal themselves to an attacker. + */ + +/** + * \fn void NoiseCipherState::clear() + * \brief Destroys sensitive data in this cipher object. + * + * After this function is called, no more packets can be encrypted or + * decrypted and a new cipher object must be created. + */ diff --git a/libraries/NoiseProtocol/src/NoiseCipherState.h b/libraries/NoiseProtocol/src/NoiseCipherState.h new file mode 100644 index 00000000..b90b4c2f --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseCipherState.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_CIPHER_STATE_h +#define NOISE_CIPHER_STATE_h + +#include +#include + +class NoiseCipherState +{ +public: + NoiseCipherState() {} + virtual ~NoiseCipherState(); + + virtual void setNonce(uint64_t nonce) = 0; + + virtual int encryptPacket + (void *output, size_t outputSize, + const void *input, size_t inputSize) = 0; + virtual int decryptPacket + (void *output, size_t outputSize, + const void *input, size_t inputSize) = 0; + + virtual void rekey() = 0; + + virtual void clear() = 0; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseCipherState_AESGCM.cpp b/libraries/NoiseProtocol/src/NoiseCipherState_AESGCM.cpp new file mode 100644 index 00000000..5344ef00 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseCipherState_AESGCM.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseCipherState_AESGCM.h" +#include "Crypto.h" +#include + +/** + * \class NoiseCipherState_AESGCM NoiseCipherState_AESGCM.h + * \brief Implementation of the AESGCM cipher + */ + +/** + * \brief Constructs a new AESGCM cipher object. + * + * \param key The 256-bit key for the cipher object. + */ +NoiseCipherState_AESGCM::NoiseCipherState_AESGCM(const uint8_t key[32]) +{ + cipher.setKey(key, 32); + n = 0; +} + +/** + * \brief Destroys this AESGCM cipher object. + */ +NoiseCipherState_AESGCM::~NoiseCipherState_AESGCM() +{ + clean(&n, sizeof(n)); +} + +void NoiseCipherState_AESGCM::setNonce(uint64_t nonce) +{ + n = nonce; +} + +// Import from NoiseSymmetricState_AESGCM_SHA256.cpp. +void noiseAESGCMFormatIV(uint8_t iv[12], uint64_t n); + +int NoiseCipherState_AESGCM::encryptPacket + (void *output, size_t outputSize, const void *input, size_t inputSize) +{ + if (outputSize < 16 || (outputSize - 16) < inputSize) + return -1; + uint8_t iv[12]; + noiseAESGCMFormatIV(iv, n); + cipher.setIV(iv, sizeof(iv)); + cipher.encrypt((uint8_t *)output, (const uint8_t *)input, inputSize); + cipher.computeTag(((uint8_t *)output) + inputSize, 16); + ++n; + return inputSize + 16; +} + +int NoiseCipherState_AESGCM::decryptPacket + (void *output, size_t outputSize, const void *input, size_t inputSize) +{ + if (inputSize < 16 || outputSize < (inputSize - 16)) + return -1; + uint8_t iv[12]; + noiseAESGCMFormatIV(iv, n); + cipher.setIV((const uint8_t *)&iv, sizeof(iv)); + cipher.decrypt((uint8_t *)output, (const uint8_t *)input, outputSize); + if (cipher.checkTag(((const uint8_t *)input) + outputSize, 16)) { + ++n; + return outputSize; + } + memset(output, 0, outputSize); // Destroy the output if the tag is invalid. + return -1; +} + +void NoiseCipherState_AESGCM::rekey() +{ + uint8_t k[32]; + static uint8_t const iv[12] = { + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + memset(k, 0, sizeof(k)); + cipher.setIV(iv, sizeof(iv)); + cipher.encrypt(k, k, sizeof(k)); + cipher.setKey(k, sizeof(k)); + clean(k); +} + +void NoiseCipherState_AESGCM::clear() +{ + cipher.clear(); + n = 0; +} diff --git a/libraries/NoiseProtocol/src/NoiseCipherState_AESGCM.h b/libraries/NoiseProtocol/src/NoiseCipherState_AESGCM.h new file mode 100644 index 00000000..8b62d745 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseCipherState_AESGCM.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_CIPHER_STATE_AESGCM_h +#define NOISE_CIPHER_STATE_AESGCM_h + +#include "NoiseCipherState.h" +#include "AES.h" +#include "GCM.h" + +class NoiseCipherState_AESGCM : public NoiseCipherState +{ +public: + explicit NoiseCipherState_AESGCM(const uint8_t key[32]); + virtual ~NoiseCipherState_AESGCM(); + + void setNonce(uint64_t nonce); + + int encryptPacket + (void *output, size_t outputSize, + const void *input, size_t inputSize); + int decryptPacket + (void *output, size_t outputSize, + const void *input, size_t inputSize); + + void rekey(); + + void clear(); + +private: + GCM cipher; + uint64_t n; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseCipherState_ChaChaPoly.cpp b/libraries/NoiseProtocol/src/NoiseCipherState_ChaChaPoly.cpp new file mode 100644 index 00000000..2a600a6b --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseCipherState_ChaChaPoly.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseCipherState_ChaChaPoly.h" +#include "Crypto.h" +#include "utility/EndianUtil.h" +#include + +/** + * \class NoiseCipherState_ChaChaPoly NoiseCipherState_ChaChaPoly.h + * \brief Implementation of the ChaChaPoly cipher + */ + +/** + * \brief Constructs a new ChaChaPoly cipher object. + * + * \param key The 256-bit key for the cipher object. + */ +NoiseCipherState_ChaChaPoly::NoiseCipherState_ChaChaPoly(const uint8_t key[32]) +{ + cipher.setKey(key, 32); + n = 0; +} + +/** + * \brief Destroys this ChaChaPoly cipher object. + */ +NoiseCipherState_ChaChaPoly::~NoiseCipherState_ChaChaPoly() +{ + clean(&n, sizeof(n)); +} + +void NoiseCipherState_ChaChaPoly::setNonce(uint64_t nonce) +{ + n = nonce; +} + +int NoiseCipherState_ChaChaPoly::encryptPacket + (void *output, size_t outputSize, const void *input, size_t inputSize) +{ + if (outputSize < 16 || (outputSize - 16) < inputSize) + return -1; + uint64_t iv = htole64(n); + cipher.setIV((const uint8_t *)&iv, sizeof(iv)); + cipher.encrypt((uint8_t *)output, (const uint8_t *)input, inputSize); + cipher.computeTag(((uint8_t *)output) + inputSize, 16); + ++n; + return inputSize + 16; +} + +int NoiseCipherState_ChaChaPoly::decryptPacket + (void *output, size_t outputSize, const void *input, size_t inputSize) +{ + if (inputSize < 16 || outputSize < (inputSize - 16)) + return -1; + uint64_t iv = htole64(n); + outputSize = inputSize - 16; + cipher.setIV((const uint8_t *)&iv, sizeof(iv)); + cipher.decrypt((uint8_t *)output, (const uint8_t *)input, outputSize); + if (cipher.checkTag(((const uint8_t *)input) + outputSize, 16)) { + ++n; + return outputSize; + } + memset(output, 0, outputSize); // Destroy the output if the tag is invalid. + return -1; +} + +void NoiseCipherState_ChaChaPoly::rekey() +{ + uint8_t k[32]; + uint64_t iv = 0xFFFFFFFFFFFFFFFFULL; + memset(k, 0, sizeof(k)); + cipher.setIV((const uint8_t *)&iv, sizeof(iv)); + cipher.encrypt(k, k, sizeof(k)); + cipher.setKey(k, sizeof(k)); + clean(k); +} + +void NoiseCipherState_ChaChaPoly::clear() +{ + cipher.clear(); + n = 0; +} diff --git a/libraries/NoiseProtocol/src/NoiseCipherState_ChaChaPoly.h b/libraries/NoiseProtocol/src/NoiseCipherState_ChaChaPoly.h new file mode 100644 index 00000000..b1ecb280 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseCipherState_ChaChaPoly.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_CIPHER_STATE_CHACHAPOLY_h +#define NOISE_CIPHER_STATE_CHACHAPOLY_h + +#include "NoiseCipherState.h" +#include "ChaChaPoly.h" + +class NoiseCipherState_ChaChaPoly : public NoiseCipherState +{ +public: + explicit NoiseCipherState_ChaChaPoly(const uint8_t key[32]); + virtual ~NoiseCipherState_ChaChaPoly(); + + void setNonce(uint64_t nonce); + + int encryptPacket + (void *output, size_t outputSize, + const void *input, size_t inputSize); + int decryptPacket + (void *output, size_t outputSize, + const void *input, size_t inputSize); + + void rekey(); + + void clear(); + +private: + ChaChaPoly cipher; + uint64_t n; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseDHState.cpp b/libraries/NoiseProtocol/src/NoiseDHState.cpp new file mode 100644 index 00000000..a2466a25 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseDHState.cpp @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseDHState.h" +#include + +/** + * \class NoiseDHState NoiseDHState.h + * \brief Abstract base class for Diffie-Hellman (DH) algorithms for Noise. + * + * This API defines how NoiseHandshakeState interacts with the DH + * algorithm to set local keys, query remote keys, generate ephemeral + * key pairs, etc. Subclasses implement specific DH algorithms, such as + * NoiseDHState_Curve25519. + */ + +/** + * \fn NoiseDHState::NoiseDHState() + * \brief Constructs a new DH state object. + */ + +/** + * \brief Destroys this DH state object. + */ +NoiseDHState::~NoiseDHState() +{ +} + +/** + * \fn bool NoiseDHState::setParameter(Noise::Parameter id, const void *value, size_t size) + * \brief Sets a parameter on the DH object. + * + * \param id Identifies the parameter. + * \param value Points to the value to set for the parameter. + * \param size Size of the parameter value in bytes. + * + * \return Returns true if the parameter is set; false if the parameter + * \a id is not supported by the DH object; or false if the \a size is + * not valid for the parameter. + * + * If the \a id is for the private key component of a key pair, then the + * public key component will be generated from \a value. Returns false if + * it is not possible to generate the public key component from the + * private key component. + * + * \sa getParameter(), getParameterSize() + */ + +/** + * \fn size_t NoiseDHState::getParameter(Noise::Parameter id, void *value, size_t maxSize) const + * \brief Gets the value associated with a parameter on the DH object. + * + * \param id Identifies the parameter. + * \param value Points to the buffer to write the parameter value to. + * \param maxSize Maximum size of the \a value buffer in bytes. + * + * \return The number of bytes that were written to \a value. + * \return 0 if \a id is not supported by the DH object. + * \return 0 if \a maxSize is not large enough to hold the parameter value. + * \return 0 if the parameter \a id has not been set yet. + * + * The getParameterSize() function can be used to determine the actual + * size of the parameter so that the caller can allocate a buffer large + * enough to contain it ahead of time. + * + * \sa setParameter(), getParameterSize() + */ + +/** + * \fn size_t NoiseDHState::getParameterSize(Noise::Parameter id) const + * \brief Gets the size of a parameter on the DH object. + * + * \param id Identifies the parameter. + * + * \return The parameter's size, or zero if \a id is not valid for + * the DH object. + * + * If the parameter is variable-length, then this function will return + * the actual length of the value, which may be zero if the value has + * not been set yet. + * + * \sa getParameter(), setParameter(), hasParameter() + */ + +/** + * \fn bool NoiseDHState::hasParameter(Noise::Parameter id) const + * \brief Determine if a parameter on this DH object has a value set. + * + * \param id Identifies the parameter. + * + * \return Returns true if \a id has a value; false if \a id does not + * have a value; false if \a id is not valid for the DH object. + * + * \sa getParameterSize(), getParameter(), removeParameter() + */ + +/** + * \fn void NoiseDHState::removeParameter(Noise::Parameter id) + * \brief Removes a parameter from this DH object. + * + * \param id Identifies the parameter. If the parameter is unknown + * to the DH object, the request will be ignored. + * + * \sa hasParameter() + */ + +/** + * \fn bool NoiseDHState::hashPublicKey(NoiseSymmetricState *sym, Noise::Parameter id) + * \brief Hashes a public key into the symmetric state. + * + * \param sym Symmetric state to hash the public key into. + * \param id Identifies the public key to hash. + * + * \return Returns true if the key was hashed; false if \a id is not supported + * by the DH object the \a id does not have a value at present. + */ + +/** + * \fn size_t NoiseDHState::sharedKeySize() const + * \brief Gets the size of the shared keys that will be generated by + * ee(), es(), se(), and ss(). + * + * \return The size of the shared keys in bytes. + * + * \sa ee(), es(), se(), ss() + */ + +/** + * \fn void NoiseDHState::generateLocalEphemeralKeyPair() + * \brief Generates the local ephemeral key pair during a handshake. + * + * For testing purposes, the application can use setParameterKeyPair() + * to specify an ephemeral key after NoiseHandshakeState::start() and + * before this function is called. This permits testing with fixed + * key values. This functionality should not be used in real applications. + */ + +/** + * \fn void NoiseDHState::ee(uint8_t *sharedKey) + * \brief Performs a DH operation using the local and remote ephemeral keys. + * + * \param sharedKey Returns the shared key. The buffer must be at least + * sharedKeySize() bytes in size. + * + * It is assumed that the caller has already verified that the DH object + * has all of the required keys before invoking this function. + * + * \sa es(), se(), ss() + */ + +/** + * \fn void NoiseDHState::es(uint8_t *sharedKey) + * \brief Performs a DH operation using the local ephemeral key and the + * remote static key. + * + * \param sharedKey Returns the shared key. The buffer must be at least + * sharedKeySize() bytes in size. + * + * It is assumed that the caller has already verified that the DH object + * has all of the required keys before invoking this function. + * + * \sa ee(), se(), ss() + */ + +/** + * \fn void NoiseDHState::se(uint8_t *sharedKey) + * \brief Performs a DH operation using the local static key and the + * remote ephemeral key. + * + * \param sharedKey Returns the shared key. The buffer must be at least + * sharedKeySize() bytes in size. + * + * It is assumed that the caller has already verified that the DH object + * has all of the required keys before invoking this function. + * + * \sa ee(), es(), ss() + */ + +/** + * \fn void NoiseDHState::ss(uint8_t *sharedKey) + * \brief Performs a DH operation using the local and remote static keys. + * + * \param sharedKey Returns the shared key. The buffer must be at least + * sharedKeySize() bytes in size. + * + * It is assumed that the caller has already verified that the DH object + * has all of the required keys before invoking this function. + * + * \sa es(), se(), ss() + */ + +/** + * \fn bool NoiseDHState::fallback(Noise::Party, const NoiseDHState *from) + * \brief Copies parameters from another DH object to perform a fallback. + * + * \param party The party to the new fallback handshake, Noise::Initiator + * or Noise::Responder. + * \param from DH object for the previous failed handshake. + * + * \return Returns false if there are insufficient parameters in \a from + * to perform a fallback or the DH algorithms do not match. Returns true + * if fallback is possible. + * + * This function copies the initiator's ephemeral keys and the local + * static key pair from a failed handshake into this DH object to + * initialize the new handshake. + */ + +/** + * \fn void NoiseDHState::clear() + * \brief Clears all sensitive data from this object. + */ + +/** + * \brief Helper function for copying a key value into the DH object. + * + * \param output Output buffer to copy the key into. + * \param expectedSize Expected size of the key value in bytes. + * \param value Points to the input value to be stored. + * \param size Size of the input value in bytes. + * + * \return Returns true if the value is stored, or false if \a size is + * not the same as \a expectedSize or \a value is NULL. + * + * \sa copyParameterOut() + */ +bool NoiseDHState::copyParameterIn + (void *output, size_t expectedSize, const void *value, size_t size) +{ + if (size != expectedSize || !value) + return false; + memcpy(output, value, size); + return true; +} + +/** + * \brief Helper function for copying a key value out of the DH object. + * + * \param output Output buffer to copy the key into. + * \param maxOutput Maximum size of the output buffer in bytes. + * \param value Points to input key value to be copied. + * \param size Size of the input key value. + * + * \return The actual size of the copied key value if it fits within + * \a maxOutputBytes. Returns zero if \a size is greater than \a maxOutput + * or \a output is NULL. + * + * \sa copyParameterIn() + */ +size_t NoiseDHState::copyParameterOut + (void *output, size_t maxOutput, const void *value, size_t size) +{ + if (size > maxOutput || !output) + return 0; + memcpy(output, value, size); + return size; +} diff --git a/libraries/NoiseProtocol/src/NoiseDHState.h b/libraries/NoiseProtocol/src/NoiseDHState.h new file mode 100644 index 00000000..f139b4a5 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseDHState.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_DH_STATE_h +#define NOISE_DH_STATE_h + +#include "NoiseNamespace.h" +#include +#include + +class NoiseSymmetricState; + +class NoiseDHState +{ +public: + NoiseDHState() {} + virtual ~NoiseDHState(); + + virtual bool setParameter + (Noise::Parameter id, const void *value, size_t size) = 0; + virtual size_t getParameter + (Noise::Parameter id, void *value, size_t maxSize) const = 0; + virtual size_t getParameterSize(Noise::Parameter id) const = 0; + virtual bool hasParameter(Noise::Parameter id) const = 0; + virtual void removeParameter(Noise::Parameter id) = 0; + + virtual bool hashPublicKey + (NoiseSymmetricState *sym, Noise::Parameter id) = 0; + + virtual size_t sharedKeySize() const = 0; + + virtual void generateLocalEphemeralKeyPair() = 0; + + virtual void ee(uint8_t *sharedKey) = 0; + virtual void es(uint8_t *sharedKey) = 0; + virtual void se(uint8_t *sharedKey) = 0; + virtual void ss(uint8_t *sharedKey) = 0; + + virtual bool fallback(Noise::Party party, const NoiseDHState *from) = 0; + + virtual void clear() = 0; + +protected: + static bool copyParameterIn + (void *output, size_t expectedSize, const void *value, size_t size); + static size_t copyParameterOut + (void *output, size_t maxOutput, const void *value, size_t size); +}; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseDHState_Curve25519.cpp b/libraries/NoiseProtocol/src/NoiseDHState_Curve25519.cpp new file mode 100644 index 00000000..360f1485 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseDHState_Curve25519.cpp @@ -0,0 +1,509 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseDHState_Curve25519.h" +#include "NoiseSymmetricState.h" +#include "Curve25519.h" +#include "Crypto.h" +#include "RNG.h" +#include + +/** + * \class NoiseDHState_Curve25519 NoiseDHState_Curve25519.h + * \brief Noise protocol interface to the Curve25519 algorithm. + */ + +/** + * \class NoiseDHState_Curve25519_EphemOnly NoiseDHState_Curve25519.h + * \brief Noise protocol interface to the ephemeral-only Curve25519 algorithm. + * + * This class is intended for use with the "NN" pattern which does not + * require static keys. It saves 96 bytes of memory compared with + * NoiseDHState_Curve25519. + */ + +#define HAVE_25519_LOCAL_EPHEM_PUBLIC 0x01 +#define HAVE_25519_LOCAL_EPHEM_PRIVATE 0x02 +#define HAVE_25519_LOCAL_STATIC_PUBLIC 0x04 +#define HAVE_25519_LOCAL_STATIC_PRIVATE 0x08 +#define HAVE_25519_REMOTE_EPHEM_PUBLIC 0x10 +#define HAVE_25519_REMOTE_STATIC_PUBLIC 0x20 + +/** + * \brief Constructs a new ephemeral-only Curve25519 DH object. + */ +NoiseDHState_Curve25519_EphemOnly::NoiseDHState_Curve25519_EphemOnly() +{ + memset(&st, 0, sizeof(st)); +} + +/** + * \brief Destroys this ephemeral-only Curve25519 DH object. + */ +NoiseDHState_Curve25519_EphemOnly::~NoiseDHState_Curve25519_EphemOnly() +{ + clean(st); +} + +bool NoiseDHState_Curve25519_EphemOnly::setParameter + (Noise::Parameter id, const void *value, size_t size) +{ + switch (id) { + case Noise::LocalEphemPrivateKey: + case Noise::LocalEphem25519PrivateKey: + if (!copyParameterIn(st.le, sizeof(st.le), value, size)) + break; + st.le[0] &= 0xF8; + st.le[31] = (st.le[31] & 0x7F) | 0x40; + Curve25519::eval(st.lf, st.le, 0); + st.flags |= HAVE_25519_LOCAL_EPHEM_PRIVATE | + HAVE_25519_LOCAL_EPHEM_PUBLIC; + return true; + case Noise::LocalEphemKeyPair: + case Noise::LocalEphem25519KeyPair: + if (size != 64) + break; + if (!copyParameterIn(st.le, sizeof(st.le), value, 32)) + break; + if (!copyParameterIn + (st.lf, sizeof(st.lf), ((const uint8_t *)value) + 32, 32)) + break; + st.flags |= HAVE_25519_LOCAL_EPHEM_PRIVATE | + HAVE_25519_LOCAL_EPHEM_PUBLIC; + return true; + case Noise::RemoteEphemPublicKey: + case Noise::RemoteEphem25519PublicKey: + if (!copyParameterIn(st.re, sizeof(st.re), value, size)) + break; + st.flags |= HAVE_25519_REMOTE_EPHEM_PUBLIC; + return true; + default: break; + } + return false; +} + +size_t NoiseDHState_Curve25519_EphemOnly::getParameter + (Noise::Parameter id, void *value, size_t maxSize) const +{ + switch (id) { + case Noise::LocalEphemPrivateKey: + case Noise::LocalEphem25519PrivateKey: + if (!(st.flags & HAVE_25519_LOCAL_EPHEM_PRIVATE)) + break; + return copyParameterOut(value, maxSize, st.le, sizeof(st.le)); + case Noise::LocalEphemPublicKey: + case Noise::LocalEphem25519PublicKey: + if (!(st.flags & HAVE_25519_LOCAL_EPHEM_PUBLIC)) + break; + return copyParameterOut(value, maxSize, st.lf, sizeof(st.lf)); + case Noise::LocalEphemKeyPair: + case Noise::LocalEphem25519KeyPair: + if (!(st.flags & HAVE_25519_LOCAL_EPHEM_PRIVATE)) + break; + if (maxSize < 64) + break; + if (copyParameterOut(value, 32, st.le, sizeof(st.le)) != 32) + break; + if (copyParameterOut + (((uint8_t *)value) + 32, 32, st.lf, sizeof(st.lf)) != 32) + break; + return 64; + case Noise::RemoteEphemPublicKey: + case Noise::RemoteEphem25519PublicKey: + if (!(st.flags & HAVE_25519_REMOTE_EPHEM_PUBLIC)) + break; + return copyParameterOut(value, maxSize, st.re, sizeof(st.re)); + default: break; + } + return 0; +} + +size_t NoiseDHState_Curve25519_EphemOnly::getParameterSize(Noise::Parameter id) const +{ + switch (id) { + case Noise::LocalEphemKeyPair: + case Noise::LocalEphem25519KeyPair: + return 64; + + case Noise::LocalEphemPrivateKey: + case Noise::LocalEphem25519PrivateKey: + case Noise::LocalEphemPublicKey: + case Noise::LocalEphem25519PublicKey: + case Noise::RemoteEphemPublicKey: + case Noise::RemoteEphem25519PublicKey: + return 32; + + default: + return 0; + } +} + +bool NoiseDHState_Curve25519_EphemOnly::hasParameter(Noise::Parameter id) const +{ + switch (id) { + case Noise::LocalEphemKeyPair: + case Noise::LocalEphemPrivateKey: + case Noise::LocalEphem25519KeyPair: + case Noise::LocalEphem25519PrivateKey: + return (st.flags & HAVE_25519_LOCAL_EPHEM_PRIVATE) != 0; + case Noise::LocalEphemPublicKey: + case Noise::LocalEphem25519PublicKey: + return (st.flags & HAVE_25519_LOCAL_EPHEM_PUBLIC) != 0; + case Noise::RemoteEphemPublicKey: + case Noise::RemoteEphem25519PublicKey: + return (st.flags & HAVE_25519_REMOTE_EPHEM_PUBLIC) != 0; + default: break; + } + return false; +} + +void NoiseDHState_Curve25519_EphemOnly::removeParameter(Noise::Parameter id) +{ + switch (id) { + case Noise::LocalEphemKeyPair: + case Noise::LocalEphemPrivateKey: + case Noise::LocalEphemPublicKey: + case Noise::LocalEphem25519KeyPair: + case Noise::LocalEphem25519PrivateKey: + case Noise::LocalEphem25519PublicKey: + st.flags &= ~(HAVE_25519_LOCAL_EPHEM_PRIVATE | + HAVE_25519_LOCAL_EPHEM_PUBLIC); + break; + + case Noise::RemoteEphemPublicKey: + case Noise::RemoteEphem25519PublicKey: + st.flags &= ~HAVE_25519_REMOTE_EPHEM_PUBLIC; + break; + + default: break; + } +} + +bool NoiseDHState_Curve25519_EphemOnly::hashPublicKey + (NoiseSymmetricState *sym, Noise::Parameter id) +{ + switch (id) { + case Noise::LocalEphemPublicKey: + case Noise::LocalEphem25519PublicKey: + if (!(st.flags & HAVE_25519_LOCAL_EPHEM_PUBLIC)) + break; + sym->mixHash(st.lf, sizeof(st.lf)); + return true; + case Noise::RemoteEphemPublicKey: + case Noise::RemoteEphem25519PublicKey: + if (!(st.flags & HAVE_25519_REMOTE_EPHEM_PUBLIC)) + break; + sym->mixHash(st.re, sizeof(st.re)); + return true; + default: break; + } + return false; +} + +size_t NoiseDHState_Curve25519_EphemOnly::sharedKeySize() const +{ + return 32; +} + +void NoiseDHState_Curve25519_EphemOnly::generateLocalEphemeralKeyPair() +{ + // For testing, the ephemeral key pair can be provided ahead of + // time by the test harness. Only create a new pair if we need it. + if (!(st.flags & HAVE_25519_LOCAL_EPHEM_PRIVATE)) { + RNG.rand(st.le, 32); + st.le[0] &= 0xF8; + st.le[31] = (st.le[31] & 0x7F) | 0x40; + Curve25519::eval(st.lf, st.le, 0); + } +} + +void NoiseDHState_Curve25519_EphemOnly::ee(uint8_t *sharedKey) +{ + Curve25519::eval(sharedKey, st.le, st.re); +} + +// es(), se(), and ss() shouldn't be called for ephemeral-only +// handshakes so we simply stub them out. If they are called +// by accident then zeroing the sharedKey ensures that we don't +// accidentally leak information about previous memory contents. + +void NoiseDHState_Curve25519_EphemOnly::es(uint8_t *sharedKey) +{ + memset(sharedKey, 0, 32); +} + +void NoiseDHState_Curve25519_EphemOnly::se(uint8_t *sharedKey) +{ + memset(sharedKey, 0, 32); +} + +void NoiseDHState_Curve25519_EphemOnly::ss(uint8_t *sharedKey) +{ + memset(sharedKey, 0, 32); +} + +bool NoiseDHState_Curve25519_EphemOnly::fallback + (Noise::Party party, const NoiseDHState *from) +{ + // Copy the initiator's ephemeral key into this object. + st.flags &= ~(HAVE_25519_LOCAL_EPHEM_PUBLIC | + HAVE_25519_LOCAL_EPHEM_PRIVATE | + HAVE_25519_REMOTE_EPHEM_PUBLIC); + if (party == Noise::Initiator) { + if (from->getParameter(Noise::LocalEphem25519PrivateKey, st.le, 32) != 32) + return false; + if (from->getParameter(Noise::LocalEphem25519PublicKey, st.lf, 32) != 32) + return false; + st.flags |= HAVE_25519_LOCAL_EPHEM_PUBLIC | + HAVE_25519_LOCAL_EPHEM_PRIVATE; + } else { + if (from->getParameter(Noise::RemoteEphem25519PublicKey, st.re, 32) != 32) + return false; + st.flags |= HAVE_25519_REMOTE_EPHEM_PUBLIC; + } + return true; +} + +void NoiseDHState_Curve25519_EphemOnly::clear() +{ + clean(st); +} + +/** + * \brief Constructs a new Curve25519 DH object. + */ +NoiseDHState_Curve25519::NoiseDHState_Curve25519() +{ + memset(&st2, 0, sizeof(st2)); +} + +/** + * \brief Destroys this Curve25519 DH object. + */ +NoiseDHState_Curve25519::~NoiseDHState_Curve25519() +{ + clean(st2); +} + +bool NoiseDHState_Curve25519::setParameter + (Noise::Parameter id, const void *value, size_t size) +{ + switch (id) { + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + if (!copyParameterIn(st2.ls, sizeof(st2.ls), value, size)) + break; + st2.ls[0] &= 0xF8; + st2.ls[31] = (st2.ls[31] & 0x7F) | 0x40; + Curve25519::eval(st2.lp, st2.ls, 0); + st.flags |= HAVE_25519_LOCAL_STATIC_PRIVATE | + HAVE_25519_LOCAL_STATIC_PUBLIC; + return true; + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + if (size != 64) + break; + if (!copyParameterIn(st2.ls, sizeof(st2.ls), value, 32)) + break; + if (!copyParameterIn + (st2.lp, sizeof(st2.lp), ((const uint8_t *)value) + 32, 32)) + break; + st.flags |= HAVE_25519_LOCAL_STATIC_PRIVATE | + HAVE_25519_LOCAL_STATIC_PUBLIC; + return true; + case Noise::RemoteStaticPublicKey: + case Noise::RemoteStatic25519PublicKey: + if (!copyParameterIn(st2.rs, sizeof(st2.rs), value, size)) + break; + st.flags |= HAVE_25519_REMOTE_STATIC_PUBLIC; + return true; + default: + return NoiseDHState_Curve25519_EphemOnly::setParameter(id, value, size); + } + return false; +} + +size_t NoiseDHState_Curve25519::getParameter + (Noise::Parameter id, void *value, size_t maxSize) const +{ + switch (id) { + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + if (!(st.flags & HAVE_25519_LOCAL_STATIC_PRIVATE)) + break; + return copyParameterOut(value, maxSize, st2.ls, sizeof(st2.ls)); + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519PublicKey: + if (!(st.flags & HAVE_25519_LOCAL_STATIC_PUBLIC)) + break; + return copyParameterOut(value, maxSize, st2.lp, sizeof(st2.lp)); + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + if (!(st.flags & HAVE_25519_LOCAL_STATIC_PRIVATE)) + break; + if (maxSize < 64) + break; + if (copyParameterOut(value, 32, st2.ls, sizeof(st2.ls)) != 32) + break; + if (copyParameterOut + (((uint8_t *)value) + 32, 32, st2.lp, sizeof(st2.lp)) != 32) + break; + return 64; + case Noise::RemoteStaticPublicKey: + case Noise::RemoteStatic25519PublicKey: + if (!(st.flags & HAVE_25519_REMOTE_STATIC_PUBLIC)) + break; + return copyParameterOut(value, maxSize, st2.rs, sizeof(st2.rs)); + default: + return NoiseDHState_Curve25519_EphemOnly::getParameter + (id, value, maxSize); + } + return 0; +} + +size_t NoiseDHState_Curve25519::getParameterSize(Noise::Parameter id) const +{ + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStatic25519KeyPair: + return 64; + + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519PrivateKey: + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519PublicKey: + case Noise::RemoteStaticPublicKey: + case Noise::RemoteStatic25519PublicKey: + return 32; + + default: + return NoiseDHState_Curve25519_EphemOnly::getParameterSize(id); + } +} + +bool NoiseDHState_Curve25519::hasParameter(Noise::Parameter id) const +{ + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStaticPrivateKey: + case Noise::LocalStatic25519KeyPair: + case Noise::LocalStatic25519PrivateKey: + return (st.flags & HAVE_25519_LOCAL_STATIC_PRIVATE) != 0; + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519PublicKey: + return (st.flags & HAVE_25519_LOCAL_STATIC_PUBLIC) != 0; + case Noise::RemoteStaticPublicKey: + case Noise::RemoteStatic25519PublicKey: + return (st.flags & HAVE_25519_REMOTE_STATIC_PUBLIC) != 0; + default: + return NoiseDHState_Curve25519_EphemOnly::getParameterSize(id); + } + return false; +} + +void NoiseDHState_Curve25519::removeParameter(Noise::Parameter id) +{ + switch (id) { + case Noise::LocalStaticKeyPair: + case Noise::LocalStaticPrivateKey: + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519KeyPair: + case Noise::LocalStatic25519PrivateKey: + case Noise::LocalStatic25519PublicKey: + st.flags &= ~(HAVE_25519_LOCAL_STATIC_PRIVATE | + HAVE_25519_LOCAL_STATIC_PUBLIC); + break; + + case Noise::RemoteStaticPublicKey: + case Noise::RemoteStatic25519PublicKey: + st.flags &= ~HAVE_25519_REMOTE_STATIC_PUBLIC; + break; + + default: + NoiseDHState_Curve25519_EphemOnly::removeParameter(id); + break; + } +} + +bool NoiseDHState_Curve25519::hashPublicKey + (NoiseSymmetricState *sym, Noise::Parameter id) +{ + switch (id) { + case Noise::LocalStaticPublicKey: + case Noise::LocalStatic25519PublicKey: + if (!(st.flags & HAVE_25519_LOCAL_STATIC_PUBLIC)) + break; + sym->mixHash(st2.lp, sizeof(st2.lp)); + return true; + case Noise::RemoteStaticPublicKey: + case Noise::RemoteStatic25519PublicKey: + if (!(st.flags & HAVE_25519_REMOTE_STATIC_PUBLIC)) + break; + sym->mixHash(st.re, sizeof(st.re)); + return true; + default: + return NoiseDHState_Curve25519_EphemOnly::hashPublicKey(sym, id); + } + return false; +} + +void NoiseDHState_Curve25519::es(uint8_t *sharedKey) +{ + Curve25519::eval(sharedKey, st.le, st2.rs); +} + +void NoiseDHState_Curve25519::se(uint8_t *sharedKey) +{ + Curve25519::eval(sharedKey, st2.ls, st.re); +} + +void NoiseDHState_Curve25519::ss(uint8_t *sharedKey) +{ + Curve25519::eval(sharedKey, st2.ls, st2.rs); +} + +bool NoiseDHState_Curve25519::fallback + (Noise::Party party, const NoiseDHState *from) +{ + // Copy the initiator's ephemeral key into this object. + if (!NoiseDHState_Curve25519_EphemOnly::fallback(party, from)) + return false; + + // Copy the local static Curve25519 key into this object. + // Don't do this if we already have a local static key because + // we may be changing to a new key for the fallback handshake. + if (!(st.flags & HAVE_25519_LOCAL_STATIC_PRIVATE)) { + if (from->getParameter(Noise::LocalStatic25519PrivateKey, st2.ls, 32) != 32) + return false; + if (from->getParameter(Noise::LocalStatic25519PublicKey, st2.lp, 32) != 32) + return false; + st.flags |= HAVE_25519_LOCAL_STATIC_PUBLIC | + HAVE_25519_LOCAL_STATIC_PRIVATE; + } + return true; +} + +void NoiseDHState_Curve25519::clear() +{ + NoiseDHState_Curve25519_EphemOnly::clear(); + clean(st2); +} diff --git a/libraries/NoiseProtocol/src/NoiseDHState_Curve25519.h b/libraries/NoiseProtocol/src/NoiseDHState_Curve25519.h new file mode 100644 index 00000000..be0f0895 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseDHState_Curve25519.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_DH_STATE_CURVE25519_h +#define NOISE_DH_STATE_CURVE25519_h + +#include "NoiseDHState.h" + +class NoiseDHState_Curve25519; + +class NoiseDHState_Curve25519_EphemOnly : public NoiseDHState +{ +public: + NoiseDHState_Curve25519_EphemOnly(); + virtual ~NoiseDHState_Curve25519_EphemOnly(); + + bool setParameter(Noise::Parameter id, const void *value, size_t size); + size_t getParameter(Noise::Parameter id, void *value, size_t maxSize) const; + size_t getParameterSize(Noise::Parameter id) const; + bool hasParameter(Noise::Parameter id) const; + void removeParameter(Noise::Parameter id); + + bool hashPublicKey(NoiseSymmetricState *sym, Noise::Parameter id); + + size_t sharedKeySize() const; + + void generateLocalEphemeralKeyPair(); + + void ee(uint8_t *sharedKey); + void es(uint8_t *sharedKey); + void se(uint8_t *sharedKey); + void ss(uint8_t *sharedKey); + + bool fallback(Noise::Party party, const NoiseDHState *from); + + void clear(); + +private: + struct { + uint8_t le[32]; // Local ephemeral private key. + uint8_t lf[32]; // Local ephemeral public key. + uint8_t re[32]; // Remote ephemeral public key. + uint8_t flags; // Indicates which keys are present. + } st; + + friend class NoiseDHState_Curve25519; +}; + +class NoiseDHState_Curve25519 : public NoiseDHState_Curve25519_EphemOnly +{ +public: + NoiseDHState_Curve25519(); + virtual ~NoiseDHState_Curve25519(); + + bool setParameter(Noise::Parameter id, const void *value, size_t size); + size_t getParameter(Noise::Parameter id, void *value, size_t maxSize) const; + size_t getParameterSize(Noise::Parameter id) const; + bool hasParameter(Noise::Parameter id) const; + void removeParameter(Noise::Parameter id); + + bool hashPublicKey(NoiseSymmetricState *sym, Noise::Parameter id); + + void es(uint8_t *sharedKey); + void se(uint8_t *sharedKey); + void ss(uint8_t *sharedKey); + + bool fallback(Noise::Party party, const NoiseDHState *from); + + void clear(); + +private: + struct { + uint8_t ls[32]; // Local static private key. + uint8_t lp[32]; // Local static public key. + uint8_t rs[32]; // Remote static public key. + } st2; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseHandshakeState.cpp b/libraries/NoiseProtocol/src/NoiseHandshakeState.cpp new file mode 100644 index 00000000..7901fb7a --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseHandshakeState.cpp @@ -0,0 +1,1003 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseHandshakeState.h" +#include "Crypto.h" +#include + +/** + * \class NoiseHandshakeState NoiseHandshakeState.h + * \brief Abstract base class for the handshake phase of Noise protocols. + * + * This class is abstract. Subclasses provide implementations of specific + * Noise patterns like "XX". + */ + +/** + * \class NoiseHandshakeStatePSK NoiseHandshakeState.h + * \brief Abstract base class for the handshake phase of Noise protocols, + * when that handshake involves a pre-shared key. + * + * This class is abstract. Subclasses provide implementations of specific + * Noise patterns like "NNpsk0". + * + * When a PSK-using handshake is initialized, the Noise::PreSharedKey + * parameter must be set on the handshake using setParameter(). Otherwise + * the handshake will fail when the PSK is needed later. For example: + * + * \code + * uint8_t psk[32] = {...}; + * Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s handshake; + * handshake.setParameter(Noise::PreSharedKey, psk, sizeof(psk)); + * handshake.start(Noise::Initiator); + * \endcode + */ + +/** + * \brief Constructs a new Noise handshake. + */ +NoiseHandshakeState::NoiseHandshakeState() + : sym(0) + , dh(0) + , protoName(0) + , pty(Noise::Initiator) + , st(Noise::Failed) + , msgnum(0) +{ +} + +/** + * \brief Destroys this Noise handshake. + */ +NoiseHandshakeState::~NoiseHandshakeState() +{ +} + +/** + * \brief Starts the handshake for the local party. + * + * \param party Noise::Initiator or Noise::Responder. + * to identity the local party. + * \param prologue Points to the prologue string, or NULL if no prologue. + * \param prologueLen Length of the prologue string, or 0 if no prologue. + * + * This function should be followed by calls to write() and read() to + * process the packets in the handshake. Once the handshake has completed, + * the application should call split() to obtain the cipher objects to use + * to encrypt and decrypt transport messages. + * + * \sa state(), write(), read(), split() + */ +void NoiseHandshakeState::start + (Noise::Party party, const void *prologue, size_t prologueLen) +{ + pty = party; + st = (party == Noise::Initiator) ? Noise::Write : Noise::Read; + msgnum = 0; + removeKeys(); + symmetricState()->initialize(protoName); + symmetricState()->mixHash(prologue, prologueLen); +} + +/** + * \brief Starts a fallback handshake for the local party. + * + * \param fallbackFrom The previous failed handshake from which certain + * parameters are copied to start the new handshake. + * \param party Noise::Initiator or Noise::Responder. + * to identity the local party. + * \param prologue Points to the prologue string, or NULL if no prologue. + * \param prologueLen Length of the prologue string, or 0 if no prologue. + * + * \return Returns true if the handshake started, false if there are + * insufficient parameters in \a fallbackFrom to start the new handshake, + * or false if the handshake coes not implement a fallback protocol. + * + * This function should be followed by calls to write() and read() to + * process the packets in the handshake. Once the handshake has completed, + * the application should call split() to obtain the cipher objects to use + * to encrypt and decrypt transport messages. + * + * \note The application must call this function instead of start() for + * fallback handshakes. Calling start() directly from the application + * will not start the handshake correctly. + */ +bool NoiseHandshakeState::startFallback + (const NoiseHandshakeState *fallbackFrom, Noise::Party party, + const void *prologue, size_t prologueLen) +{ + // Default implementation does not support fallback. + return false; +} + +/** + * \fn Noise::Party NoiseHandshakeState::party() const + * \brief Gets the identity of this party to the handshake. + * + * \return Noise::Initiator or Noise::Responder. + */ + +/** + * \fn Noise::HandshakeState NoiseHandshakeState::state() const + * \brief Gets the state of the handshake. + * + * \return Noise::Write if the handshake is still in progress and the next + * operation is write(). + * \return Noise::Read if the handshake is still in progress and the next + * operation is read(). + * \return Noise::Split if the handshake has completed and the next operation + * is split(). + * \return Noise::Finished if the handshake has completed and split() has + * already been called. + * \return Noise::Failed if the handshake has failed or it was never started. + * + * \sa write(), read() + */ + +/** + * \fn const char *NoiseHandshakeState::protocolName() const + * \brief Gets the full name of the Noise protocol that is implemented + * by this handshake object. + * + * \return The full name of the Noise protocol; for example + * "Noise_XX_25519_ChaChaPoly_BLAKE2s". + */ + +/** + * \brief Sets a parameter on the handshake. + * + * \param id Identifies the parameter. + * \param value Points to the value to set for the parameter. + * \param size Size of the parameter value in bytes. + * + * \return Returns true if the parameter is set; false if the parameter + * \a id is not supported by the handshake; or false if the \a size is + * not valid for the parameter. + * + * If the \a id is for the private key component of a key pair, then the + * public key component will be generated from \a value. Returns false if + * it is not possible to generate the public key component from the + * private key component. + * + * \sa getParameter(), getParameterSize() + */ +bool NoiseHandshakeState::setParameter + (Noise::Parameter id, const void *value, size_t size) +{ + if (dh) + return dh->setParameter(id, value, size); + return false; +} + +/** + * \brief Gets the value associated with a parameter on the handshake. + * + * \param id Identifies the parameter. + * \param value Points to the buffer to write the parameter value to. + * \param maxSize Maximum size of the \a value buffer in bytes. + * + * \return The number of bytes that were written to \a value. + * \return 0 if \a id is not supported by the handshake. + * \return 0 if \a maxSize is not large enough to hold the parameter value. + * \return 0 if the parameter \a id has not been set yet. + * + * The getParameterSize() function can be used to determine the actual + * size of the parameter so that the caller can allocate a buffer large + * enough to contain it ahead of time. + * + * \sa setParameter(), getParameterSize() + */ +size_t NoiseHandshakeState::getParameter + (Noise::Parameter id, void *value, size_t maxSize) const +{ + if (dh) + return dh->getParameter(id, value, maxSize); + return 0; +} + +/** + * \brief Gets the size of a parameter on the handshake. + * + * \param id Identifies the parameter. + * + * \return The parameter's size, or zero if \a id is not valid for + * the handshake. + * + * If the parameter is variable-length, then this function will return + * the actual length of the value, which may be zero if the value has + * not been set yet. + * + * \sa getParameter(), setParameter(), hasParameter() + */ +size_t NoiseHandshakeState::getParameterSize(Noise::Parameter id) const +{ + if (dh) + return dh->getParameterSize(id); + return 0; +} + +/** + * \brief Determine if a parameter on this handshake has a value set. + * + * \param id Identifies the parameter. + * + * \return Returns true if \a id has a value; false if \a id does not + * have a value; false if \a id is not valid for the handshake. + * + * \sa getParameterSize(), getParameter(), removeParameter() + */ +bool NoiseHandshakeState::hasParameter(Noise::Parameter id) const +{ + if (dh) + return dh->hasParameter(id); + return false; +} + +/** + * \brief Removes a parameter from this handshake. + * + * \param id Identifies the parameter. If the parameter is unknown + * to the handshake, the request will be ignored. + * + * \sa hasParameter() + */ +void NoiseHandshakeState::removeParameter(Noise::Parameter id) +{ + if (dh) + dh->removeParameter(id); +} + +/** + * \brief Formats the next handshake packet to be written to the transport. + * + * \param output Points to a buffer to receive the formatted handshake packet. + * \param maxOutputSize Maximum size of the \a output buffer in bytes. + * \param payload Points to the application-supplied payload to be encrypted + * and sent with the handshake packet. May be NULL for no payload. + * \param payloadSize Number of bytes of payload; zero if no payload. + * + * \return The number of bytes that were written to \a output if the + * return value is greater than or equal to zero. + * \return -1 if there is insufficient space in the \a output buffer for the + * full handshake packet, or the state() is not NoiseHandshakeState::Write. + * + * After this function returns successfully, the application should call + * state() to determine what operation to perform next: read() or split(). + * + * \sa read(), split(), state() + */ +int NoiseHandshakeState::write + (void *output, size_t maxOutputSize, + const void *payload, size_t payloadSize) +{ + // Cannot write if the handshake is not in the correct state. + if (st != Noise::Write) + return -1; + + // Form a packet structure for the output buffer. + Packet packet; + packet.data = (uint8_t *)output; + packet.posn = 0; + packet.size = maxOutputSize; + packet.error = false; + packet.done = false; + + // Run the tokens for the handshake pattern and format the payload. + writeTokens(packet, msgnum); + writePayload(packet, payload, payloadSize); + + // Move onto the next state. + if (packet.error) { + st = Noise::Failed; + return -1; + } else if (packet.done) { + st = Noise::Split; + return (int)packet.posn; + } else { + ++msgnum; + st = Noise::Read; + return (int)packet.posn; + } +} + +/** + * \brief Reads the contents of the next handshake packet from the transport. + * + * \param payload Points to a buffer to receive the decrypted payload data. + * \param maxPayloadSize Maximum size of the \a payload buffer in bytes. + * \param input Points to the incoming handshake packet from the transport. + * \param inputSize Number of bytes in the incoming handshake packet. + * + * \return The number of bytes that were written to \a payload if the + * return value is greater than or equal to zero. + * \return -1 if there is insufficient space in the \a payload buffer for the + * full payload, the state() is not NoiseHandshakeState::Read, or an + * error occurred while decrypting the packet. + * + * After this function returns successfully, the application should call + * state() to determine what operation to perform next: write() or split(). + * + * \sa write(), split(), state() + */ +int NoiseHandshakeState::read + (void *payload, size_t maxPayloadSize, + const void *input, size_t inputSize) +{ + // Cannot read if the handshake is not in the correct state. + if (st != Noise::Read) + return -1; + + // Form a packet structure for the input buffer. + Packet packet; + packet.data = (uint8_t *)(const_cast(input)); + packet.posn = 0; + packet.size = inputSize; + packet.error = false; + packet.done = false; + + // Run the tokens for the handshake pattern and extract the payload. + readTokens(packet, msgnum); + size_t result = readPayload(packet, payload, maxPayloadSize); + + // Move onto the next state. + if (packet.error) { + st = Noise::Failed; + return -1; + } else if (packet.done) { + st = Noise::Split; + return (int)result; + } else { + ++msgnum; + st = Noise::Write; + return (int)result; + } +} + +/** + * \brief Splits cipher objects for the transport phase of the session out + * of this handshake state once the handshake ends. + * + * \param tx Returns a pointer to the cipher object to use to encrypt messages + * for transmission to the remote party. + * \param rx Returns a pointer to the cipher object to use to decrypt messages + * that were received from the remote party. + * + * \return Returns true if the cipher objects were split out, or false if + * state() is not NoiseHandshakeState::Split. + * + * If \a tx or \a rx are NULL, the the respective cipher object will not + * be created. This is useful for one-way patterns. + * + * The application is responsible for destroying the \a tx and \a rx + * objects when it no longer requires them. + * + * \sa write(), read(), getHandshakeHash() + */ +bool NoiseHandshakeState::split + (NoiseCipherState **tx, NoiseCipherState **rx) +{ + if (tx) + *tx = 0; + if (rx) + *rx = 0; + if (st != Noise::Split) + return false; + if (pty == Noise::Initiator) + symmetricState()->split(tx, rx); + else + symmetricState()->split(rx, tx); + st = Noise::Finished; + return true; +} + +/** + * \brief Gets the handshake hash after the handshake completes. + * + * \param data Data buffer to fill with the handshake hash. + * \param size Size of the \a data buffer in bytes. + * + * \return Returns true if the handshake hash was copied to \a data, + * or false if the handshake has not completed yet. + * + * If \a size is less than the size of the symmetric state's hash, + * then the value will be truncated to the first \a size bytes. + * If \a size is greater, then the extra bytes will be filled with zeroes. + * + * This function can be called just before or after split(). If the + * handshake has not completed yet or it is has failed, then the hash + * value will be unavailable. + * + * \sa split() + */ +bool NoiseHandshakeState::getHandshakeHash(void *data, size_t size) +{ + if (st != Noise::Split && st != Noise::Finished) { + memset(data, 0, size); + return false; + } + symmetricState()->getHandshakeHash(data, size); + return true; +} + +/** + * \brief Clears all sensitive data from this handshake object. + * + * The application will need to call start() again to begin a new handshake. + */ +void NoiseHandshakeState::clear() +{ + sym->clear(); + dh->clear(); + pty = Noise::Initiator; + st = Noise::Failed; + msgnum = 0; +} + +/** + * \fn NoiseSymmetricState *NoiseHandshakeState::symmetricState() const + * \brief Gets the symmetric state associated with this handshake. + * + * \return A pointer to the symmetric state. + * + * \sa setSymmetricState() + */ + +/** + * \fn void NoiseHandshakeState::setSymmetricState(NoiseSymmetricState *symState) + * \brief Sets the symmetric state for this handshake. + * + * \param symState A pointer to the symmetric state. + * + * This function must be called from a subclass constructor to initialize + * the handshake object properly before start() is called. + * + * \sa symmetricState() + */ + +/** + * \fn NoiseDHState *NoiseHandshakeState::dhState() const + * \brief Gets the DH object for this handshake. + * + * \return A pointer to the DH object. + * + * \sa setDHState() + */ + +/** + * \fn void NoiseHandshakeState::setDHState(NoiseDHState *dhState) + * \brief Sets the DH object for this handshake. + * + * \param dhState A pointer to the DH object. + * + * This function must be called from a subclass constructor to initialize + * the handshake object properly before start() is called. + * + * \sa dhState() + */ + +/** + * \fn const NoiseDHState *NoiseHandshakeState::otherDHState(const NoiseHandshakeState *handshake) + * \brief Gets the DH object within another handshake. + * + * \param handshake The other handshake. + * + * \return A pointer to the DH object for \a handshake. + */ + +/** + * \fn void NoiseHandshakeState::setProtocolName(const char *name) + * \brief Sets the protocol name for this handshake. + * + * \param name The full Noise protocol name. + * + * This function must be called from a subclass constructor to initialize + * the handshake object properly before start() is called. + * + * \sa protocolName() + */ + +/** + * \brief Removes keys from the parameter list that need to be + * generated or discovered during the course of the handshake. + * + * The default implementation removes the local and remote ephemeral keys + * but leaves local and remote static keys alone. Subclasses may also + * remove the remote static key if it is expected to be discovered during + * the handshake. + */ +void NoiseHandshakeState::removeKeys() +{ + removeParameter(Noise::LocalEphemKeyPair); + removeParameter(Noise::RemoteEphemPublicKey); +} + +/** + * \fn void NoiseHandshakeState::writeTokens(NoiseHandshakeState::Packet &packet, uint8_t msgnum) + * \brief Runs the tokens for a handshake message in write mode. + * + * \param packet The packet to format based on the tokens. + * \param msgnum The message number within the handshake, 0 for the first + * message, 1 for the second, and so on. + */ + +/** + * \fn void NoiseHandshakeState::readTokens(NoiseHandshakeState::Packet &packet, uint8_t msgnum) + * \brief Runs the tokens for a handshake message in read mode. + * + * \param packet The packet to read based on the tokens. + * \param msgnum The message number within the handshake, 0 for the first + * message, 1 for the second, and so on. + */ + +/** + * \brief Processes an "e" token when writing a handshake packet. + * + * \param packet The handshake packet that is being written. + * + * If there is not enough room in \a packet to hold the ephemeral public key, + * then the error flag will be set in \a packet. + * + * \sa read_e() + */ +void NoiseHandshakeState::write_e(NoiseHandshakeState::Packet &packet) +{ + size_t len = dhState()->getParameterSize(Noise::LocalEphemPublicKey); + if ((packet.size - packet.posn) >= len) { + dhState()->generateLocalEphemeralKeyPair(); + dhState()->getParameter + (Noise::LocalEphemPublicKey, packet.data + packet.posn, len); + symmetricState()->mixHash(packet.data + packet.posn, len); + packet.posn += len; + } else { + packet.error = true; + } +} + +/** + * \brief Processes a "s" token when writing a handshake packet. + * + * \param packet The handshake packet that is being written. + * + * If there is not enough room in \a packet to hold the static public key, + * then the error flag will be set in \a packet. + * + * \sa read_s() + */ +void NoiseHandshakeState::write_s(NoiseHandshakeState::Packet &packet) +{ + // Check that the application has supplied us with a local static key. + if (!dhState()->hasParameter(Noise::LocalStaticPublicKey)) { + packet.error = true; + return; + } + + // Write the local static public key to the outgoing message. + size_t len = dhState()->getParameterSize(Noise::LocalStaticPublicKey); + if ((packet.size - packet.posn) >= len) { + dhState()->getParameter + (Noise::LocalStaticPublicKey, packet.data + packet.posn, len); + int size = symmetricState()->encryptAndHash + (packet.data + packet.posn, packet.size - packet.posn, + packet.data + packet.posn, len); + if (size > 0) + packet.posn += size; + else + packet.error = true; + } else { + packet.error = true; + } +} + +/** + * \brief Processes an "ee" token when writing a handshake packet. + * + * \param packet The handshake packet that is being written. + * + * \sa read_ee() + */ +void NoiseHandshakeState::write_ee(NoiseHandshakeState::Packet &packet) +{ + size_t size = dhState()->sharedKeySize(); + uint8_t shared[size]; + dhState()->ee(shared); + symmetricState()->mixKey(shared, size); + clean(shared, size); +} + +/** + * \brief Processes an "es" token when writing a handshake packet. + * + * \param packet The handshake packet that is being written. + * + * \sa read_es() + */ +void NoiseHandshakeState::write_es(NoiseHandshakeState::Packet &packet) +{ + if (!dhState()->hasParameter(Noise::RemoteStaticPublicKey)) { + // We don't have a remote static key. It probably should have + // been provided ahead of time when the handshake started. + packet.error = true; + return; + } + size_t size = dhState()->sharedKeySize(); + uint8_t shared[size]; + if (pty == Noise::Initiator) + dhState()->es(shared); + else + dhState()->se(shared); + symmetricState()->mixKey(shared, size); + clean(shared, size); +} + +/** + * \brief Processes a "se" token when writing a handshake packet. + * + * \param packet The handshake packet that is being written. + * + * \sa read_se() + */ +void NoiseHandshakeState::write_se(NoiseHandshakeState::Packet &packet) +{ + if (!dhState()->hasParameter(Noise::LocalStaticPrivateKey)) { + // We don't have a local static key. It probably should have + // been provided ahead of time when the handshake started. + packet.error = true; + return; + } + size_t size = dhState()->sharedKeySize(); + uint8_t shared[size]; + if (pty == Noise::Initiator) + dhState()->se(shared); + else + dhState()->es(shared); + symmetricState()->mixKey(shared, size); + clean(shared, size); +} + +/** + * \brief Processes a "ss" token when writing a handshake packet. + * + * \param packet The handshake packet that is being written. + * + * \sa read_ss() + */ +void NoiseHandshakeState::write_ss(NoiseHandshakeState::Packet &packet) +{ + if (!dhState()->hasParameter(Noise::LocalStaticPrivateKey) || + !dhState()->hasParameter(Noise::RemoteStaticPublicKey)) { + // We don't have all required static keys. They probably should + // have been provided ahead of time when the handshake started. + packet.error = true; + return; + } + size_t size = dhState()->sharedKeySize(); + uint8_t shared[size]; + dhState()->ss(shared); + symmetricState()->mixKey(shared, size); + clean(shared, size); +} + +/** + * \brief Processes an "e" token when reading a handshake packet. + * + * \param packet The handshake packet that is being read. + * + * If there is not enough data in \a packet to for a valid ephemeral public + * key, then the error flag will be set in \a packet. + * + * \sa write_e() + */ +void NoiseHandshakeState::read_e(NoiseHandshakeState::Packet &packet) +{ + size_t len = dhState()->getParameterSize(Noise::RemoteEphemPublicKey); + if ((packet.size - packet.posn) >= len) { + if (dhState()->setParameter + (Noise::RemoteEphemPublicKey, packet.data + packet.posn, len)) { + symmetricState()->mixHash(packet.data + packet.posn, len); + } else { + packet.error = true; + } + packet.posn += len; + } else { + packet.error = true; + } +} + +/** + * \brief Processes a "s" token when reading a handshake packet. + * + * \param packet The handshake packet that is being read. + * + * If there is not enough data in \a packet to for a valid static public + * key, or the value failed to decrypt, then the error flag will be set + * in \a packet. + * + * \sa write_s() + */ +void NoiseHandshakeState::read_s(NoiseHandshakeState::Packet &packet) +{ + size_t len = dhState()->getParameterSize(Noise::RemoteStaticPublicKey); + size_t fullLen = len; + if (symmetricState()->hasKey()) + fullLen += symmetricState()->macLen(); + if ((packet.size - packet.posn) >= fullLen) { + uint8_t s[len]; + int size = symmetricState()->decryptAndHash + (s, len, packet.data + packet.posn, fullLen); + if (size > 0) { + packet.posn += size; + if (!dhState()->setParameter(Noise::RemoteStaticPublicKey, s, len)) + packet.error = true; + } else { + packet.error = true; + } + clean(s, len); + } else { + packet.error = true; + } +} + +/** + * \fn void NoiseHandshakeState::read_ee(NoiseHandshakeState::Packet &packet) + * \brief Processes an "ee" token when reading a handshake packet. + * + * \param packet The handshake packet that is being read. + * + * This is a convenience function. The "ee" token has identical behaviour + * when both reading and writing. + * + * \sa write_ee() + */ + +/** + * \fn void NoiseHandshakeState::read_es(NoiseHandshakeState::Packet &packet) + * \brief Processes an "es" token when reading a handshake packet. + * + * \param packet The handshake packet that is being read. + * + * This is a convenience function. The "es" token has identical behaviour + * when both reading and writing. + * + * \sa write_es() + */ + +/** + * \fn void NoiseHandshakeState::read_se(NoiseHandshakeState::Packet &packet) + * \brief Processes a "se" token when reading a handshake packet. + * + * \param packet The handshake packet that is being read. + * + * This is a convenience function. The "se" token has identical behaviour + * when both reading and writing. + * + * \sa write_se() + */ + +/** + * \fn void NoiseHandshakeState::read_ss(NoiseHandshakeState::Packet &packet) + * \brief Processes a "ss" token when reading a handshake packet. + * + * \param packet The handshake packet that is being read. + * + * This is a convenience function. The "ss" token has identical behaviour + * when both reading and writing. + * + * \sa write_ss() + */ + +/** + * \fn void NoiseHandshakeState::setState(Noise::HandshakeState state) + * \brief Sets the state of this handshake. + * + * \param state The new state. + * + * This is intended for use in subclass implementations of start() when + * initializing the handshake. + * + * \sa state() + */ + +/** + * \brief Writes a payload to a handshake packet. + * + * \param packet The handshake packet that is being written. + * \param data Points to the plaintext payload data to be written. + * \param size Number of bytes of plaintext payload to write. + * + * If there is not enough room in \a packet to hold the encrypted payload, + * then the error flag will be set in \a packet. + * + * \sa readPayload() + */ +void NoiseHandshakeState::writePayload(NoiseHandshakeState::Packet &packet, + const void *data, size_t size) +{ + int result = symmetricState()->encryptAndHash + (packet.data + packet.posn, packet.size - packet.posn, + (const uint8_t *)data, size); + if (result >= 0) + packet.posn += result; + else + packet.error = true; +} + +/** + * \brief Reads a payload from a handshake packet. + * + * \param packet The handshake packet that is being read. + * \param data Points to the buffer to place the plaintext payload data into. + * \param maxSize Maximum number of bytes that can be written to \a data. + * + * \return Number of plaintext bytes that were written to the \a data buffer. + * + * If there is a problem decrypting the payload, or \a maxSize is not large + * enough, then 0 will be returned and the error flag will be set in \a packet. + * + * \sa writePayload() + */ +size_t NoiseHandshakeState::readPayload(NoiseHandshakeState::Packet &packet, + void *data, size_t maxSize) +{ + int result = symmetricState()->decryptAndHash + ((uint8_t *)data, maxSize, + packet.data + packet.posn, packet.size - packet.posn); + packet.posn = packet.size; + if (result >= 0) + return result; + packet.error = true; + return 0; +} + +/** + * \brief Constructs a new PSK-using handshake. + */ +NoiseHandshakeStatePSK::NoiseHandshakeStatePSK() + : havePSK(false) +{ +} + +/** + * \brief Destroys this PSK-using handshake. + */ +NoiseHandshakeStatePSK::~NoiseHandshakeStatePSK() +{ + clean(psk); +} + +bool NoiseHandshakeStatePSK::setParameter + (Noise::Parameter id, const void *value, size_t size) +{ + if (id == Noise::PreSharedKey) { + if (!value || size != 32) + return false; + memcpy(psk, value, size); + havePSK = true; + return true; + } else { + return NoiseHandshakeState::setParameter(id, value, size); + } +} + +size_t NoiseHandshakeStatePSK::getParameter + (Noise::Parameter id, void *value, size_t maxSize) const +{ + if (id == Noise::PreSharedKey) { + if (!havePSK || !value || maxSize < 32) + return 0; + memcpy(value, psk, 32); + return 32; + } else { + return NoiseHandshakeState::getParameter(id, value, maxSize); + } +} + +size_t NoiseHandshakeStatePSK::getParameterSize(Noise::Parameter id) const +{ + if (id == Noise::PreSharedKey) + return 32; + else + return NoiseHandshakeState::getParameterSize(id); +} + +bool NoiseHandshakeStatePSK::hasParameter(Noise::Parameter id) const +{ + if (id == Noise::PreSharedKey) + return havePSK; + else + return NoiseHandshakeState::hasParameter(id); +} + +void NoiseHandshakeStatePSK::removeParameter(Noise::Parameter id) +{ + if (id == Noise::PreSharedKey) + havePSK = false; + else + NoiseHandshakeState::removeParameter(id); +} + +void NoiseHandshakeStatePSK::clear() +{ + clean(psk); + havePSK = false; + NoiseHandshakeState::clear(); +} + +/** + * \brief Processes an "e" token when writing a handshake packet. + * + * \param packet The handshake packet that is being written. + * + * This overrides the base class implementation of write_e() to provide + * additional behaviour for handshakes that involve PSK values. + */ +void NoiseHandshakeStatePSK::write_e(NoiseHandshakeState::Packet &packet) +{ + NoiseHandshakeState::write_e(packet); + if (!packet.error) { + size_t len = dhState()->getParameterSize(Noise::LocalEphemPublicKey); + symmetricState()->mixKey(packet.data + packet.posn - len, len); + } +} + +/** + * \brief Processes an "e" token when reading a handshake packet. + * + * \param packet The handshake packet that is being read. + * + * This overrides the base class implementation of read_e() to provide + * additional behaviour for handshakes that involve PSK values. + */ +void NoiseHandshakeStatePSK::read_e(NoiseHandshakeState::Packet &packet) +{ + NoiseHandshakeState::read_e(packet); + if (!packet.error) { + size_t len = dhState()->getParameterSize(Noise::RemoteEphemPublicKey); + symmetricState()->mixKey(packet.data + packet.posn - len, len); + } +} + +/** + * \brief Processes a "psk" token when writing a handshake packet. + * + * \param packet The handshake packet that is being written. + * + * \sa read_psk() + */ +void NoiseHandshakeStatePSK::write_psk(NoiseHandshakeState::Packet &packet) +{ + if (havePSK) + symmetricState()->mixKeyAndHash(psk, 32); + else + packet.error = true; +} + +/** + * \fn void NoiseHandshakeStatePSK::read_psk(NoiseHandshakeState::Packet &packet) + * \brief Processes a "psk" token when reading a handshake packet. + * + * \param packet The handshake packet that is being read. + * + * This is a convenience function. The "psk" token has identical behaviour + * when both reading and writing. + * + * \sa write_psk() + */ diff --git a/libraries/NoiseProtocol/src/NoiseHandshakeState.h b/libraries/NoiseProtocol/src/NoiseHandshakeState.h new file mode 100644 index 00000000..0efdbaff --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseHandshakeState.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_HANDSHAKE_STATE_h +#define NOISE_HANDSHAKE_STATE_h + +#include "NoiseNamespace.h" +#include "NoiseSymmetricState.h" +#include "NoiseDHState.h" +#include "NoiseCipherState.h" + +class NoiseHandshakeState +{ +public: + virtual ~NoiseHandshakeState(); + + virtual void start + (Noise::Party party, const void *prologue = 0, size_t prologueLen = 0); + virtual bool startFallback + (const NoiseHandshakeState *fallbackFrom, Noise::Party party, + const void *prologue = 0, size_t prologueLen = 0); + + Noise::Party party() const { return pty; } + Noise::HandshakeState state() const { return st; } + const char *protocolName() const { return protoName; } + + virtual bool setParameter + (Noise::Parameter id, const void *value, size_t size); + virtual size_t getParameter + (Noise::Parameter id, void *value, size_t maxSize) const; + virtual size_t getParameterSize(Noise::Parameter id) const; + virtual bool hasParameter(Noise::Parameter id) const; + virtual void removeParameter(Noise::Parameter id); + + int write(void *output, size_t maxOutputSize, + const void *payload, size_t payloadSize); + int read(void *payload, size_t maxPayloadSize, + const void *input, size_t inputSize); + bool split(NoiseCipherState **tx, NoiseCipherState **rx); + bool getHandshakeHash(void *data, size_t size); + + virtual void clear(); + +protected: + NoiseHandshakeState(); + + NoiseSymmetricState *symmetricState() const { return sym; } + void setSymmetricState(NoiseSymmetricState *symState) { sym = symState; } + + NoiseDHState *dhState() const { return dh; } + void setDHState(NoiseDHState *dhState) { dh = dhState; } + + static const NoiseDHState *otherDHState + (const NoiseHandshakeState *handshake) { return handshake->dh; } + + void setProtocolName(const char *name) { protoName = name; } + + virtual void removeKeys(); + + /** + * \brief Information about a handshake packet that is being processed. + */ + struct Packet + { + uint8_t *data; /**< Points to the start of the packet's data */ + size_t posn; /**< Current processing position in the data array */ + size_t size; /**< Maximum amount of available packet data */ + bool error; /**< Set to true if an error has occurred */ + bool done; /**< Set to true for the last handshake message */ + }; + + virtual void writeTokens + (NoiseHandshakeState::Packet &packet, uint8_t msgnum) = 0; + virtual void readTokens + (NoiseHandshakeState::Packet &packet, uint8_t msgnum) = 0; + + virtual void write_e(NoiseHandshakeState::Packet &packet); + void write_s(NoiseHandshakeState::Packet &packet); + void write_ee(NoiseHandshakeState::Packet &packet); + void write_es(NoiseHandshakeState::Packet &packet); + void write_se(NoiseHandshakeState::Packet &packet); + void write_ss(NoiseHandshakeState::Packet &packet); + + virtual void read_e(NoiseHandshakeState::Packet &packet); + void read_s(NoiseHandshakeState::Packet &packet); + void read_ee(NoiseHandshakeState::Packet &packet) { write_ee(packet); } + void read_es(NoiseHandshakeState::Packet &packet) { write_es(packet); } + void read_se(NoiseHandshakeState::Packet &packet) { write_se(packet); } + void read_ss(NoiseHandshakeState::Packet &packet) { write_ss(packet); } + + void setState(Noise::HandshakeState state) { st = state; } + +private: + NoiseSymmetricState *sym; + NoiseDHState *dh; + const char *protoName; + Noise::Party pty; + Noise::HandshakeState st; + uint8_t msgnum; + + void writePayload(NoiseHandshakeState::Packet &packet, + const void *data, size_t size); + size_t readPayload(NoiseHandshakeState::Packet &packet, + void *data, size_t maxSize); +}; + +class NoiseHandshakeStatePSK : public NoiseHandshakeState +{ +public: + virtual ~NoiseHandshakeStatePSK(); + + bool setParameter(Noise::Parameter id, const void *value, size_t size); + size_t getParameter(Noise::Parameter id, void *value, size_t maxSize) const; + size_t getParameterSize(Noise::Parameter id) const; + bool hasParameter(Noise::Parameter id) const; + void removeParameter(Noise::Parameter id); + + void clear(); + +protected: + NoiseHandshakeStatePSK(); + + void write_e(NoiseHandshakeState::Packet &packet); + void read_e(NoiseHandshakeState::Packet &packet); + void write_psk(NoiseHandshakeState::Packet &packet); + void read_psk(NoiseHandshakeState::Packet &packet) { write_psk(packet); } + +private: + uint8_t psk[32]; + bool havePSK; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseNamespace.cpp b/libraries/NoiseProtocol/src/NoiseNamespace.cpp new file mode 100644 index 00000000..505a4474 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseNamespace.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseNamespace.h" + +/** + * \namespace Noise + * \brief Common definitions for the Noise protocol. + */ diff --git a/libraries/NoiseProtocol/src/NoiseNamespace.h b/libraries/NoiseProtocol/src/NoiseNamespace.h new file mode 100644 index 00000000..7985efe1 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseNamespace.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_NAMESPACE_h +#define NOISE_NAMESPACE_h + +#include + +namespace Noise +{ + /** + * \brief Indicates which party is engaging in a handshake. + */ + enum Party + { + Initiator, /**< Local party is the initiator of the handshake */ + Responder /**< Local party is the responder of the handshake */ + }; + + /** + * \brief Current state of a handshake. + */ + enum HandshakeState + { + Write, /**< Next operation is a handshake packet write() */ + Read, /**< Next operation is a handshake packet read() */ + Split, /**< Handshake complete, next operation is split() */ + Finished, /**< Handshake finished and split() already done */ + Failed /**< Handshake has failed or was never started */ + }; + + /** + * \brief Identifiers for handshake parameters. + */ + enum Parameter + { + // Standard handshake parameters. + LocalStaticKeyPair = 1, /**< Local DH static key pair */ + LocalStaticPrivateKey = 2, /**< Local DH static private key */ + LocalStaticPublicKey = 3, /**< Local DH static public key */ + RemoteStaticPublicKey = 4, /**< Remote DH static public key */ + PreSharedKey = 5, /**< Pre-shared symmetric key */ + + // Specific algorithm names for meta-handshakes. + LocalStatic25519KeyPair = 100, /**< Local Curve25519 key pair */ + LocalStatic25519PrivateKey = 101, /**< Local Curve25519 private key */ + LocalStatic25519PublicKey = 102, /**< Local Curve25519 public key */ + RemoteStatic25519PublicKey = 103, /**< Remote Curve25519 public key */ + + // Internal parameters (for application testing use only). + LocalEphemKeyPair = 200, /**< Local DH ephemeral key pair */ + LocalEphemPrivateKey = 201, /**< Local DH ephemeral private key */ + LocalEphemPublicKey = 202, /**< Local DH ephemeral public key */ + RemoteEphemPublicKey = 203, /**< Remote DH ephemeral public key */ + LocalEphem25519KeyPair = 204, /**< Local ephemeral Curve25519 key pair */ + LocalEphem25519PrivateKey = 205, /**< Local ephemeral Curve25519 private key */ + LocalEphem25519PublicKey = 206, /**< Local ephemeral Curve25519 public key */ + RemoteEphem25519PublicKey = 207 /**< Remote ephemeral Curve25519 public key */ + }; + +}; // namespace Noise + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseProtocol.h b/libraries/NoiseProtocol/src/NoiseProtocol.h new file mode 100644 index 00000000..7d3fd794 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseProtocol.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_PROTOCOL_h +#define NOISE_PROTOCOL_h + +#include "NoiseNamespace.h" + +#include "Noise_IK_25519_AESGCM_SHA256.h" +#include "Noise_IK_25519_ChaChaPoly_BLAKE2s.h" +#include "Noise_IK_25519_ChaChaPoly_SHA256.h" + +#include "Noise_NNpsk0_25519_AESGCM_SHA256.h" +#include "Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.h" +#include "Noise_NNpsk0_25519_ChaChaPoly_SHA256.h" + +#include "Noise_Pipes_25519_AESGCM_SHA256.h" +#include "Noise_Pipes_25519_ChaChaPoly_BLAKE2s.h" +#include "Noise_Pipes_25519_ChaChaPoly_SHA256.h" + +#include "Noise_XX_25519_AESGCM_SHA256.h" +#include "Noise_XX_25519_ChaChaPoly_BLAKE2s.h" +#include "Noise_XX_25519_ChaChaPoly_SHA256.h" + +#include "Noise_XXfallback_25519_AESGCM_SHA256.h" +#include "Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.h" +#include "Noise_XXfallback_25519_ChaChaPoly_SHA256.h" + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseProtocolDescriptor.cpp b/libraries/NoiseProtocol/src/NoiseProtocolDescriptor.cpp new file mode 100644 index 00000000..83bf5b55 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseProtocolDescriptor.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseProtocolDescriptor.h" + +/** + * \class NoiseProtocolDescriptor NoiseProtocolDescriptor.h + * \brief Description of a Noise protocol and a method to create a handshake + * object that implements the protocol. + * + * This class is abstract. The caller should instantiate a subclass like + * Noise_XX_25519_ChaChaPoly_BLAKE2s or Noise_XX_25519_AESGCM_SHA256 to + * get an actual descriptor. + */ + +/** + * \fn NoiseProtocolDescriptor::NoiseProtocolDescriptor(const char *name, const char *alias) + * \brief Creates a new Noise protocol descriptor. + * + * \param name Name of the Noise protocol, e.g. "Noise_XX_25519_AESGCM_SHA256". + * \param alias NoiseTinyLink alias for the Noise protocol; e.g. "1". Set this + * to NULL if the protocol does not have a NoiseTinyLink alias defined. + */ + +/** + * \brief Destroys this Noise protocol descriptor. + */ +NoiseProtocolDescriptor::~NoiseProtocolDescriptor() +{ +} + +/** + * \fn const char *NoiseProtocolDescriptor::protocolName() const + * \brief Gets the name of the Noise protocol represented by this descriptor. + * + * \return The name of the Noise protocol. + * + * \sa protocolAlias() + */ + +/** + * \fn const char *NoiseProtocolDescriptor::protocolAlias() const + * \brief Gets the NoiseTinyLink alias for the Noise protocol represented + * by this descriptor. + * + * \return The alias or NULL if the protocol does not have a NoiseTinyLink + * alias defined. + * + * \sa protocolName() + */ + +/** + * \fn NoiseHandshakeState *NoiseProtocolDescriptor::createHandshake() const + * \brief Creates a handshake object for the Noise protocol represented + * by this descriptor. + * + * \return A new handshake object for the protocol. + */ + +/** + * \brief Returns the descriptor for the abbreviated protocol, if any. + * + * \return Returns a pointer to the abbreviated protocol descriptor, or NULL + * if this protocol does not have an abbreviated version. + * + * This function and fallbackDescriptor() to intended to help implement + * fallback-using protocols like Noise Pipes. In the case of Noise Pipes, + * the full protocol would be XX, the abbreviated protocol would be IK, + * and the fallback protocol would XXfallback. + * + * The abbreviated protocol should be selected if a remote static public + * key is available when the handshake starts. Otherwise the full protocol + * should be used to discover the remote static public key dynamically. + * + * \sa fallbackDescriptor() + */ +const NoiseProtocolDescriptor *NoiseProtocolDescriptor::abbreviatedDescriptor() const +{ + return 0; +} + +/** + * \brief Returns the descriptor for the fallback protocol, if any. + * + * \return Returns a pointer to the fallback protocol descriptor, or NULL + * if it is not possible to fall back from the abbreviated protocol to + * another protocol. The default implementation returns NULL. + * + * \sa abbreviatedDescriptor() + */ +const NoiseProtocolDescriptor *NoiseProtocolDescriptor::fallbackDescriptor() const +{ + return 0; +} diff --git a/libraries/NoiseProtocol/src/NoiseProtocolDescriptor.h b/libraries/NoiseProtocol/src/NoiseProtocolDescriptor.h new file mode 100644 index 00000000..32788fb7 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseProtocolDescriptor.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_PROTOCOL_DESCRIPTOR_h +#define NOISE_PROTOCOL_DESCRIPTOR_h + +class NoiseHandshakeState; + +class NoiseProtocolDescriptor +{ +public: + virtual ~NoiseProtocolDescriptor(); + + const char *protocolName() const { return protoName; } + const char *protocolAlias() const { return protoAlias; } + + virtual NoiseHandshakeState *createHandshake() const = 0; + + virtual const NoiseProtocolDescriptor *abbreviatedDescriptor() const; + virtual const NoiseProtocolDescriptor *fallbackDescriptor() const; + +protected: + explicit NoiseProtocolDescriptor(const char *name, const char *alias = 0) + : protoName(name), protoAlias(alias) {} + +private: + const char *protoName; + const char *protoAlias; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseSymmetricState.cpp b/libraries/NoiseProtocol/src/NoiseSymmetricState.cpp new file mode 100644 index 00000000..18a02771 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseSymmetricState.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseSymmetricState.h" + +/** + * \class NoiseSymmetricState NoiseSymmetricState.h + * \brief Abstract base class for the Noise protocol's symmetric state. + * + * This class is abstract. The caller should instantiate a subclass like + * NoiseSymmetricState_ChaChaPoly_BLAKE2s or NoiseSymmetricState_AESGCM_SHA256 + * to choose the specific algorithms to use in the symmetric state. + */ + +/** + * \fn NoiseSymmetricState::NoiseSymmetricState() + * \brief Constructs a new symmetric state object. + */ + +/** + * \brief Destroys this symmetric state object. + */ +NoiseSymmetricState::~NoiseSymmetricState() +{ +} + +/** + * \fn void NoiseSymmetricState::initialize(const char *protocolName) + * \brief Initializes a Noise protocol using this symmetric state. + * + * \param protocolName The full name of the Noise protocol. + */ + +/** + * \fn bool NoiseSymmetricState::hasKey() const + * \brief Determine if this symmetric state has an encryption key set. + * + * \return Returns true if an encryption key has been set, false if not. + */ + +/** + * \brief Returns the length of MAC values for this symmetric state. + * + * \return The base class returns 16 which is the recommended size for + * MAC values in all Noise protocols. + * + * In theory, subclasses could return a smaller value than 16 if MAC values + * were being truncated to save packet space. The Noise specification + * recommends against MAC truncation as it reduces security. + */ +size_t NoiseSymmetricState::macLen() const +{ + return 16; +} + +/** + * \fn void NoiseSymmetricState::mixKey(const void *data, size_t size) + * \brief Mixes input data into the chaining key. + * + * \param data Points to the data to be mixed in. + * \param size Number of bytes to mix in. + * + * \sa mixHash(), mixKeyAndHash() + */ + +/** + * \fn void NoiseSymmetricState::mixHash(const void *data, size_t size) + * \brief Mixes input data into the handshake hash. + * + * \param data Points to the data to be mixed in. + * \param size Number of bytes to mix in. + * + * \sa mixKey(), mixKeyAndHash() + */ + +/** + * \fn void NoiseSymmetricState::mixKeyAndHash(const void *data, size_t size) + * \brief Mixes input data into the chaining key and handshake hash. + * + * \param data Points to the data to be mixed in. + * \param size Number of bytes to mix in. + * + * \sa mixKey(), mixHash() + */ + +/** + * \fn void NoiseSymmetricState::getHandshakeHash(void *data, size_t size) + * \brief Gets the handshake hash from the symmetric state. + * + * \param data Data buffer to fill with the handshake hash. + * \param size Size of the \a data buffer in bytes. + * + * If \a size is less than the size of the symmetric state's hash, + * then the value will be truncated to the first \a size bytes. + * If \a size is greater, then the extra bytes will be filled with zeroes. + */ + +/** + * \fn int NoiseSymmetricState::encryptAndHash(uint8_t *output, size_t outputSize, const uint8_t *input, size_t inputSize) + * \brief Encrypts data and hashes it into the handshake hash. + * + * \param output Output buffer to write the ciphertext and MAC to. + * \param outputSize Available space in the \a output buffer. + * \param input Input buffer containing the plaintext to be encrypted. + * \param inputSize Number of bytes of plaintext. + * + * \return The number of bytes that were written to \a output. + * \return -1 if \a outputSize is not large enough to contain the + * ciphertext and MAC. + * + * The plaintext will be copied directly to the output buffer without a MAC + * if mixKey() has not been called yet. + * + * \sa decryptAndHash() + */ + +/** + * \fn int NoiseSymmetricState::decryptAndHash(uint8_t *output, size_t outputSize, const uint8_t *input, size_t inputSize) + * \brief Decrypts data and hashes it into the handshake hash. + * + * \param output Output buffer to write the plaintext to. + * \param outputSize Available space in the \a output buffer. + * \param input Input buffer containing the ciphertext and MAC. + * \param inputSize Number of bytes of ciphertext plus the MAC. + * + * \return The number of bytes that were written to \a output. + * \return -1 if \a outputSize is not large enough to contain the plaintext. + * \return -1 if the MAC check failed; the plaintext output will be invalid. + * + * The ciphertext will be copied directly to the output buffer without + * removing a MAC if mixKey() has not been called yet. + * + * \sa encryptAndHash() + */ + +/** + * \fn void NoiseSymmetricState::split(NoiseCipherState **c1, NoiseCipherState **c2) + * \brief Splits the symmetric state into two cipher objects for the + * transport phase of the Noise session. + * + * \param c1 Returns a new cipher object for encrypting traffic from the + * initiator to the responder. May be NULL if the object is not required. + * \param c2 Returns a new cipher object for encrypting traffic from the + * responder to the initiator. May be NULL if the object is not required. + */ + +/** + * \fn void NoiseSymmetricState::clear() + * \brief Clears all sensitive data from this symmetric state object. + */ diff --git a/libraries/NoiseProtocol/src/NoiseSymmetricState.h b/libraries/NoiseProtocol/src/NoiseSymmetricState.h new file mode 100644 index 00000000..a1e72d3e --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseSymmetricState.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_SYMMETRIC_STATE_h +#define NOISE_SYMMETRIC_STATE_h + +#include +#include + +class NoiseCipherState; + +class NoiseSymmetricState +{ +public: + NoiseSymmetricState() {} + virtual ~NoiseSymmetricState(); + + virtual void initialize(const char *protocolName) = 0; + + virtual bool hasKey() const = 0; + virtual size_t macLen() const; + + virtual void mixKey(const void *data, size_t size) = 0; + virtual void mixHash(const void *data, size_t size) = 0; + virtual void mixKeyAndHash(const void *data, size_t size) = 0; + + virtual void getHandshakeHash(void *data, size_t size) = 0; + + virtual int encryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize) = 0; + virtual int decryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize) = 0; + + virtual void split(NoiseCipherState **c1, NoiseCipherState **c2) = 0; + + virtual void clear() = 0; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseSymmetricState_AESGCM_SHA256.cpp b/libraries/NoiseProtocol/src/NoiseSymmetricState_AESGCM_SHA256.cpp new file mode 100644 index 00000000..9774b07d --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseSymmetricState_AESGCM_SHA256.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseSymmetricState_AESGCM_SHA256.h" +#include "NoiseCipherState_AESGCM.h" +#include "SHA256.h" +#include "Crypto.h" +#include + +/** + * \class NoiseSymmetricState_AESGCM_SHA256 NoiseSymmetricState_AESGCM_SHA256.h + * \brief Noise symmetric state implementation using AES256, GCM, and SHA256. + */ + +/** + * \brief Constructs a new symmetric state using AES256, GCM, and SHA256. + */ +NoiseSymmetricState_AESGCM_SHA256::NoiseSymmetricState_AESGCM_SHA256() +{ + st.n = 0; + st.hasKey = false; +} + +/** + * \brief Destroys this symmetric state object. + */ +NoiseSymmetricState_AESGCM_SHA256::~NoiseSymmetricState_AESGCM_SHA256() +{ + clean(st); +} + +void NoiseSymmetricState_AESGCM_SHA256::initialize + (const char *protocolName) +{ + size_t len = strlen(protocolName); + if (len <= 32) { + memcpy(st.h, protocolName, len); + memset(st.h + len, 0, 32 - len); + } else { + SHA256 hash; + hash.update(protocolName, len); + hash.finalize(st.h, 32); + } + memcpy(st.ck, st.h, 32); + st.hasKey = false; +} + +bool NoiseSymmetricState_AESGCM_SHA256::hasKey() const +{ + return st.hasKey; +} + +void NoiseSymmetricState_AESGCM_SHA256::mixKey + (const void *data, size_t size) +{ + uint8_t key[32]; + hmac(key, st.ck, data, size, 0); + hmac(st.ck, key, 0, 0, 1); + hmac(key, key, st.ck, 32, 2); + st.hasKey = true; + st.n = 0; + cipher.setKey(key, sizeof(key)); + clean(key); +} + +void NoiseSymmetricState_AESGCM_SHA256::mixHash + (const void *data, size_t size) +{ + SHA256 hash; + hash.update(st.h, sizeof(st.h)); + hash.update(data, size); + hash.finalize(st.h, sizeof(st.h)); +} + +void NoiseSymmetricState_AESGCM_SHA256::mixKeyAndHash + (const void *data, size_t size) +{ + uint8_t key[32]; + uint8_t temph[32]; + hmac(key, st.ck, data, size, 0); + hmac(st.ck, key, 0, 0, 1); + hmac(temph, key, st.ck, 32, 2); + hmac(key, key, temph, 32, 3); + st.hasKey = true; + st.n = 0; + cipher.setKey(key, sizeof(key)); + mixHash(temph, sizeof(temph)); + clean(key); + clean(temph); +} + +void NoiseSymmetricState_AESGCM_SHA256::getHandshakeHash + (void *data, size_t size) +{ + if (size <= 32) { + memcpy(data, st.h, size); + } else { + memcpy(data, st.h, 32); + memset(((uint8_t *)data) + 32, 0, size - 32); + } +} + +/** + * \brief Formats the 12-byte IV for use with AESGCM according + * to the requirements of the Noise specification. + * + * \param iv Returns the formatted IV. + * \param n 64-bit nonce value for the packet. + */ +void noiseAESGCMFormatIV(uint8_t iv[12], uint64_t n) +{ + iv[0] = 0; + iv[1] = 0; + iv[2] = 0; + iv[3] = 0; + iv[4] = (uint8_t)(n >> 56); + iv[5] = (uint8_t)(n >> 48); + iv[6] = (uint8_t)(n >> 40); + iv[7] = (uint8_t)(n >> 32); + iv[8] = (uint8_t)(n >> 24); + iv[9] = (uint8_t)(n >> 16); + iv[10] = (uint8_t)(n >> 8); + iv[11] = (uint8_t)n; +} + +int NoiseSymmetricState_AESGCM_SHA256::encryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize) +{ + if (st.hasKey) { + if (outputSize < 16 || (outputSize - 16) < inputSize) + return -1; + uint8_t iv[24]; + noiseAESGCMFormatIV(iv, st.n); + cipher.setIV(iv, sizeof(iv)); + cipher.encrypt(output, input, inputSize); + cipher.computeTag(output + inputSize, 16); + mixHash(output, inputSize + 16); + ++st.n; + return inputSize + 16; + } else { + if (outputSize < inputSize) + return -1; + memcpy(output, input, inputSize); + mixHash(output, inputSize); + return inputSize; + } +} + +int NoiseSymmetricState_AESGCM_SHA256::decryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize) +{ + if (st.hasKey) { + if (inputSize < 16 || outputSize < (inputSize - 16)) + return -1; + outputSize = inputSize - 16; + mixHash(input, inputSize); + uint8_t iv[24]; + noiseAESGCMFormatIV(iv, st.n); + cipher.setIV(iv, sizeof(iv)); + cipher.decrypt(output, input, outputSize); + if (cipher.checkTag(input + outputSize, 16)) { + ++st.n; + return outputSize; + } + memset(output, 0, outputSize); // Destroy output if tag is incorrect. + return -1; + } else { + if (outputSize < inputSize) + return -1; + mixHash(input, inputSize); + memcpy(output, input, inputSize); + return inputSize; + } +} + +void NoiseSymmetricState_AESGCM_SHA256::split + (NoiseCipherState **c1, NoiseCipherState **c2) +{ + uint8_t k1[32]; + uint8_t k2[32]; + hmac(k2, st.ck, 0, 0, 0); + hmac(k1, k2, 0, 0, 1); + hmac(k2, k2, k1, 32, 2); + if (c1) + *c1 = new NoiseCipherState_AESGCM(k1); + if (c2) + *c2 = new NoiseCipherState_AESGCM(k2); + clean(k1); + clean(k2); +} + +void NoiseSymmetricState_AESGCM_SHA256::clear() +{ + clean(st); + st.n = 0; + st.hasKey = false; +} + +void NoiseSymmetricState_AESGCM_SHA256::hmac + (uint8_t *output, const uint8_t *key, + const void *data, size_t size, uint8_t tag) +{ + SHA256 hash; + hash.resetHMAC(key, 32); + hash.update(data, size); + if (tag != 0) + hash.update(&tag, 1); + hash.finalizeHMAC(key, 32, output, 32); +} diff --git a/libraries/NoiseProtocol/src/NoiseSymmetricState_AESGCM_SHA256.h b/libraries/NoiseProtocol/src/NoiseSymmetricState_AESGCM_SHA256.h new file mode 100644 index 00000000..de169308 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseSymmetricState_AESGCM_SHA256.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_SYMMETRIC_STATE_AESGCM_SHA256_H +#define NOISE_SYMMETRIC_STATE_AESGCM_SHA256_H + +#include "NoiseSymmetricState.h" +#include "AES.h" +#include "GCM.h" + +class NoiseSymmetricState_AESGCM_SHA256 : public NoiseSymmetricState +{ +public: + NoiseSymmetricState_AESGCM_SHA256(); + virtual ~NoiseSymmetricState_AESGCM_SHA256(); + + void initialize(const char *protocolName); + + bool hasKey() const; + + void mixKey(const void *data, size_t size); + void mixHash(const void *data, size_t size); + void mixKeyAndHash(const void *data, size_t size); + + void getHandshakeHash(void *data, size_t size); + + int encryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize); + int decryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize); + + void split(NoiseCipherState **c1, NoiseCipherState **c2); + + void clear(); + +private: + GCM cipher; + struct { + uint8_t ck[32]; + uint8_t h[32]; + uint64_t n; + bool hasKey; + } st; + + static void hmac(uint8_t *output, const uint8_t *key, + const void *data, size_t size, uint8_t tag); +}; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_BLAKE2s.cpp b/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_BLAKE2s.cpp new file mode 100644 index 00000000..90059aa1 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_BLAKE2s.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseSymmetricState_ChaChaPoly_BLAKE2s.h" +#include "NoiseCipherState_ChaChaPoly.h" +#include "ChaChaPoly.h" +#include "BLAKE2s.h" +#include "Crypto.h" +#include "utility/EndianUtil.h" +#include + +/** + * \class NoiseSymmetricState_ChaChaPoly_BLAKE2s NoiseSymmetricState_ChaChaPoly_BLAKE2s.h + * \brief Noise symmetric state implementation using ChaChaPoly and BLAKE2s. + */ + +/** + * \brief Constructs a new symmetric state using ChaChaPoly and BLAKE2s. + */ +NoiseSymmetricState_ChaChaPoly_BLAKE2s::NoiseSymmetricState_ChaChaPoly_BLAKE2s() +{ + st.n = 0; + st.hasKey = false; +} + +/** + * \brief Destroys this symmetric state object. + */ +NoiseSymmetricState_ChaChaPoly_BLAKE2s::~NoiseSymmetricState_ChaChaPoly_BLAKE2s() +{ + clean(st); +} + +void NoiseSymmetricState_ChaChaPoly_BLAKE2s::initialize + (const char *protocolName) +{ + size_t len = strlen(protocolName); + if (len <= 32) { + memcpy(st.h, protocolName, len); + memset(st.h + len, 0, 32 - len); + } else { + BLAKE2s hash; + hash.update(protocolName, len); + hash.finalize(st.h, 32); + } + memcpy(st.ck, st.h, 32); + st.hasKey = false; +} + +bool NoiseSymmetricState_ChaChaPoly_BLAKE2s::hasKey() const +{ + return st.hasKey; +} + +void NoiseSymmetricState_ChaChaPoly_BLAKE2s::mixKey + (const void *data, size_t size) +{ + hmac(st.key, st.ck, data, size, 0); + hmac(st.ck, st.key, 0, 0, 1); + hmac(st.key, st.key, st.ck, 32, 2); + st.hasKey = true; + st.n = 0; +} + +void NoiseSymmetricState_ChaChaPoly_BLAKE2s::mixHash + (const void *data, size_t size) +{ + BLAKE2s hash; + hash.update(st.h, sizeof(st.h)); + hash.update(data, size); + hash.finalize(st.h, sizeof(st.h)); +} + +void NoiseSymmetricState_ChaChaPoly_BLAKE2s::mixKeyAndHash + (const void *data, size_t size) +{ + uint8_t temph[32]; + hmac(st.key, st.ck, data, size, 0); + hmac(st.ck, st.key, 0, 0, 1); + hmac(temph, st.key, st.ck, 32, 2); + hmac(st.key, st.key, temph, 32, 3); + st.hasKey = true; + st.n = 0; + mixHash(temph, 32); + clean(temph); +} + +void NoiseSymmetricState_ChaChaPoly_BLAKE2s::getHandshakeHash + (void *data, size_t size) +{ + if (size <= 32) { + memcpy(data, st.h, size); + } else { + memcpy(data, st.h, 32); + memset(((uint8_t *)data) + 32, 0, size - 32); + } +} + +int NoiseSymmetricState_ChaChaPoly_BLAKE2s::encryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize) +{ + if (st.hasKey) { + if (outputSize < 16 || (outputSize - 16) < inputSize) + return -1; + ChaChaPoly cipher; + uint64_t iv = htole64(st.n); + cipher.setKey(st.key, 32); + cipher.setIV((const uint8_t *)&iv, sizeof(iv)); + cipher.encrypt(output, input, inputSize); + cipher.computeTag(output + inputSize, 16); + mixHash(output, inputSize + 16); + ++st.n; + return inputSize + 16; + } else { + if (outputSize < inputSize) + return -1; + memcpy(output, input, inputSize); + mixHash(output, inputSize); + return inputSize; + } +} + +int NoiseSymmetricState_ChaChaPoly_BLAKE2s::decryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize) +{ + if (st.hasKey) { + if (inputSize < 16 || outputSize < (inputSize - 16)) + return -1; + outputSize = inputSize - 16; + mixHash(input, inputSize); + ChaChaPoly cipher; + uint64_t iv = htole64(st.n); + cipher.setKey(st.key, 32); + cipher.setIV((const uint8_t *)&iv, sizeof(iv)); + cipher.decrypt(output, input, outputSize); + if (cipher.checkTag(input + outputSize, 16)) { + ++st.n; + return outputSize; + } + memset(output, 0, outputSize); // Destroy output if tag is incorrect. + return -1; + } else { + if (outputSize < inputSize) + return -1; + mixHash(input, inputSize); + memcpy(output, input, inputSize); + return inputSize; + } +} + +void NoiseSymmetricState_ChaChaPoly_BLAKE2s::split + (NoiseCipherState **c1, NoiseCipherState **c2) +{ + uint8_t k1[32]; + uint8_t k2[32]; + hmac(k2, st.ck, 0, 0, 0); + hmac(k1, k2, 0, 0, 1); + hmac(k2, k2, k1, 32, 2); + if (c1) + *c1 = new NoiseCipherState_ChaChaPoly(k1); + if (c2) + *c2 = new NoiseCipherState_ChaChaPoly(k2); + clean(k1); + clean(k2); +} + +void NoiseSymmetricState_ChaChaPoly_BLAKE2s::clear() +{ + clean(st); + st.n = 0; + st.hasKey = false; +} + +void NoiseSymmetricState_ChaChaPoly_BLAKE2s::hmac + (uint8_t *output, const uint8_t *key, + const void *data, size_t size, uint8_t tag) +{ + BLAKE2s hash; + hash.resetHMAC(key, 32); + hash.update(data, size); + if (tag != 0) + hash.update(&tag, 1); + hash.finalizeHMAC(key, 32, output, 32); +} diff --git a/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_BLAKE2s.h b/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_BLAKE2s.h new file mode 100644 index 00000000..1861d14c --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_BLAKE2s.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_SYMMETRIC_STATE_CHACHAPOLY_BLAKE2S_H +#define NOISE_SYMMETRIC_STATE_CHACHAPOLY_BLAKE2S_H + +#include "NoiseSymmetricState.h" + +class NoiseSymmetricState_ChaChaPoly_BLAKE2s : public NoiseSymmetricState +{ +public: + NoiseSymmetricState_ChaChaPoly_BLAKE2s(); + virtual ~NoiseSymmetricState_ChaChaPoly_BLAKE2s(); + + void initialize(const char *protocolName); + + bool hasKey() const; + + void mixKey(const void *data, size_t size); + void mixHash(const void *data, size_t size); + void mixKeyAndHash(const void *data, size_t size); + + void getHandshakeHash(void *data, size_t size); + + int encryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize); + int decryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize); + + void split(NoiseCipherState **c1, NoiseCipherState **c2); + + void clear(); + +private: + struct { + uint8_t ck[32]; + uint8_t h[32]; + uint8_t key[32]; + uint64_t n; + bool hasKey; + } st; + + static void hmac(uint8_t *output, const uint8_t *key, + const void *data, size_t size, uint8_t tag); +}; + +#endif diff --git a/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_SHA256.cpp b/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_SHA256.cpp new file mode 100644 index 00000000..0d5343a6 --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_SHA256.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "NoiseSymmetricState_ChaChaPoly_SHA256.h" +#include "NoiseCipherState_ChaChaPoly.h" +#include "ChaChaPoly.h" +#include "SHA256.h" +#include "Crypto.h" +#include "utility/EndianUtil.h" +#include + +/** + * \class NoiseSymmetricState_ChaChaPoly_SHA256 NoiseSymmetricState_ChaChaPoly_SHA256.h + * \brief Noise symmetric state implementation using ChaChaPoly and SHA256. + */ + +/** + * \brief Constructs a new symmetric state using ChaChaPoly and SHA256. + */ +NoiseSymmetricState_ChaChaPoly_SHA256::NoiseSymmetricState_ChaChaPoly_SHA256() +{ + st.n = 0; + st.hasKey = false; +} + +/** + * \brief Destroys this symmetric state object. + */ +NoiseSymmetricState_ChaChaPoly_SHA256::~NoiseSymmetricState_ChaChaPoly_SHA256() +{ + clean(st); +} + +void NoiseSymmetricState_ChaChaPoly_SHA256::initialize + (const char *protocolName) +{ + size_t len = strlen(protocolName); + if (len <= 32) { + memcpy(st.h, protocolName, len); + memset(st.h + len, 0, 32 - len); + } else { + SHA256 hash; + hash.update(protocolName, len); + hash.finalize(st.h, 32); + } + memcpy(st.ck, st.h, 32); + st.hasKey = false; +} + +bool NoiseSymmetricState_ChaChaPoly_SHA256::hasKey() const +{ + return st.hasKey; +} + +void NoiseSymmetricState_ChaChaPoly_SHA256::mixKey + (const void *data, size_t size) +{ + hmac(st.key, st.ck, data, size, 0); + hmac(st.ck, st.key, 0, 0, 1); + hmac(st.key, st.key, st.ck, 32, 2); + st.hasKey = true; + st.n = 0; +} + +void NoiseSymmetricState_ChaChaPoly_SHA256::mixHash + (const void *data, size_t size) +{ + SHA256 hash; + hash.update(st.h, sizeof(st.h)); + hash.update(data, size); + hash.finalize(st.h, sizeof(st.h)); +} + +void NoiseSymmetricState_ChaChaPoly_SHA256::mixKeyAndHash + (const void *data, size_t size) +{ + uint8_t temph[32]; + hmac(st.key, st.ck, data, size, 0); + hmac(st.ck, st.key, 0, 0, 1); + hmac(temph, st.key, st.ck, 32, 2); + hmac(st.key, st.key, temph, 32, 3); + st.hasKey = true; + st.n = 0; + mixHash(temph, 32); + clean(temph); +} + +void NoiseSymmetricState_ChaChaPoly_SHA256::getHandshakeHash + (void *data, size_t size) +{ + if (size <= 32) { + memcpy(data, st.h, size); + } else { + memcpy(data, st.h, 32); + memset(((uint8_t *)data) + 32, 0, size - 32); + } +} + +int NoiseSymmetricState_ChaChaPoly_SHA256::encryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize) +{ + if (st.hasKey) { + if (outputSize < 16 || (outputSize - 16) < inputSize) + return -1; + ChaChaPoly cipher; + uint64_t iv = htole64(st.n); + cipher.setKey(st.key, 32); + cipher.setIV((const uint8_t *)&iv, sizeof(iv)); + cipher.encrypt(output, input, inputSize); + cipher.computeTag(output + inputSize, 16); + mixHash(output, inputSize + 16); + ++st.n; + return inputSize + 16; + } else { + if (outputSize < inputSize) + return -1; + memcpy(output, input, inputSize); + mixHash(output, inputSize); + return inputSize; + } +} + +int NoiseSymmetricState_ChaChaPoly_SHA256::decryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize) +{ + if (st.hasKey) { + if (inputSize < 16 || outputSize < (inputSize - 16)) + return -1; + outputSize = inputSize - 16; + mixHash(input, inputSize); + ChaChaPoly cipher; + uint64_t iv = htole64(st.n); + cipher.setKey(st.key, 32); + cipher.setIV((const uint8_t *)&iv, sizeof(iv)); + cipher.decrypt(output, input, outputSize); + if (cipher.checkTag(input + outputSize, 16)) { + ++st.n; + return outputSize; + } + memset(output, 0, outputSize); // Destroy output if tag is incorrect. + return -1; + } else { + if (outputSize < inputSize) + return -1; + mixHash(input, inputSize); + memcpy(output, input, inputSize); + return inputSize; + } +} + +void NoiseSymmetricState_ChaChaPoly_SHA256::split + (NoiseCipherState **c1, NoiseCipherState **c2) +{ + uint8_t k1[32]; + uint8_t k2[32]; + hmac(k2, st.ck, 0, 0, 0); + hmac(k1, k2, 0, 0, 1); + hmac(k2, k2, k1, 32, 2); + if (c1) + *c1 = new NoiseCipherState_ChaChaPoly(k1); + if (c2) + *c2 = new NoiseCipherState_ChaChaPoly(k2); + clean(k1); + clean(k2); +} + +void NoiseSymmetricState_ChaChaPoly_SHA256::clear() +{ + clean(st); + st.n = 0; + st.hasKey = false; +} + +void NoiseSymmetricState_ChaChaPoly_SHA256::hmac + (uint8_t *output, const uint8_t *key, + const void *data, size_t size, uint8_t tag) +{ + SHA256 hash; + hash.resetHMAC(key, 32); + hash.update(data, size); + if (tag != 0) + hash.update(&tag, 1); + hash.finalizeHMAC(key, 32, output, 32); +} diff --git a/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_SHA256.h b/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_SHA256.h new file mode 100644 index 00000000..b66ddb8d --- /dev/null +++ b/libraries/NoiseProtocol/src/NoiseSymmetricState_ChaChaPoly_SHA256.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_SYMMETRIC_STATE_CHACHAPOLY_SHA256_H +#define NOISE_SYMMETRIC_STATE_CHACHAPOLY_SHA256_H + +#include "NoiseSymmetricState.h" + +class NoiseSymmetricState_ChaChaPoly_SHA256 : public NoiseSymmetricState +{ +public: + NoiseSymmetricState_ChaChaPoly_SHA256(); + virtual ~NoiseSymmetricState_ChaChaPoly_SHA256(); + + void initialize(const char *protocolName); + + bool hasKey() const; + + void mixKey(const void *data, size_t size); + void mixHash(const void *data, size_t size); + void mixKeyAndHash(const void *data, size_t size); + + void getHandshakeHash(void *data, size_t size); + + int encryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize); + int decryptAndHash + (uint8_t *output, size_t outputSize, + const uint8_t *input, size_t inputSize); + + void split(NoiseCipherState **c1, NoiseCipherState **c2); + + void clear(); + +private: + struct { + uint8_t ck[32]; + uint8_t h[32]; + uint8_t key[32]; + uint64_t n; + bool hasKey; + } st; + + static void hmac(uint8_t *output, const uint8_t *key, + const void *data, size_t size, uint8_t tag); +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_IK.cpp b/libraries/NoiseProtocol/src/Noise_IK.cpp new file mode 100644 index 00000000..1b6d036b --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_IK.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_IK.h" + +/** + * \class NoiseHandshakeState_IK Noise_IK.h + * \brief Handshake implementation of the Noise "IK" pattern. + * + * The "IK" pattern provides mutual authentication of the two communicating + * parties, with the identifying key for the initiating party sent during + * the handshake. The identifying key for the responding party is assumed + * to already be known to the initiator. If the responding party's key + * changes, then the application will need to transition to "XXfallback" + * to discover the new key. + * + * This class provides the core "IK" functionality. Subclasses provide + * implementations of "IK" that use specific algorithms, such as + * Noise_IK_25519_ChaChaPoly_BLAKE2s. + */ + +/** + * \fn NoiseHandshakeState_IK::NoiseHandshakeState_IK() + * \brief Constructs a new Noise handshake that uses the IK pattern. + */ + +/** + * \brief Destroys this Noise handshake. + */ +NoiseHandshakeState_IK::~NoiseHandshakeState_IK() +{ +} + +void NoiseHandshakeState_IK::writeTokens + (NoiseHandshakeState::Packet &packet, uint8_t msgnum) +{ + if (msgnum == 0) { + write_e(packet); + write_es(packet); + write_s(packet); + write_ss(packet); + } else if (msgnum == 1) { + write_e(packet); + write_ee(packet); + write_se(packet); + packet.done = true; + } +} + +void NoiseHandshakeState_IK::readTokens + (NoiseHandshakeState::Packet &packet, uint8_t msgnum) +{ + if (msgnum == 0) { + read_e(packet); + read_es(packet); + read_s(packet); + read_ss(packet); + } else if (msgnum == 1) { + read_e(packet); + read_ee(packet); + read_se(packet); + packet.done = true; + } +} diff --git a/libraries/NoiseProtocol/src/Noise_IK.h b/libraries/NoiseProtocol/src/Noise_IK.h new file mode 100644 index 00000000..bd30e424 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_IK.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_IK_h +#define NOISE_IK_h + +#include "NoiseHandshakeState.h" + +class NoiseHandshakeState_IK : public NoiseHandshakeState +{ +public: + virtual ~NoiseHandshakeState_IK(); + +protected: + NoiseHandshakeState_IK() {} + + void writeTokens(NoiseHandshakeState::Packet &packet, uint8_t msgnum); + void readTokens(NoiseHandshakeState::Packet &packet, uint8_t msgnum); +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_IK_25519_AESGCM_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_IK_25519_AESGCM_SHA256.cpp new file mode 100644 index 00000000..88868f4c --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_IK_25519_AESGCM_SHA256.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_IK_25519_AESGCM_SHA256.h" + +/** + * \class NoiseHandshakeState_IK_25519_AESGCM_SHA256 Noise_IK_25519_AESGCM_SHA256.h + * \brief "IK" Noise handshake, using Curve25519, AES256, GCM, and SHA256. + */ + +/** + * \class Noise_IK_25519_AESGCM_SHA256 Noise_IK_25519_AESGCM_SHA256.h + * \brief "IK" Noise descriptor, using Curve25519, AES256, GCM, and SHA256. + */ + +static char const Noise_IK_25519_AESGCM_SHA256_Name[] = + "Noise_IK_25519_AESGCM_SHA256"; + +NoiseHandshakeState_IK_25519_AESGCM_SHA256::NoiseHandshakeState_IK_25519_AESGCM_SHA256() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_IK_25519_AESGCM_SHA256_Name); +} + +NoiseHandshakeState_IK_25519_AESGCM_SHA256::~NoiseHandshakeState_IK_25519_AESGCM_SHA256() +{ +} + +Noise_IK_25519_AESGCM_SHA256::Noise_IK_25519_AESGCM_SHA256() + : NoiseProtocolDescriptor(Noise_IK_25519_AESGCM_SHA256_Name) +{ +} + +Noise_IK_25519_AESGCM_SHA256::~Noise_IK_25519_AESGCM_SHA256() +{ +} + +NoiseHandshakeState *Noise_IK_25519_AESGCM_SHA256::createHandshake() const +{ + return new NoiseHandshakeState_IK_25519_AESGCM_SHA256(); +} diff --git a/libraries/NoiseProtocol/src/Noise_IK_25519_AESGCM_SHA256.h b/libraries/NoiseProtocol/src/Noise_IK_25519_AESGCM_SHA256.h new file mode 100644 index 00000000..91f8b0be --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_IK_25519_AESGCM_SHA256.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_IK_25519_AESGCM_SHA256_h +#define NOISE_IK_25519_AESGCM_SHA256_h + +#include "Noise_IK.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_AESGCM_SHA256.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_IK_25519_AESGCM_SHA256 : public NoiseHandshakeState_IK +{ +public: + NoiseHandshakeState_IK_25519_AESGCM_SHA256(); + virtual ~NoiseHandshakeState_IK_25519_AESGCM_SHA256(); + +private: + NoiseSymmetricState_AESGCM_SHA256 sym; + NoiseDHState_Curve25519 dh; +}; + +class Noise_IK_25519_AESGCM_SHA256 : public NoiseProtocolDescriptor +{ +public: + Noise_IK_25519_AESGCM_SHA256(); + virtual ~Noise_IK_25519_AESGCM_SHA256(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_BLAKE2s.cpp b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_BLAKE2s.cpp new file mode 100644 index 00000000..a98bb8b2 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_BLAKE2s.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_IK_25519_ChaChaPoly_BLAKE2s.h" + +/** + * \class NoiseHandshakeState_IK_25519_ChaChaPoly_BLAKE2s Noise_IK_25519_ChaChaPoly_BLAKE2s.h + * \brief "IK" Noise handshake, using Curve25519, ChaChaPoly, and BLAKE2s. + */ + +/** + * \class Noise_IK_25519_ChaChaPoly_BLAKE2s Noise_IK_25519_ChaChaPoly_BLAKE2s.h + * \brief "IK" Noise descriptor, using Curve25519, ChaChaPoly, and BLAKE2s. + */ + +static char const Noise_IK_25519_ChaChaPoly_BLAKE2s_Name[] = + "Noise_IK_25519_ChaChaPoly_BLAKE2s"; + +NoiseHandshakeState_IK_25519_ChaChaPoly_BLAKE2s::NoiseHandshakeState_IK_25519_ChaChaPoly_BLAKE2s() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_IK_25519_ChaChaPoly_BLAKE2s_Name); +} + +NoiseHandshakeState_IK_25519_ChaChaPoly_BLAKE2s::~NoiseHandshakeState_IK_25519_ChaChaPoly_BLAKE2s() +{ +} + +Noise_IK_25519_ChaChaPoly_BLAKE2s::Noise_IK_25519_ChaChaPoly_BLAKE2s() + : NoiseProtocolDescriptor(Noise_IK_25519_ChaChaPoly_BLAKE2s_Name) +{ +} + +Noise_IK_25519_ChaChaPoly_BLAKE2s::~Noise_IK_25519_ChaChaPoly_BLAKE2s() +{ +} + +NoiseHandshakeState *Noise_IK_25519_ChaChaPoly_BLAKE2s::createHandshake() const +{ + return new NoiseHandshakeState_IK_25519_ChaChaPoly_BLAKE2s(); +} diff --git a/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_BLAKE2s.h b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_BLAKE2s.h new file mode 100644 index 00000000..132d02ee --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_BLAKE2s.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_IK_25519_CHACHAPOLY_BLAKE2S_h +#define NOISE_IK_25519_CHACHAPOLY_BLAKE2S_h + +#include "Noise_IK.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_ChaChaPoly_BLAKE2s.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_IK_25519_ChaChaPoly_BLAKE2s + : public NoiseHandshakeState_IK +{ +public: + NoiseHandshakeState_IK_25519_ChaChaPoly_BLAKE2s(); + virtual ~NoiseHandshakeState_IK_25519_ChaChaPoly_BLAKE2s(); + +private: + NoiseSymmetricState_ChaChaPoly_BLAKE2s sym; + NoiseDHState_Curve25519 dh; +}; + +class Noise_IK_25519_ChaChaPoly_BLAKE2s : public NoiseProtocolDescriptor +{ +public: + Noise_IK_25519_ChaChaPoly_BLAKE2s(); + virtual ~Noise_IK_25519_ChaChaPoly_BLAKE2s(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_SHA256.cpp new file mode 100644 index 00000000..e60eed53 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_SHA256.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_IK_25519_ChaChaPoly_SHA256.h" + +/** + * \class NoiseHandshakeState_IK_25519_ChaChaPoly_SHA256 Noise_IK_25519_ChaChaPoly_SHA256.h + * \brief "IK" Noise handshake, using Curve25519, ChaChaPoly, and SHA256. + */ + +/** + * \class Noise_IK_25519_ChaChaPoly_SHA256 Noise_IK_25519_ChaChaPoly_SHA256.h + * \brief "IK" Noise descriptor, using Curve25519, ChaChaPoly, and SHA256. + */ + +static char const Noise_IK_25519_ChaChaPoly_SHA256_Name[] = + "Noise_IK_25519_ChaChaPoly_SHA256"; + +NoiseHandshakeState_IK_25519_ChaChaPoly_SHA256::NoiseHandshakeState_IK_25519_ChaChaPoly_SHA256() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_IK_25519_ChaChaPoly_SHA256_Name); +} + +NoiseHandshakeState_IK_25519_ChaChaPoly_SHA256::~NoiseHandshakeState_IK_25519_ChaChaPoly_SHA256() +{ +} + +Noise_IK_25519_ChaChaPoly_SHA256::Noise_IK_25519_ChaChaPoly_SHA256() + : NoiseProtocolDescriptor(Noise_IK_25519_ChaChaPoly_SHA256_Name) +{ +} + +Noise_IK_25519_ChaChaPoly_SHA256::~Noise_IK_25519_ChaChaPoly_SHA256() +{ +} + +NoiseHandshakeState *Noise_IK_25519_ChaChaPoly_SHA256::createHandshake() const +{ + return new NoiseHandshakeState_IK_25519_ChaChaPoly_SHA256(); +} diff --git a/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_SHA256.h b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_SHA256.h new file mode 100644 index 00000000..3e95e03e --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_IK_25519_ChaChaPoly_SHA256.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_IK_25519_CHACHAPOLY_SHA256_h +#define NOISE_IK_25519_CHACHAPOLY_SHA256_h + +#include "Noise_IK.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_ChaChaPoly_SHA256.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_IK_25519_ChaChaPoly_SHA256 + : public NoiseHandshakeState_IK +{ +public: + NoiseHandshakeState_IK_25519_ChaChaPoly_SHA256(); + virtual ~NoiseHandshakeState_IK_25519_ChaChaPoly_SHA256(); + +private: + NoiseSymmetricState_ChaChaPoly_SHA256 sym; + NoiseDHState_Curve25519 dh; +}; + +class Noise_IK_25519_ChaChaPoly_SHA256 : public NoiseProtocolDescriptor +{ +public: + Noise_IK_25519_ChaChaPoly_SHA256(); + virtual ~Noise_IK_25519_ChaChaPoly_SHA256(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0.cpp b/libraries/NoiseProtocol/src/Noise_NNpsk0.cpp new file mode 100644 index 00000000..b3c2e586 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_NNpsk0.h" + +/** + * \class NoiseHandshakeState_NNpsk0 Noise_NNpsk0.h + * \brief Handshake implementation of the Noise "NNpsk0" pattern. + * + * The "NNpsk0" pattern is intended for use in place of "XX" when + * the parties have a pre-shared symmetric key (or "PSK"). + * + * This class provides the core "NNpsk0" functionality. Subclasses provide + * implementations of "NNpsk0" that use specific algorithms, such as + * Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s. + */ + +/** + * \fn NoiseHandshakeState_NNpsk0::NoiseHandshakeState_NNpsk0() + * \brief Constructs a new Noise handshake that uses the NNpsk0 pattern. + */ + +/** + * \brief Destroys this Noise handshake. + */ +NoiseHandshakeState_NNpsk0::~NoiseHandshakeState_NNpsk0() +{ +} + +void NoiseHandshakeState_NNpsk0::writeTokens + (NoiseHandshakeState::Packet &packet, uint8_t msgnum) +{ + if (msgnum == 0) { + write_psk(packet); + write_e(packet); + } else if (msgnum == 1) { + write_e(packet); + write_ee(packet); + packet.done = true; + } +} + +void NoiseHandshakeState_NNpsk0::readTokens + (NoiseHandshakeState::Packet &packet, uint8_t msgnum) +{ + if (msgnum == 0) { + read_psk(packet); + read_e(packet); + } else if (msgnum == 1) { + read_e(packet); + read_ee(packet); + packet.done = true; + } +} diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0.h b/libraries/NoiseProtocol/src/Noise_NNpsk0.h new file mode 100644 index 00000000..12511827 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_NN_PSK0_h +#define NOISE_NN_PSK0_h + +#include "NoiseHandshakeState.h" + +class NoiseHandshakeState_NNpsk0 : public NoiseHandshakeStatePSK +{ +public: + virtual ~NoiseHandshakeState_NNpsk0(); + +protected: + NoiseHandshakeState_NNpsk0() {} + + void writeTokens(NoiseHandshakeState::Packet &packet, uint8_t msgnum); + void readTokens(NoiseHandshakeState::Packet &packet, uint8_t msgnum); +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_AESGCM_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_AESGCM_SHA256.cpp new file mode 100644 index 00000000..719f0323 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_AESGCM_SHA256.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_NNpsk0_25519_AESGCM_SHA256.h" + +/** + * \class NoiseHandshakeState_NNpsk0_25519_AESGCM_SHA256 Noise_NNpsk0_25519_AESGCM_SHA256.h + * \brief "NNpsk0" Noise handshake, using Curve25519, AES256, GCM, and SHA256. + */ + +/** + * \class Noise_NNpsk0_25519_AESGCM_SHA256 Noise_NNpsk0_25519_AESGCM_SHA256.h + * \brief "NNpsk0" Noise descriptor, using Curve25519, AES256, GCM, and SHA256. + */ + +static char const Noise_NNpsk0_25519_AESGCM_SHA256_Name[] = + "Noise_NNpsk0_25519_AESGCM_SHA256"; + +NoiseHandshakeState_NNpsk0_25519_AESGCM_SHA256::NoiseHandshakeState_NNpsk0_25519_AESGCM_SHA256() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_NNpsk0_25519_AESGCM_SHA256_Name); +} + +NoiseHandshakeState_NNpsk0_25519_AESGCM_SHA256::~NoiseHandshakeState_NNpsk0_25519_AESGCM_SHA256() +{ +} + +Noise_NNpsk0_25519_AESGCM_SHA256::Noise_NNpsk0_25519_AESGCM_SHA256() + : NoiseProtocolDescriptor(Noise_NNpsk0_25519_AESGCM_SHA256_Name) +{ +} + +Noise_NNpsk0_25519_AESGCM_SHA256::~Noise_NNpsk0_25519_AESGCM_SHA256() +{ +} + +NoiseHandshakeState *Noise_NNpsk0_25519_AESGCM_SHA256::createHandshake() const +{ + return new NoiseHandshakeState_NNpsk0_25519_AESGCM_SHA256(); +} diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_AESGCM_SHA256.h b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_AESGCM_SHA256.h new file mode 100644 index 00000000..48f0c2c8 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_AESGCM_SHA256.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_NN_PSK0_25519_AESGCM_SHA256_h +#define NOISE_NN_PSK0_25519_AESGCM_SHA256_h + +#include "Noise_NNpsk0.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_AESGCM_SHA256.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_NNpsk0_25519_AESGCM_SHA256 + : public NoiseHandshakeState_NNpsk0 +{ +public: + NoiseHandshakeState_NNpsk0_25519_AESGCM_SHA256(); + virtual ~NoiseHandshakeState_NNpsk0_25519_AESGCM_SHA256(); + +private: + NoiseSymmetricState_AESGCM_SHA256 sym; + NoiseDHState_Curve25519_EphemOnly dh; +}; + +class Noise_NNpsk0_25519_AESGCM_SHA256 : public NoiseProtocolDescriptor +{ +public: + Noise_NNpsk0_25519_AESGCM_SHA256(); + virtual ~Noise_NNpsk0_25519_AESGCM_SHA256(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.cpp b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.cpp new file mode 100644 index 00000000..7ceffca7 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.h" + +/** + * \class NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_BLAKE2s Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.h + * \brief "NNpsk0" Noise handshake, using Curve25519, ChaChaPoly, and BLAKE2s. + */ + +/** + * \class Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.h + * \brief "NNpsk0" Noise descriptor, using Curve25519, ChaChaPoly, and BLAKE2s. + */ + +static char const Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s_Name[] = + "Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s"; + +NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_BLAKE2s::NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_BLAKE2s() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s_Name); +} + +NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_BLAKE2s::~NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_BLAKE2s() +{ +} + +Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s::Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s() + : NoiseProtocolDescriptor(Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s_Name) +{ +} + +Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s::~Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s() +{ +} + +NoiseHandshakeState *Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s::createHandshake() const +{ + return new NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_BLAKE2s(); +} diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.h b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.h new file mode 100644 index 00000000..c89bf7cf --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_NN_PSK0_25519_CHACHAPOLY_BLAKE2S_h +#define NOISE_NN_PSK0_25519_CHACHAPOLY_BLAKE2S_h + +#include "Noise_NNpsk0.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_ChaChaPoly_BLAKE2s.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_BLAKE2s + : public NoiseHandshakeState_NNpsk0 +{ +public: + NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_BLAKE2s(); + virtual ~NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_BLAKE2s(); + +private: + NoiseSymmetricState_ChaChaPoly_BLAKE2s sym; + NoiseDHState_Curve25519_EphemOnly dh; +}; + +class Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s : public NoiseProtocolDescriptor +{ +public: + Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s(); + virtual ~Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_SHA256.cpp new file mode 100644 index 00000000..e51cb4e6 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_SHA256.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_NNpsk0_25519_ChaChaPoly_SHA256.h" + +/** + * \class NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_SHA256 Noise_NNpsk0_25519_ChaChaPoly_SHA256.h + * \brief "NNpsk0" Noise handshake, using Curve25519, ChaChaPoly, and SHA256. + */ + +/** + * \class Noise_NNpsk0_25519_ChaChaPoly_SHA256 Noise_NNpsk0_25519_ChaChaPoly_SHA256.h + * \brief "NNpsk0" Noise descriptor, using Curve25519, ChaChaPoly, and SHA256. + */ + +static char const Noise_NNpsk0_25519_ChaChaPoly_SHA256_Name[] = + "Noise_NNpsk0_25519_ChaChaPoly_SHA256"; + +NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_SHA256::NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_SHA256() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_NNpsk0_25519_ChaChaPoly_SHA256_Name); +} + +NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_SHA256::~NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_SHA256() +{ +} + +Noise_NNpsk0_25519_ChaChaPoly_SHA256::Noise_NNpsk0_25519_ChaChaPoly_SHA256() + : NoiseProtocolDescriptor(Noise_NNpsk0_25519_ChaChaPoly_SHA256_Name) +{ +} + +Noise_NNpsk0_25519_ChaChaPoly_SHA256::~Noise_NNpsk0_25519_ChaChaPoly_SHA256() +{ +} + +NoiseHandshakeState *Noise_NNpsk0_25519_ChaChaPoly_SHA256::createHandshake() const +{ + return new NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_SHA256(); +} diff --git a/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_SHA256.h b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_SHA256.h new file mode 100644 index 00000000..9713853e --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_NNpsk0_25519_ChaChaPoly_SHA256.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_NN_PSK0_25519_CHACHAPOLY_SHA256_h +#define NOISE_NN_PSK0_25519_CHACHAPOLY_SHA256_h + +#include "Noise_NNpsk0.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_ChaChaPoly_SHA256.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_SHA256 + : public NoiseHandshakeState_NNpsk0 +{ +public: + NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_SHA256(); + virtual ~NoiseHandshakeState_NNpsk0_25519_ChaChaPoly_SHA256(); + +private: + NoiseSymmetricState_ChaChaPoly_SHA256 sym; + NoiseDHState_Curve25519_EphemOnly dh; +}; + +class Noise_NNpsk0_25519_ChaChaPoly_SHA256 : public NoiseProtocolDescriptor +{ +public: + Noise_NNpsk0_25519_ChaChaPoly_SHA256(); + virtual ~Noise_NNpsk0_25519_ChaChaPoly_SHA256(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_Pipes_25519_AESGCM_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_Pipes_25519_AESGCM_SHA256.cpp new file mode 100644 index 00000000..b4041344 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_Pipes_25519_AESGCM_SHA256.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_Pipes_25519_AESGCM_SHA256.h" + +/** + * \class Noise_Pipes_25519_AESGCM_SHA256 Noise_Pipes_25519_AESGCM_SHA256.h + * \brief Noise Pipes descriptor, using Curve25519, AES256, GCM, and SHA256. + * + * Noise Pipes combines the effect of XX, IK, and XXfallback to produce a + * protocol that requires only two handshake messages if the responder's + * static public key is known, or three handshake messages if the key + * is unknown or incorrect. + */ + +Noise_Pipes_25519_AESGCM_SHA256::Noise_Pipes_25519_AESGCM_SHA256() +{ +} + +Noise_Pipes_25519_AESGCM_SHA256::~Noise_Pipes_25519_AESGCM_SHA256() +{ +} + +const NoiseProtocolDescriptor *Noise_Pipes_25519_AESGCM_SHA256::abbreviatedDescriptor() const +{ + return &ik; +} + +const NoiseProtocolDescriptor *Noise_Pipes_25519_AESGCM_SHA256::fallbackDescriptor() const +{ + return &fallback; +} diff --git a/libraries/NoiseProtocol/src/Noise_Pipes_25519_AESGCM_SHA256.h b/libraries/NoiseProtocol/src/Noise_Pipes_25519_AESGCM_SHA256.h new file mode 100644 index 00000000..1be38abd --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_Pipes_25519_AESGCM_SHA256.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_PIPES_25519_AESGCM_SHA256_h +#define NOISE_PIPES_25519_AESGCM_SHA256_h + +#include "Noise_XX_25519_AESGCM_SHA256.h" +#include "Noise_IK_25519_AESGCM_SHA256.h" +#include "Noise_XXfallback_25519_AESGCM_SHA256.h" + +class Noise_Pipes_25519_AESGCM_SHA256 : + public Noise_XX_25519_AESGCM_SHA256 +{ +public: + Noise_Pipes_25519_AESGCM_SHA256(); + virtual ~Noise_Pipes_25519_AESGCM_SHA256(); + + const NoiseProtocolDescriptor *abbreviatedDescriptor() const; + const NoiseProtocolDescriptor *fallbackDescriptor() const; + +private: + Noise_IK_25519_AESGCM_SHA256 ik; + Noise_XXfallback_25519_AESGCM_SHA256 fallback; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_BLAKE2s.cpp b/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_BLAKE2s.cpp new file mode 100644 index 00000000..88aea122 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_BLAKE2s.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_Pipes_25519_ChaChaPoly_BLAKE2s.h" + +/** + * \class Noise_Pipes_25519_ChaChaPoly_BLAKE2s Noise_Pipes_25519_ChaChaPoly_BLAKE2s.h + * \brief Noise Pipes descriptor, using Curve25519, ChaChaPoly, and BLAKE2s. + * + * Noise Pipes combines the effect of XX, IK, and XXfallback to produce a + * protocol that requires only two handshake messages if the responder's + * static public key is known, or three handshake messages if the key + * is unknown or incorrect. + */ + +Noise_Pipes_25519_ChaChaPoly_BLAKE2s::Noise_Pipes_25519_ChaChaPoly_BLAKE2s() +{ +} + +Noise_Pipes_25519_ChaChaPoly_BLAKE2s::~Noise_Pipes_25519_ChaChaPoly_BLAKE2s() +{ +} + +const NoiseProtocolDescriptor *Noise_Pipes_25519_ChaChaPoly_BLAKE2s::abbreviatedDescriptor() const +{ + return &ik; +} + +const NoiseProtocolDescriptor *Noise_Pipes_25519_ChaChaPoly_BLAKE2s::fallbackDescriptor() const +{ + return &fallback; +} diff --git a/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_BLAKE2s.h b/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_BLAKE2s.h new file mode 100644 index 00000000..5c0d8bef --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_BLAKE2s.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_PIPES_25519_CHACHAPOLY_BLAKE2S_h +#define NOISE_PIPES_25519_CHACHAPOLY_BLAKE2S_h + +#include "Noise_XX_25519_ChaChaPoly_BLAKE2s.h" +#include "Noise_IK_25519_ChaChaPoly_BLAKE2s.h" +#include "Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.h" + +class Noise_Pipes_25519_ChaChaPoly_BLAKE2s : + public Noise_XX_25519_ChaChaPoly_BLAKE2s +{ +public: + Noise_Pipes_25519_ChaChaPoly_BLAKE2s(); + virtual ~Noise_Pipes_25519_ChaChaPoly_BLAKE2s(); + + const NoiseProtocolDescriptor *abbreviatedDescriptor() const; + const NoiseProtocolDescriptor *fallbackDescriptor() const; + +private: + Noise_IK_25519_ChaChaPoly_BLAKE2s ik; + Noise_XXfallback_25519_ChaChaPoly_BLAKE2s fallback; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_SHA256.cpp new file mode 100644 index 00000000..5a795acd --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_SHA256.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_Pipes_25519_ChaChaPoly_SHA256.h" + +/** + * \class Noise_Pipes_25519_ChaChaPoly_SHA256 Noise_Pipes_25519_ChaChaPoly_SHA256.h + * \brief Noise Pipes descriptor, using Curve25519, ChaChaPoly, and SHA256. + * + * Noise Pipes combines the effect of XX, IK, and XXfallback to produce a + * protocol that requires only two handshake messages if the responder's + * static public key is known, or three handshake messages if the key + * is unknown or incorrect. + */ + +Noise_Pipes_25519_ChaChaPoly_SHA256::Noise_Pipes_25519_ChaChaPoly_SHA256() +{ +} + +Noise_Pipes_25519_ChaChaPoly_SHA256::~Noise_Pipes_25519_ChaChaPoly_SHA256() +{ +} + +const NoiseProtocolDescriptor *Noise_Pipes_25519_ChaChaPoly_SHA256::abbreviatedDescriptor() const +{ + return &ik; +} + +const NoiseProtocolDescriptor *Noise_Pipes_25519_ChaChaPoly_SHA256::fallbackDescriptor() const +{ + return &fallback; +} diff --git a/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_SHA256.h b/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_SHA256.h new file mode 100644 index 00000000..69b62e1c --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_Pipes_25519_ChaChaPoly_SHA256.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_PIPES_25519_CHACHAPOLY_SHA256_h +#define NOISE_PIPES_25519_CHACHAPOLY_SHA256_h + +#include "Noise_XX_25519_ChaChaPoly_SHA256.h" +#include "Noise_IK_25519_ChaChaPoly_SHA256.h" +#include "Noise_XXfallback_25519_ChaChaPoly_SHA256.h" + +class Noise_Pipes_25519_ChaChaPoly_SHA256 : + public Noise_XX_25519_ChaChaPoly_SHA256 +{ +public: + Noise_Pipes_25519_ChaChaPoly_SHA256(); + virtual ~Noise_Pipes_25519_ChaChaPoly_SHA256(); + + const NoiseProtocolDescriptor *abbreviatedDescriptor() const; + const NoiseProtocolDescriptor *fallbackDescriptor() const; + +private: + Noise_IK_25519_ChaChaPoly_SHA256 ik; + Noise_XXfallback_25519_ChaChaPoly_SHA256 fallback; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_XX.cpp b/libraries/NoiseProtocol/src/Noise_XX.cpp new file mode 100644 index 00000000..86809680 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XX.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_XX.h" + +/** + * \class NoiseHandshakeState_XX Noise_XX.h + * \brief Handshake implementation of the Noise "XX" pattern. + * + * The "XX" pattern provides mutual authentication of the two communicating + * parties, with the identifying keys for the parties exchanged during + * the handshake. + * + * This class provides the core "XX" functionality. Subclasses provide + * implementations of "XX" that use specific algorithms, such as + * Noise_XX_25519_ChaChaPoly_BLAKE2s. + */ + +/** + * \fn NoiseHandshakeState_XX::NoiseHandshakeState_XX() + * \brief Constructs a new Noise handshake that uses the XX pattern. + */ + +/** + * \brief Destroys this Noise handshake. + */ +NoiseHandshakeState_XX::~NoiseHandshakeState_XX() +{ +} + +void NoiseHandshakeState_XX::removeKeys() +{ + // Remote static key is expected to be discovered during the XX handshake. + // Local static key is preserved because we will eventually need to + // send it to the remote party during the XX handshake. + removeParameter(Noise::RemoteStaticPublicKey); + + // Base class implementation removes the ephemeral keys. + NoiseHandshakeState::removeKeys(); +} + +void NoiseHandshakeState_XX::writeTokens + (NoiseHandshakeState::Packet &packet, uint8_t msgnum) +{ + if (msgnum == 0) { + write_e(packet); + } else if (msgnum == 1) { + write_e(packet); + write_ee(packet); + write_s(packet); + write_es(packet); + } else if (msgnum == 2) { + write_s(packet); + write_se(packet); + packet.done = true; + } +} + +void NoiseHandshakeState_XX::readTokens + (NoiseHandshakeState::Packet &packet, uint8_t msgnum) +{ + if (msgnum == 0) { + read_e(packet); + } else if (msgnum == 1) { + read_e(packet); + read_ee(packet); + read_s(packet); + read_es(packet); + } else if (msgnum == 2) { + read_s(packet); + read_se(packet); + packet.done = true; + } +} diff --git a/libraries/NoiseProtocol/src/Noise_XX.h b/libraries/NoiseProtocol/src/Noise_XX.h new file mode 100644 index 00000000..74112ea9 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XX.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_XX_h +#define NOISE_XX_h + +#include "NoiseHandshakeState.h" + +class NoiseHandshakeState_XX : public NoiseHandshakeState +{ +public: + virtual ~NoiseHandshakeState_XX(); + +protected: + NoiseHandshakeState_XX() {} + + void removeKeys(); + void writeTokens(NoiseHandshakeState::Packet &packet, uint8_t msgnum); + void readTokens(NoiseHandshakeState::Packet &packet, uint8_t msgnum); +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_XX_25519_AESGCM_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_XX_25519_AESGCM_SHA256.cpp new file mode 100644 index 00000000..ab34d1a7 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XX_25519_AESGCM_SHA256.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_XX_25519_AESGCM_SHA256.h" + +/** + * \class NoiseHandshakeState_XX_25519_AESGCM_SHA256 Noise_XX_25519_AESGCM_SHA256.h + * \brief "XX" Noise handshake, using Curve25519, AES256, GCM, and SHA256. + */ + +/** + * \class Noise_XX_25519_AESGCM_SHA256 Noise_XX_25519_AESGCM_SHA256.h + * \brief "XX" Noise descriptor, using Curve25519, AES256, GCM, and SHA256. + */ + +static char const Noise_XX_25519_AESGCM_SHA256_Name[] = + "Noise_XX_25519_AESGCM_SHA256"; + +NoiseHandshakeState_XX_25519_AESGCM_SHA256::NoiseHandshakeState_XX_25519_AESGCM_SHA256() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_XX_25519_AESGCM_SHA256_Name); +} + +NoiseHandshakeState_XX_25519_AESGCM_SHA256::~NoiseHandshakeState_XX_25519_AESGCM_SHA256() +{ +} + +Noise_XX_25519_AESGCM_SHA256::Noise_XX_25519_AESGCM_SHA256() + : NoiseProtocolDescriptor(Noise_XX_25519_AESGCM_SHA256_Name, "1") +{ +} + +Noise_XX_25519_AESGCM_SHA256::~Noise_XX_25519_AESGCM_SHA256() +{ +} + +NoiseHandshakeState *Noise_XX_25519_AESGCM_SHA256::createHandshake() const +{ + return new NoiseHandshakeState_XX_25519_AESGCM_SHA256(); +} diff --git a/libraries/NoiseProtocol/src/Noise_XX_25519_AESGCM_SHA256.h b/libraries/NoiseProtocol/src/Noise_XX_25519_AESGCM_SHA256.h new file mode 100644 index 00000000..67042945 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XX_25519_AESGCM_SHA256.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_XX_25519_AESGCM_SHA256_h +#define NOISE_XX_25519_AESGCM_SHA256_h + +#include "Noise_XX.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_AESGCM_SHA256.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_XX_25519_AESGCM_SHA256 : public NoiseHandshakeState_XX +{ +public: + NoiseHandshakeState_XX_25519_AESGCM_SHA256(); + virtual ~NoiseHandshakeState_XX_25519_AESGCM_SHA256(); + +private: + NoiseSymmetricState_AESGCM_SHA256 sym; + NoiseDHState_Curve25519 dh; +}; + +class Noise_XX_25519_AESGCM_SHA256 : public NoiseProtocolDescriptor +{ +public: + Noise_XX_25519_AESGCM_SHA256(); + virtual ~Noise_XX_25519_AESGCM_SHA256(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_BLAKE2s.cpp b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_BLAKE2s.cpp new file mode 100644 index 00000000..c18a8c2e --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_BLAKE2s.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_XX_25519_ChaChaPoly_BLAKE2s.h" + +/** + * \class NoiseHandshakeState_XX_25519_ChaChaPoly_BLAKE2s Noise_XX_25519_ChaChaPoly_BLAKE2s.h + * \brief "XX" Noise handshake, using Curve25519, ChaChaPoly, and BLAKE2s. + */ + +/** + * \class Noise_XX_25519_ChaChaPoly_BLAKE2s Noise_XX_25519_ChaChaPoly_BLAKE2s.h + * \brief "XX" Noise descriptor, using Curve25519, ChaChaPoly, and BLAKE2s. + */ + +static char const Noise_XX_25519_ChaChaPoly_BLAKE2s_Name[] = + "Noise_XX_25519_ChaChaPoly_BLAKE2s"; + +NoiseHandshakeState_XX_25519_ChaChaPoly_BLAKE2s::NoiseHandshakeState_XX_25519_ChaChaPoly_BLAKE2s() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_XX_25519_ChaChaPoly_BLAKE2s_Name); +} + +NoiseHandshakeState_XX_25519_ChaChaPoly_BLAKE2s::~NoiseHandshakeState_XX_25519_ChaChaPoly_BLAKE2s() +{ +} + +Noise_XX_25519_ChaChaPoly_BLAKE2s::Noise_XX_25519_ChaChaPoly_BLAKE2s() + : NoiseProtocolDescriptor(Noise_XX_25519_ChaChaPoly_BLAKE2s_Name, "3") +{ +} + +Noise_XX_25519_ChaChaPoly_BLAKE2s::~Noise_XX_25519_ChaChaPoly_BLAKE2s() +{ +} + +NoiseHandshakeState *Noise_XX_25519_ChaChaPoly_BLAKE2s::createHandshake() const +{ + return new NoiseHandshakeState_XX_25519_ChaChaPoly_BLAKE2s(); +} diff --git a/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_BLAKE2s.h b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_BLAKE2s.h new file mode 100644 index 00000000..a3a1af11 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_BLAKE2s.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_XX_25519_CHACHAPOLY_BLAKE2S_h +#define NOISE_XX_25519_CHACHAPOLY_BLAKE2S_h + +#include "Noise_XX.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_ChaChaPoly_BLAKE2s.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_XX_25519_ChaChaPoly_BLAKE2s + : public NoiseHandshakeState_XX +{ +public: + NoiseHandshakeState_XX_25519_ChaChaPoly_BLAKE2s(); + virtual ~NoiseHandshakeState_XX_25519_ChaChaPoly_BLAKE2s(); + +private: + NoiseSymmetricState_ChaChaPoly_BLAKE2s sym; + NoiseDHState_Curve25519 dh; +}; + +class Noise_XX_25519_ChaChaPoly_BLAKE2s : public NoiseProtocolDescriptor +{ +public: + Noise_XX_25519_ChaChaPoly_BLAKE2s(); + virtual ~Noise_XX_25519_ChaChaPoly_BLAKE2s(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_SHA256.cpp new file mode 100644 index 00000000..d3e7af32 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_SHA256.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_XX_25519_ChaChaPoly_SHA256.h" + +/** + * \class NoiseHandshakeState_XX_25519_ChaChaPoly_SHA256 Noise_XX_25519_ChaChaPoly_SHA256.h + * \brief "XX" Noise handshake, using Curve25519, ChaChaPoly, and SHA256. + */ + +/** + * \class Noise_XX_25519_ChaChaPoly_SHA256 Noise_XX_25519_ChaChaPoly_SHA256.h + * \brief "XX" Noise descriptor, using Curve25519, ChaChaPoly, and SHA256. + */ + +static char const Noise_XX_25519_ChaChaPoly_SHA256_Name[] = + "Noise_XX_25519_ChaChaPoly_SHA256"; + +NoiseHandshakeState_XX_25519_ChaChaPoly_SHA256::NoiseHandshakeState_XX_25519_ChaChaPoly_SHA256() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_XX_25519_ChaChaPoly_SHA256_Name); +} + +NoiseHandshakeState_XX_25519_ChaChaPoly_SHA256::~NoiseHandshakeState_XX_25519_ChaChaPoly_SHA256() +{ +} + +Noise_XX_25519_ChaChaPoly_SHA256::Noise_XX_25519_ChaChaPoly_SHA256() + : NoiseProtocolDescriptor(Noise_XX_25519_ChaChaPoly_SHA256_Name, "2") +{ +} + +Noise_XX_25519_ChaChaPoly_SHA256::~Noise_XX_25519_ChaChaPoly_SHA256() +{ +} + +NoiseHandshakeState *Noise_XX_25519_ChaChaPoly_SHA256::createHandshake() const +{ + return new NoiseHandshakeState_XX_25519_ChaChaPoly_SHA256(); +} diff --git a/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_SHA256.h b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_SHA256.h new file mode 100644 index 00000000..5ab73adf --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XX_25519_ChaChaPoly_SHA256.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_XX_25519_CHACHAPOLY_SHA256_h +#define NOISE_XX_25519_CHACHAPOLY_SHA256_h + +#include "Noise_XX.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_ChaChaPoly_SHA256.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_XX_25519_ChaChaPoly_SHA256 + : public NoiseHandshakeState_XX +{ +public: + NoiseHandshakeState_XX_25519_ChaChaPoly_SHA256(); + virtual ~NoiseHandshakeState_XX_25519_ChaChaPoly_SHA256(); + +private: + NoiseSymmetricState_ChaChaPoly_SHA256 sym; + NoiseDHState_Curve25519 dh; +}; + +class Noise_XX_25519_ChaChaPoly_SHA256 : public NoiseProtocolDescriptor +{ +public: + Noise_XX_25519_ChaChaPoly_SHA256(); + virtual ~Noise_XX_25519_ChaChaPoly_SHA256(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_XXfallback.cpp b/libraries/NoiseProtocol/src/Noise_XXfallback.cpp new file mode 100644 index 00000000..56f27f40 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XXfallback.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_XXfallback.h" + +/** + * \class NoiseHandshakeState_XXfallback Noise_XXfallback.h + * \brief Handshake implementation of the Noise "XXfallback" pattern. + * + * The "XXfallback" pattern provides mutual authentication of the two + * communicating parties after a previous "IK" handshake has failed. + * The application should use startFallback() instead of start() to + * start the new handshake. + * + * This class provides the core "XXfallback" functionality. Subclasses provide + * implementations of "XXfallback" that use specific algorithms, such as + * Noise_XXfallback_25519_ChaChaPoly_BLAKE2s. + */ + +/** + * \fn NoiseHandshakeState_XXfallback::NoiseHandshakeState_XXfallback() + * \brief Constructs a new Noise handshake that uses the XXfallback pattern. + */ + +/** + * \brief Destroys this Noise handshake. + */ +NoiseHandshakeState_XXfallback::~NoiseHandshakeState_XXfallback() +{ +} + +bool NoiseHandshakeState_XXfallback::startFallback + (const NoiseHandshakeState *fallbackFrom, Noise::Party party, + const void *prologue, size_t prologueLen) +{ + // Cannot fallback if no previous handshake, or fall back from ourselves. + if (!fallbackFrom || fallbackFrom == this) { + setState(Noise::Failed); + return false; + } + NoiseDHState *thisDH = dhState(); + + // Copy keys from the previous handshake into this one. + const NoiseDHState *otherDH = otherDHState(fallbackFrom); + if (!thisDH || !otherDH || !thisDH->fallback(party, otherDH)) { + setState(Noise::Failed); + return false; + } + + // Start the new handshake. + start(party, prologue, prologueLen); + + // Hash the initiator's ephemeral public key from the pre-message. + if (party == Noise::Initiator) + thisDH->hashPublicKey(symmetricState(), Noise::LocalEphemPublicKey); + else + thisDH->hashPublicKey(symmetricState(), Noise::RemoteEphemPublicKey); + + // The responder writes first in a XXfallback handshake. + setState(party == Noise::Initiator ? Noise::Read : Noise::Write); + return true; +} + +void NoiseHandshakeState_XXfallback::removeKeys() +{ + // Remove the remote static public key only. We need to keep the + // ephemeral keys to perform the fallback correctly. + removeParameter(Noise::RemoteStaticPublicKey); +} + +void NoiseHandshakeState_XXfallback::writeTokens + (NoiseHandshakeState::Packet &packet, uint8_t msgnum) +{ + if (msgnum == 0) { + write_e(packet); + write_ee(packet); + write_s(packet); + write_es(packet); + } else if (msgnum == 1) { + write_s(packet); + write_se(packet); + packet.done = true; + } +} + +void NoiseHandshakeState_XXfallback::readTokens + (NoiseHandshakeState::Packet &packet, uint8_t msgnum) +{ + if (msgnum == 0) { + read_e(packet); + read_ee(packet); + read_s(packet); + read_es(packet); + } else if (msgnum == 1) { + read_s(packet); + read_se(packet); + packet.done = true; + } +} diff --git a/libraries/NoiseProtocol/src/Noise_XXfallback.h b/libraries/NoiseProtocol/src/Noise_XXfallback.h new file mode 100644 index 00000000..9174a2d6 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XXfallback.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_XX_FALLBACK_h +#define NOISE_XX_FALLBACK_h + +#include "NoiseHandshakeState.h" + +class NoiseHandshakeState_XXfallback : public NoiseHandshakeState +{ +public: + virtual ~NoiseHandshakeState_XXfallback(); + + bool startFallback + (const NoiseHandshakeState *fallbackFrom, Noise::Party party, + const void *prologue, size_t prologueLen); + +protected: + NoiseHandshakeState_XXfallback() {} + + void removeKeys(); + void writeTokens(NoiseHandshakeState::Packet &packet, uint8_t msgnum); + void readTokens(NoiseHandshakeState::Packet &packet, uint8_t msgnum); +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_XXfallback_25519_AESGCM_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_AESGCM_SHA256.cpp new file mode 100644 index 00000000..9e2ec779 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_AESGCM_SHA256.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_XXfallback_25519_AESGCM_SHA256.h" + +/** + * \class NoiseHandshakeState_XXfallback_25519_AESGCM_SHA256 Noise_XXfallback_25519_AESGCM_SHA256.h + * \brief "XXfallback" Noise handshake, using Curve25519, AES256, GCM, and SHA256. + */ + +/** + * \class Noise_XXfallback_25519_AESGCM_SHA256 Noise_XXfallback_25519_AESGCM_SHA256.h + * \brief "XXfallback" Noise descriptor, using Curve25519, AES256, GCM, and SHA256. + */ + +static char const Noise_XXfallback_25519_AESGCM_SHA256_Name[] = + "Noise_XXfallback_25519_AESGCM_SHA256"; + +NoiseHandshakeState_XXfallback_25519_AESGCM_SHA256::NoiseHandshakeState_XXfallback_25519_AESGCM_SHA256() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_XXfallback_25519_AESGCM_SHA256_Name); +} + +NoiseHandshakeState_XXfallback_25519_AESGCM_SHA256::~NoiseHandshakeState_XXfallback_25519_AESGCM_SHA256() +{ +} + +Noise_XXfallback_25519_AESGCM_SHA256::Noise_XXfallback_25519_AESGCM_SHA256() + : NoiseProtocolDescriptor(Noise_XXfallback_25519_AESGCM_SHA256_Name) +{ +} + +Noise_XXfallback_25519_AESGCM_SHA256::~Noise_XXfallback_25519_AESGCM_SHA256() +{ +} + +NoiseHandshakeState *Noise_XXfallback_25519_AESGCM_SHA256::createHandshake() const +{ + return new NoiseHandshakeState_XXfallback_25519_AESGCM_SHA256(); +} diff --git a/libraries/NoiseProtocol/src/Noise_XXfallback_25519_AESGCM_SHA256.h b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_AESGCM_SHA256.h new file mode 100644 index 00000000..01c58338 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_AESGCM_SHA256.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_XX_FALLBACK_25519_AESGCM_SHA256_h +#define NOISE_XX_FALLBACK_25519_AESGCM_SHA256_h + +#include "Noise_XXfallback.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_AESGCM_SHA256.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_XXfallback_25519_AESGCM_SHA256 : public NoiseHandshakeState_XXfallback +{ +public: + NoiseHandshakeState_XXfallback_25519_AESGCM_SHA256(); + virtual ~NoiseHandshakeState_XXfallback_25519_AESGCM_SHA256(); + +private: + NoiseSymmetricState_AESGCM_SHA256 sym; + NoiseDHState_Curve25519 dh; +}; + +class Noise_XXfallback_25519_AESGCM_SHA256 : public NoiseProtocolDescriptor +{ +public: + Noise_XXfallback_25519_AESGCM_SHA256(); + virtual ~Noise_XXfallback_25519_AESGCM_SHA256(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.cpp b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.cpp new file mode 100644 index 00000000..4569d638 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.h" + +/** + * \class NoiseHandshakeState_XXfallback_25519_ChaChaPoly_BLAKE2s Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.h + * \brief "XXfallback" Noise handshake, using Curve25519, ChaChaPoly, and BLAKE2s. + */ + +/** + * \class Noise_XXfallback_25519_ChaChaPoly_BLAKE2s Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.h + * \brief "XXfallback" Noise descriptor, using Curve25519, ChaChaPoly, and BLAKE2s. + */ + +static char const Noise_XXfallback_25519_ChaChaPoly_BLAKE2s_Name[] = + "Noise_XXfallback_25519_ChaChaPoly_BLAKE2s"; + +NoiseHandshakeState_XXfallback_25519_ChaChaPoly_BLAKE2s::NoiseHandshakeState_XXfallback_25519_ChaChaPoly_BLAKE2s() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_XXfallback_25519_ChaChaPoly_BLAKE2s_Name); +} + +NoiseHandshakeState_XXfallback_25519_ChaChaPoly_BLAKE2s::~NoiseHandshakeState_XXfallback_25519_ChaChaPoly_BLAKE2s() +{ +} + +Noise_XXfallback_25519_ChaChaPoly_BLAKE2s::Noise_XXfallback_25519_ChaChaPoly_BLAKE2s() + : NoiseProtocolDescriptor(Noise_XXfallback_25519_ChaChaPoly_BLAKE2s_Name) +{ +} + +Noise_XXfallback_25519_ChaChaPoly_BLAKE2s::~Noise_XXfallback_25519_ChaChaPoly_BLAKE2s() +{ +} + +NoiseHandshakeState *Noise_XXfallback_25519_ChaChaPoly_BLAKE2s::createHandshake() const +{ + return new NoiseHandshakeState_XXfallback_25519_ChaChaPoly_BLAKE2s(); +} diff --git a/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.h b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.h new file mode 100644 index 00000000..dec64eb1 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_BLAKE2s.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_XX_FALLBACK_25519_CHACHAPOLY_BLAKE2S_h +#define NOISE_XX_FALLBACK_25519_CHACHAPOLY_BLAKE2S_h + +#include "Noise_XXfallback.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_ChaChaPoly_BLAKE2s.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_XXfallback_25519_ChaChaPoly_BLAKE2s + : public NoiseHandshakeState_XXfallback +{ +public: + NoiseHandshakeState_XXfallback_25519_ChaChaPoly_BLAKE2s(); + virtual ~NoiseHandshakeState_XXfallback_25519_ChaChaPoly_BLAKE2s(); + +private: + NoiseSymmetricState_ChaChaPoly_BLAKE2s sym; + NoiseDHState_Curve25519 dh; +}; + +class Noise_XXfallback_25519_ChaChaPoly_BLAKE2s : public NoiseProtocolDescriptor +{ +public: + Noise_XXfallback_25519_ChaChaPoly_BLAKE2s(); + virtual ~Noise_XXfallback_25519_ChaChaPoly_BLAKE2s(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif diff --git a/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_SHA256.cpp b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_SHA256.cpp new file mode 100644 index 00000000..df959a91 --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_SHA256.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Noise_XXfallback_25519_ChaChaPoly_SHA256.h" + +/** + * \class NoiseHandshakeState_XXfallback_25519_ChaChaPoly_SHA256 Noise_XXfallback_25519_ChaChaPoly_SHA256.h + * \brief "XXfallback" Noise handshake, using Curve25519, ChaChaPoly, and SHA256. + */ + +/** + * \class Noise_XXfallback_25519_ChaChaPoly_SHA256 Noise_XXfallback_25519_ChaChaPoly_SHA256.h + * \brief "XXfallback" Noise descriptor, using Curve25519, ChaChaPoly, and SHA256. + */ + +static char const Noise_XXfallback_25519_ChaChaPoly_SHA256_Name[] = + "Noise_XXfallback_25519_ChaChaPoly_SHA256"; + +NoiseHandshakeState_XXfallback_25519_ChaChaPoly_SHA256::NoiseHandshakeState_XXfallback_25519_ChaChaPoly_SHA256() +{ + setSymmetricState(&sym); + setDHState(&dh); + setProtocolName(Noise_XXfallback_25519_ChaChaPoly_SHA256_Name); +} + +NoiseHandshakeState_XXfallback_25519_ChaChaPoly_SHA256::~NoiseHandshakeState_XXfallback_25519_ChaChaPoly_SHA256() +{ +} + +Noise_XXfallback_25519_ChaChaPoly_SHA256::Noise_XXfallback_25519_ChaChaPoly_SHA256() + : NoiseProtocolDescriptor(Noise_XXfallback_25519_ChaChaPoly_SHA256_Name) +{ +} + +Noise_XXfallback_25519_ChaChaPoly_SHA256::~Noise_XXfallback_25519_ChaChaPoly_SHA256() +{ +} + +NoiseHandshakeState *Noise_XXfallback_25519_ChaChaPoly_SHA256::createHandshake() const +{ + return new NoiseHandshakeState_XXfallback_25519_ChaChaPoly_SHA256(); +} diff --git a/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_SHA256.h b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_SHA256.h new file mode 100644 index 00000000..3d942bbf --- /dev/null +++ b/libraries/NoiseProtocol/src/Noise_XXfallback_25519_ChaChaPoly_SHA256.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOISE_XX_FALLBACK_25519_CHACHAPOLY_SHA256_h +#define NOISE_XX_FALLBACK_25519_CHACHAPOLY_SHA256_h + +#include "Noise_XXfallback.h" +#include "NoiseProtocolDescriptor.h" +#include "NoiseSymmetricState_ChaChaPoly_SHA256.h" +#include "NoiseDHState_Curve25519.h" + +class NoiseHandshakeState_XXfallback_25519_ChaChaPoly_SHA256 + : public NoiseHandshakeState_XXfallback +{ +public: + NoiseHandshakeState_XXfallback_25519_ChaChaPoly_SHA256(); + virtual ~NoiseHandshakeState_XXfallback_25519_ChaChaPoly_SHA256(); + +private: + NoiseSymmetricState_ChaChaPoly_SHA256 sym; + NoiseDHState_Curve25519 dh; +}; + +class Noise_XXfallback_25519_ChaChaPoly_SHA256 : public NoiseProtocolDescriptor +{ +public: + Noise_XXfallback_25519_ChaChaPoly_SHA256(); + virtual ~Noise_XXfallback_25519_ChaChaPoly_SHA256(); + + NoiseHandshakeState *createHandshake() const; +}; + +#endif