2016-05-05 21:46:13 +02:00
|
|
|
/*****************************************************************************
|
2018-06-15 14:07:34 +02:00
|
|
|
* Copyright (c) 2014-2018 OpenRCT2 developers
|
2016-05-05 21:46:13 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
2016-05-05 21:46:13 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
2016-05-05 21:46:13 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2016-05-20 11:51:31 +02:00
|
|
|
#ifndef DISABLE_NETWORK
|
|
|
|
|
2018-06-22 23:02:47 +02:00
|
|
|
#include "NetworkKey.h"
|
|
|
|
|
|
|
|
#include "../Diagnostic.h"
|
2018-05-23 21:27:00 +02:00
|
|
|
#include "../core/Crypt.h"
|
2017-02-08 13:53:00 +01:00
|
|
|
#include "../core/IStream.hpp"
|
2016-05-05 21:46:13 +02:00
|
|
|
|
2018-06-22 23:02:47 +02:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
NetworkKey::NetworkKey()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
NetworkKey::~NetworkKey()
|
|
|
|
{
|
|
|
|
}
|
2016-05-05 21:46:13 +02:00
|
|
|
|
|
|
|
void NetworkKey::Unload()
|
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
_key = nullptr;
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool NetworkKey::Generate()
|
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
try
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
_key = Crypt::CreateRSAKey();
|
|
|
|
_key->Generate();
|
|
|
|
return true;
|
2016-05-19 10:23:42 +02:00
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
catch (const std::exception& e)
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
log_error("NetworkKey::Generate failed: %s", e.what());
|
2016-05-05 21:46:13 +02:00
|
|
|
return false;
|
2016-05-21 00:00:23 +02:00
|
|
|
}
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:02:47 +02:00
|
|
|
bool NetworkKey::LoadPrivate(IStream* stream)
|
2016-05-05 21:46:13 +02:00
|
|
|
{
|
2017-02-08 13:53:00 +01:00
|
|
|
Guard::ArgumentNotNull(stream);
|
|
|
|
|
|
|
|
size_t size = (size_t)stream->GetLength();
|
2016-05-25 10:18:26 +02:00
|
|
|
if (size == (size_t)-1)
|
|
|
|
{
|
2016-05-05 21:46:13 +02:00
|
|
|
log_error("unknown size, refusing to load key");
|
|
|
|
return false;
|
2016-05-21 00:00:23 +02:00
|
|
|
}
|
|
|
|
else if (size > 4 * 1024 * 1024)
|
|
|
|
{
|
2016-05-05 21:46:13 +02:00
|
|
|
log_error("Key file suspiciously large, refusing to load it");
|
|
|
|
return false;
|
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
|
|
|
|
std::string pem(size, '\0');
|
|
|
|
stream->Read(pem.data(), pem.size());
|
|
|
|
|
|
|
|
try
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
_key = Crypt::CreateRSAKey();
|
|
|
|
_key->SetPrivate(pem);
|
|
|
|
return true;
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
catch (const std::exception& e)
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
log_error("NetworkKey::LoadPrivate failed: %s", e.what());
|
2016-05-05 21:46:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:02:47 +02:00
|
|
|
bool NetworkKey::LoadPublic(IStream* stream)
|
2016-05-05 21:46:13 +02:00
|
|
|
{
|
2017-02-08 13:53:00 +01:00
|
|
|
Guard::ArgumentNotNull(stream);
|
|
|
|
|
|
|
|
size_t size = (size_t)stream->GetLength();
|
2016-05-21 00:05:11 +02:00
|
|
|
if (size == (size_t)-1)
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2016-05-05 21:46:13 +02:00
|
|
|
log_error("unknown size, refusing to load key");
|
|
|
|
return false;
|
2016-05-21 00:00:23 +02:00
|
|
|
}
|
|
|
|
else if (size > 4 * 1024 * 1024)
|
|
|
|
{
|
2016-05-05 21:46:13 +02:00
|
|
|
log_error("Key file suspiciously large, refusing to load it");
|
|
|
|
return false;
|
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
|
|
|
|
std::string pem(size, '\0');
|
|
|
|
stream->Read(pem.data(), pem.size());
|
|
|
|
|
|
|
|
try
|
2016-05-25 10:18:26 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
_key = Crypt::CreateRSAKey();
|
|
|
|
_key->SetPublic(pem);
|
|
|
|
return true;
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
catch (const std::exception& e)
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
log_error("NetworkKey::LoadPublic failed: %s", e.what());
|
|
|
|
return false;
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:02:47 +02:00
|
|
|
bool NetworkKey::SavePrivate(IStream* stream)
|
2016-05-05 21:46:13 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
try
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
if (_key == nullptr)
|
|
|
|
{
|
2018-06-01 22:08:40 +02:00
|
|
|
throw std::runtime_error("No key loaded");
|
2018-06-01 20:17:13 +02:00
|
|
|
}
|
|
|
|
auto pem = _key->GetPrivate();
|
|
|
|
stream->Write(pem.data(), pem.size());
|
|
|
|
return true;
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
catch (const std::exception& e)
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
log_error("NetworkKey::SavePrivate failed: %s", e.what());
|
2016-05-05 21:46:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:02:47 +02:00
|
|
|
bool NetworkKey::SavePublic(IStream* stream)
|
2016-05-05 21:46:13 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
try
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
if (_key == nullptr)
|
|
|
|
{
|
2018-06-01 22:08:40 +02:00
|
|
|
throw std::runtime_error("No key loaded");
|
2018-06-01 20:17:13 +02:00
|
|
|
}
|
2018-07-18 23:11:34 +02:00
|
|
|
auto pem = _key->GetPublic();
|
2018-06-01 20:17:13 +02:00
|
|
|
stream->Write(pem.data(), pem.size());
|
|
|
|
return true;
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
catch (const std::exception& e)
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
log_error("NetworkKey::SavePublic failed: %s", e.what());
|
2016-05-05 21:46:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-19 10:23:42 +02:00
|
|
|
std::string NetworkKey::PublicKeyString()
|
2016-05-05 21:46:13 +02:00
|
|
|
{
|
2016-05-25 10:18:26 +02:00
|
|
|
if (_key == nullptr)
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 22:08:40 +02:00
|
|
|
throw std::runtime_error("No key loaded");
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
return _key->GetPublic();
|
2016-05-19 10:23:42 +02:00
|
|
|
}
|
2016-05-05 21:46:13 +02:00
|
|
|
|
2016-05-19 10:23:42 +02:00
|
|
|
/**
|
|
|
|
* @brief NetworkKey::PublicKeyHash
|
|
|
|
* Computes a short, human-readable (e.g. asciif-ied hex) hash for a given
|
|
|
|
* public key. Serves a purpose of easy identification keys in multiplayer
|
|
|
|
* overview, multiplayer settings.
|
|
|
|
*
|
2017-04-30 06:39:24 +02:00
|
|
|
* In particular, any of digest functions applied to a standardised key
|
2016-05-19 10:23:42 +02:00
|
|
|
* representation, like PEM, will be sufficient.
|
|
|
|
*
|
|
|
|
* @return returns a string containing key hash.
|
|
|
|
*/
|
|
|
|
std::string NetworkKey::PublicKeyHash()
|
|
|
|
{
|
2018-05-23 01:46:20 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
std::string key = PublicKeyString();
|
|
|
|
if (key.empty())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("No key found");
|
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
auto hash = Crypt::SHA1(key.c_str(), key.size());
|
2018-05-23 01:46:20 +02:00
|
|
|
|
|
|
|
std::string result;
|
|
|
|
result.reserve(hash.size() * 2);
|
|
|
|
for (auto b : hash)
|
|
|
|
{
|
|
|
|
char buf[3];
|
|
|
|
snprintf(buf, 3, "%02x", b);
|
|
|
|
result.append(buf);
|
|
|
|
}
|
|
|
|
return result;
|
2016-05-19 10:23:42 +02:00
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
catch (const std::exception& e)
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-05-23 01:46:20 +02:00
|
|
|
log_error("Failed to create hash of public key: %s", e.what());
|
2016-05-19 10:23:42 +02:00
|
|
|
}
|
2018-05-23 01:46:20 +02:00
|
|
|
return nullptr;
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:02:47 +02:00
|
|
|
bool NetworkKey::Sign(const uint8_t* md, const size_t len, char** signature, size_t* out_size)
|
2016-05-05 21:46:13 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
try
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
auto rsa = Crypt::CreateRSA();
|
|
|
|
auto sig = rsa->SignData(*_key, md, len);
|
|
|
|
*out_size = sig.size();
|
|
|
|
*signature = new char[sig.size()];
|
|
|
|
std::memcpy(*signature, sig.data(), sig.size());
|
|
|
|
return true;
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
catch (const std::exception& e)
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
log_error("NetworkKey::Sign failed: %s", e.what());
|
|
|
|
*signature = nullptr;
|
|
|
|
*out_size = 0;
|
2016-05-05 21:46:13 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:02:47 +02:00
|
|
|
bool NetworkKey::Verify(const uint8_t* md, const size_t len, const char* sig, const size_t siglen)
|
2016-05-05 21:46:13 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
try
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
auto rsa = Crypt::CreateRSA();
|
|
|
|
return rsa->VerifyData(*_key, md, len, sig, siglen);
|
2016-05-21 00:00:23 +02:00
|
|
|
}
|
2018-06-01 20:17:13 +02:00
|
|
|
catch (const std::exception& e)
|
2016-05-21 00:00:23 +02:00
|
|
|
{
|
2018-06-01 20:17:13 +02:00
|
|
|
log_error("NetworkKey::Verify failed: %s", e.what());
|
2016-05-19 10:23:42 +02:00
|
|
|
return false;
|
2016-05-05 21:46:13 +02:00
|
|
|
}
|
|
|
|
}
|
2016-05-20 11:51:31 +02:00
|
|
|
|
|
|
|
#endif // DISABLE_NETWORK
|