OpenRCT2/src/openrct2/network/NetworkKey.cpp

227 lines
5.2 KiB
C++
Raw Normal View History

2016-05-05 21:46:13 +02:00
/*****************************************************************************
2020-07-21 15:04:34 +02:00
* Copyright (c) 2014-2020 OpenRCT2 developers
2016-05-05 21:46:13 +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
*
* 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-07-21 16:17:06 +02:00
# include "NetworkKey.h"
2018-06-22 23:02:47 +02:00
2018-07-21 16:17:06 +02:00
# include "../Diagnostic.h"
# include "../core/Crypt.h"
# include "../core/IStream.hpp"
2016-05-05 21:46:13 +02:00
2018-07-21 16:17:06 +02:00
# include <vector>
2018-06-22 23:02:47 +02:00
NetworkKey::NetworkKey()
{
}
NetworkKey::~NetworkKey()
{
}
2016-05-05 21:46:13 +02:00
void NetworkKey::Unload()
{
_key = nullptr;
2016-05-05 21:46:13 +02:00
}
bool NetworkKey::Generate()
{
try
2016-05-21 00:00:23 +02:00
{
_key = Crypt::CreateRSAKey();
_key->Generate();
return true;
2016-05-19 10:23:42 +02:00
}
catch (const std::exception& e)
2016-05-21 00:00:23 +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
}
bool NetworkKey::LoadPrivate(OpenRCT2::IStream* stream)
2016-05-05 21:46:13 +02:00
{
2017-02-08 13:53:00 +01:00
Guard::ArgumentNotNull(stream);
size_t size = static_cast<size_t>(stream->GetLength());
if (size == static_cast<size_t>(-1))
2016-05-25 10:18:26 +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;
}
std::string pem(size, '\0');
stream->Read(pem.data(), pem.size());
try
2016-05-21 00:00:23 +02:00
{
_key = Crypt::CreateRSAKey();
_key->SetPrivate(pem);
return true;
2016-05-05 21:46:13 +02:00
}
catch (const std::exception& e)
2016-05-21 00:00:23 +02:00
{
log_error("NetworkKey::LoadPrivate failed: %s", e.what());
2016-05-05 21:46:13 +02:00
return false;
}
}
bool NetworkKey::LoadPublic(OpenRCT2::IStream* stream)
2016-05-05 21:46:13 +02:00
{
2017-02-08 13:53:00 +01:00
Guard::ArgumentNotNull(stream);
size_t size = static_cast<size_t>(stream->GetLength());
if (size == static_cast<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;
}
std::string pem(size, '\0');
stream->Read(pem.data(), pem.size());
try
2016-05-25 10:18:26 +02:00
{
_key = Crypt::CreateRSAKey();
_key->SetPublic(pem);
return true;
2016-05-05 21:46:13 +02:00
}
catch (const std::exception& e)
2016-05-21 00:00:23 +02:00
{
log_error("NetworkKey::LoadPublic failed: %s", e.what());
return false;
2016-05-05 21:46:13 +02:00
}
}
bool NetworkKey::SavePrivate(OpenRCT2::IStream* stream)
2016-05-05 21:46:13 +02:00
{
try
2016-05-21 00:00:23 +02:00
{
if (_key == nullptr)
{
2018-06-01 22:08:40 +02:00
throw std::runtime_error("No key loaded");
}
auto pem = _key->GetPrivate();
stream->Write(pem.data(), pem.size());
return true;
2016-05-05 21:46:13 +02:00
}
catch (const std::exception& e)
2016-05-21 00:00:23 +02:00
{
log_error("NetworkKey::SavePrivate failed: %s", e.what());
2016-05-05 21:46:13 +02:00
return false;
}
}
bool NetworkKey::SavePublic(OpenRCT2::IStream* stream)
2016-05-05 21:46:13 +02:00
{
try
2016-05-21 00:00:23 +02:00
{
if (_key == nullptr)
{
2018-06-01 22:08:40 +02:00
throw std::runtime_error("No key loaded");
}
auto pem = _key->GetPublic();
stream->Write(pem.data(), pem.size());
return true;
2016-05-05 21:46:13 +02:00
}
catch (const std::exception& e)
2016-05-21 00:00:23 +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
}
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.
*
* 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()
{
try
{
std::string key = PublicKeyString();
if (key.empty())
{
throw std::runtime_error("No key found");
}
auto hash = Crypt::SHA1(key.c_str(), key.size());
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
}
catch (const std::exception& e)
2016-05-21 00:00:23 +02:00
{
log_error("Failed to create hash of public key: %s", e.what());
2016-05-19 10:23:42 +02:00
}
return nullptr;
2016-05-05 21:46:13 +02:00
}
bool NetworkKey::Sign(const uint8_t* md, const size_t len, std::vector<uint8_t>& signature)
2016-05-05 21:46:13 +02:00
{
try
2016-05-21 00:00:23 +02:00
{
auto rsa = Crypt::CreateRSA();
signature = rsa->SignData(*_key, md, len);
return true;
2016-05-05 21:46:13 +02:00
}
catch (const std::exception& e)
2016-05-21 00:00:23 +02:00
{
log_error("NetworkKey::Sign failed: %s", e.what());
2016-05-05 21:46:13 +02:00
return false;
}
}
bool NetworkKey::Verify(const uint8_t* md, const size_t len, const std::vector<uint8_t>& signature)
2016-05-05 21:46:13 +02:00
{
try
2016-05-21 00:00:23 +02:00
{
auto rsa = Crypt::CreateRSA();
return rsa->VerifyData(*_key, md, len, signature.data(), signature.size());
2016-05-21 00:00:23 +02:00
}
catch (const std::exception& e)
2016-05-21 00:00:23 +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