SuperTuxKart
Loading...
Searching...
No Matches
crypto_openssl.hpp
1//
2// SuperTuxKart - a fun racing game with go-kart
3// Copyright (C) 2018 SuperTuxKart-Team
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License
7// as published by the Free Software Foundation; either version 3
8// of the License, or (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
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19#ifdef ENABLE_CRYPTO_OPENSSL
20
21#ifndef HEADER_CRYPTO_OPENSSL_HPP
22#define HEADER_CRYPTO_OPENSSL_HPP
23
24#include "utils/log.hpp"
25
26#include <enet/enet.h>
27
28#define OPENSSL_API_COMPAT 0x09800000L
29#include <openssl/evp.h>
30#include <openssl/rand.h>
31
32#include <algorithm>
33#include <array>
34#include <cassert>
35#include <memory>
36#include <mutex>
37#include <random>
38#include <string>
39#include <vector>
40
42class NetworkString;
43
44class Crypto
45{
46private:
47 static std::string m_client_key;
48
49 static std::string m_client_iv;
50
51 std::array<uint8_t, 12> m_iv;
52
53 uint32_t m_packet_counter;
54
55 EVP_CIPHER_CTX* m_encrypt;
56
57 EVP_CIPHER_CTX* m_decrypt;
58
59 std::mutex m_crypto_mutex;
60
61 // ------------------------------------------------------------------------
62 static size_t calcDecodeLength(const std::string& input)
63 {
64 // Calculates the length of a decoded string
65 size_t padding = 0;
66 const size_t len = input.size();
67 if (input[len - 1] == '=' && input[len - 2] == '=')
68 {
69 // last two chars are =
70 padding = 2;
71 }
72 else if (input[len - 1] == '=')
73 {
74 // last char is =
75 padding = 1;
76 }
77 return (len * 3) / 4 - padding;
78 } // calcDecodeLength
79public:
80 // ------------------------------------------------------------------------
81 static std::string base64(const std::vector<uint8_t>& input);
82 // ------------------------------------------------------------------------
83 static std::vector<uint8_t> decode64(std::string input);
84 // ------------------------------------------------------------------------
85 static std::array<uint8_t, 32> sha256(const std::string& input);
86 // ------------------------------------------------------------------------
87 static std::unique_ptr<Crypto> getClientCrypto()
88 {
89 assert(!m_client_key.empty());
90 assert(!m_client_iv.empty());
91 auto c = std::unique_ptr<Crypto>(new Crypto(decode64(m_client_key),
92 decode64(m_client_iv)));
93 c->m_packet_counter = 0;
94 return c;
95 }
96 // ------------------------------------------------------------------------
97 static void initClientAES()
98 {
99 std::random_device rd;
100 std::mt19937 g(rd());
101
102 // Default key and if RAND_bytes failed
103 std::vector<uint8_t> key;
104 for (int i = 0; i < 16; i++)
105 key.push_back((uint8_t)(g() % 255));
106 std::vector<uint8_t> iv;
107 for (int i = 0; i < 12; i++)
108 iv.push_back((uint8_t)(g() % 255));
109 if (!RAND_bytes(key.data(), 16))
110 {
111 Log::warn("Crypto",
112 "Failed to generate cryptographically strong key");
113 }
114 m_client_key = base64(key);
115 m_client_iv = base64(iv);
116 }
117 // ------------------------------------------------------------------------
118 static void resetClientAES()
119 {
120 m_client_key = "";
121 m_client_iv = "";
122 }
123 // ------------------------------------------------------------------------
124 static const std::string& getClientKey() { return m_client_key; }
125 // ------------------------------------------------------------------------
126 static const std::string& getClientIV() { return m_client_iv; }
127 // ------------------------------------------------------------------------
128 Crypto(const std::vector<uint8_t>& key,
129 const std::vector<uint8_t>& iv)
130 {
131 assert(key.size() == 16);
132 assert(iv.size() == 12);
133 std::copy_n(iv.begin(), 12, m_iv.begin());
134 m_packet_counter = 0;
135 m_encrypt = EVP_CIPHER_CTX_new();
136 EVP_CIPHER_CTX_init(m_encrypt);
137 EVP_EncryptInit_ex(m_encrypt, EVP_aes_128_gcm(), NULL, key.data(),
138 iv.data());
139 m_decrypt = EVP_CIPHER_CTX_new();
140 EVP_CIPHER_CTX_init(m_decrypt);
141 EVP_DecryptInit_ex(m_decrypt, EVP_aes_128_gcm(), NULL, key.data(),
142 iv.data());
143 }
144 // ------------------------------------------------------------------------
145 ~Crypto()
146 {
147 EVP_CIPHER_CTX_free(m_encrypt);
148 EVP_CIPHER_CTX_free(m_decrypt);
149 }
150 // ------------------------------------------------------------------------
151 bool encryptConnectionRequest(BareNetworkString& ns);
152 // ------------------------------------------------------------------------
153 bool decryptConnectionRequest(BareNetworkString& ns);
154 // ------------------------------------------------------------------------
155 ENetPacket* encryptSend(BareNetworkString& ns, bool reliable);
156 // ------------------------------------------------------------------------
157 NetworkString* decryptRecieve(ENetPacket* p);
158
159};
160
161#endif // HEADER_CRYPTO_OPENSSL_HPP
162
163#endif
Describes a chain of 8-bit unsigned integers.
Definition: network_string.hpp:53
unsigned int size() const
Returns the remaining length of the network string.
Definition: network_string.hpp:191
A new implementation of NetworkString, which has a fixed format: Byte 0: The type of the message,...
Definition: network_string.hpp:422
CScriptArray * sha256(std::string *input)
Return a sha256 checksum of string in an array of integers of size 32.
Definition: script_utils.cpp:164