1/**
2 * The Forgotten Server - a free and open-source MMORPG server emulator
3 * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include "otpch.h"
21
22#include "rsa.h"
23
24#include <cryptopp/base64.h>
25#include <cryptopp/osrng.h>
26
27#include <fstream>
28#include <sstream>
29
30static CryptoPP::AutoSeededRandomPool prng;
31
32void RSA::decrypt(char* msg) const
33{
34 try {
35 CryptoPP::Integer m{reinterpret_cast<uint8_t*>(msg), 128};
36 auto c = pk.CalculateInverse(prng, m);
37 c.Encode(reinterpret_cast<uint8_t*>(msg), 128);
38 } catch (const CryptoPP::Exception& e) {
39 std::cout << e.what() << '\n';
40 }
41}
42
43static const std::string header = "-----BEGIN RSA PRIVATE KEY-----";
44static const std::string footer = "-----END RSA PRIVATE KEY-----";
45
46void RSA::loadPEM(const std::string& filename)
47{
48 std::ifstream file{filename};
49
50 if (!file.is_open()) {
51 throw std::runtime_error("Missing file " + filename + ".");
52 }
53
54 std::ostringstream oss;
55 for (std::string line; std::getline(file, line); oss << line);
56 std::string key = oss.str();
57
58 // fixes "Missing RSA private key footer." error
59 key.erase(0, key.find_first_not_of(" \t\f\v\n\r"));
60 key.erase(key.find_last_not_of(" \t\f\v\n\r") + 1);
61
62 if (key.substr(0, header.size()) != header) {
63 throw std::runtime_error("Missing RSA private key header.");
64 }
65
66 if (key.substr(key.size() - footer.size(), footer.size()) != footer) {
67 throw std::runtime_error("Missing RSA private key footer.");
68 }
69
70 key = key.substr(header.size(), key.size() - footer.size());
71
72 CryptoPP::ByteQueue queue;
73 CryptoPP::Base64Decoder decoder;
74 decoder.Attach(new CryptoPP::Redirector(queue));
75 decoder.Put(reinterpret_cast<const uint8_t*>(key.c_str()), key.size());
76 decoder.MessageEnd();
77
78 try {
79 pk.BERDecodePrivateKey(queue, false, queue.MaxRetrievable());
80
81 if (!pk.Validate(prng, 3)) {
82 throw std::runtime_error("RSA private key is not valid.");
83 }
84 } catch (const CryptoPP::Exception& e) {
85 std::cout << e.what() << '\n';
86 }
87}
88