diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/common/Cryptography/Ed25519.cpp | 156 | ||||
-rw-r--r-- | src/common/Cryptography/Ed25519.h | 69 |
3 files changed, 227 insertions, 1 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 5258258a7c6..6b674e9dd24 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -72,7 +72,8 @@ target_link_libraries(common openssl valgrind threads - jemalloc) + jemalloc + openssl_ed25519) add_dependencies(common revision_data.h) diff --git a/src/common/Cryptography/Ed25519.cpp b/src/common/Cryptography/Ed25519.cpp new file mode 100644 index 00000000000..bbe053fa3b2 --- /dev/null +++ b/src/common/Cryptography/Ed25519.cpp @@ -0,0 +1,156 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Ed25519.h" +#include "CryptoHash.h" +#include "Memory.h" +#include <ed25519/ed25519.h> +#include <openssl/pem.h> +#include <algorithm> +#include <memory> +#include <vector> + +namespace Trinity::Crypto +{ +Ed25519::Ed25519() +{ +} + +Ed25519::Ed25519(Ed25519 const& right) +{ + *this = right; +} + +Ed25519::Ed25519(Ed25519&& right) noexcept +{ + *this = std::move(right); +} + +Ed25519::~Ed25519() +{ + EVP_PKEY_free(_key); +} + +Ed25519& Ed25519::operator=(Ed25519 const& right) +{ + if (this == &right) + return *this; + + _key = right._key; // EVP_PKEY uses reference counting internally, just copy the pointer + EVP_PKEY_up_ref(_key); // Bump reference count for PKEY, as every instance of this class holds two references to PKEY and destructor decrements it twice + return *this; +} + +Ed25519& Ed25519::operator=(Ed25519&& right) noexcept +{ + if (this == &right) + return *this; + + _key = std::exchange(right._key, EVP_PKEY_new()); + return *this; +} + +bool Ed25519::LoadFromFile(std::string const& fileName) +{ + if (_key) + { + EVP_PKEY_free(_key); + _key = nullptr; + } + + auto keyBIO = make_unique_ptr_with_deleter(BIO_new_file(fileName.c_str(), "r"), BIO_free); + if (!keyBIO) + return false; + + _key = EVP_PKEY_new(); + if (!PEM_read_bio_PrivateKey(keyBIO.get(), &_key, nullptr, nullptr)) + return false; + + return true; +} + +bool Ed25519::LoadFromString(std::string const& keyPem) +{ + if (_key) + { + EVP_PKEY_free(_key); + _key = nullptr; + } + + auto keyBIO = make_unique_ptr_with_deleter(BIO_new_mem_buf( + const_cast<char*>(keyPem.c_str()) /*api hack - this function assumes memory is readonly but lacks const modifier*/, + keyPem.length() + 1), BIO_free); + if (!keyBIO) + return false; + + _key = EVP_PKEY_new(); + if (!PEM_read_bio_PrivateKey(keyBIO.get(), &_key, nullptr, nullptr)) + return false; + + return true; +} + +bool Ed25519::LoadFromByteArray(std::array<uint8, 32> const& keyBytes) +{ + if (_key) + { + EVP_PKEY_free(_key); + _key = nullptr; + } + + _key = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, nullptr, keyBytes.data(), keyBytes.size()); + if (!_key) + return false; + + return true; +} + +bool Ed25519::Sign(uint8 const* message, std::size_t messageLength, std::vector<uint8>& output) +{ + constexpr size_t KeySize = 32; + + uint8 publicKey[KeySize] = {}; + std::size_t keyLength = KeySize; + EVP_PKEY_get_raw_public_key(_key, publicKey, &keyLength); + + uint8 privateKey[KeySize] = {}; + keyLength = KeySize; + EVP_PKEY_get_raw_private_key(_key, privateKey, &keyLength); + + output.resize(64); + int result = ED25519_sign(output.data(), message, messageLength, publicKey, privateKey); + std::reverse(output.begin(), output.end()); + return result != 0; +} + +bool Ed25519::SignWithContext(uint8 const* message, std::size_t messageLength, std::vector<uint8> const& context, std::vector<uint8>& output) +{ + constexpr size_t KeySize = 32; + + uint8 publicKey[KeySize] = {}; + std::size_t keyLength = KeySize; + EVP_PKEY_get_raw_public_key(_key, publicKey, &keyLength); + + uint8 privateKey[KeySize] = {}; + keyLength = KeySize; + EVP_PKEY_get_raw_private_key(_key, privateKey, &keyLength); + + output.resize(64); + int result = ED25519_sign_ctx(output.data(), message, messageLength, publicKey, privateKey, context.data(), context.size()); + return result != 0; +} +} diff --git a/src/common/Cryptography/Ed25519.h b/src/common/Cryptography/Ed25519.h new file mode 100644 index 00000000000..7d7f56bb905 --- /dev/null +++ b/src/common/Cryptography/Ed25519.h @@ -0,0 +1,69 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITYCORE_ED25519_H +#define TRINITYCORE_ED25519_H + +#include "Define.h" +#include <array> +#include <string> +#include <vector> +#include <openssl/evp.h> + +class BigNumber; + +namespace Trinity::Crypto +{ +class TC_COMMON_API Ed25519 +{ +public: + Ed25519(); + Ed25519(Ed25519 const& other); + Ed25519(Ed25519&& other) noexcept; + ~Ed25519(); + + Ed25519& operator=(Ed25519 const& right); + Ed25519& operator=(Ed25519&& right) noexcept; + + bool LoadFromFile(std::string const& fileName); + + bool LoadFromString(std::string const& keyPem); + + bool LoadFromByteArray(std::array<uint8, 32> const& keyBytes); + + template <std::size_t N> + bool Sign(std::array<uint8, N> const& message, std::vector<uint8>& output) + { + return this->Sign(message.data(), message.size(), output); + } + + bool Sign(uint8 const* message, std::size_t messageLength, std::vector<uint8>& output); + + template <std::size_t N> + bool SignWithContext(std::array<uint8, N> const& message, std::vector<uint8> const& context, std::vector<uint8>& output) + { + return this->SignWithContext(message.data(), message.size(), context, output); + } + + bool SignWithContext(uint8 const* message, std::size_t messageLength, std::vector<uint8> const& context, std::vector<uint8>& output); + +private: + EVP_PKEY* _key = nullptr; +}; +} + +#endif // TRINITYCORE_ED25519_H |