SuperTuxKart
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 #define CRYPTO_AES_GCM_32BIT_TAG
24 
25 #include "utils/log.hpp"
26 
27 #include <enet/enet.h>
28 
29 #define OPENSSL_API_COMPAT 0x09800000L
30 #include <openssl/evp.h>
31 #include <openssl/rand.h>
32 
33 #include <algorithm>
34 #include <array>
35 #include <cassert>
36 #include <cstdint>
37 #include <memory>
38 #include <mutex>
39 #include <random>
40 #include <string>
41 #include <vector>
42 
43 class BareNetworkString;
44 class NetworkString;
45 
46 class Crypto
47 {
48 private:
49  static std::string m_client_key;
50 
51  static std::string m_client_iv;
52 
53  std::array<uint8_t, 12> m_iv;
54 
55  uint32_t m_packet_counter;
56 
57  EVP_CIPHER_CTX* m_encrypt;
58 
59  EVP_CIPHER_CTX* m_decrypt;
60 
61  std::mutex m_crypto_mutex;
62 
63  const size_t m_tag_size;
64 
65  // ------------------------------------------------------------------------
66  static size_t calcDecodeLength(const std::string& input)
67  {
68  // Calculates the length of a decoded string
69  size_t padding = 0;
70  const size_t len = input.size();
71  if (input[len - 1] == '=' && input[len - 2] == '=')
72  {
73  // last two chars are =
74  padding = 2;
75  }
76  else if (input[len - 1] == '=')
77  {
78  // last char is =
79  padding = 1;
80  }
81  return (len * 3) / 4 - padding;
82  } // calcDecodeLength
83 public:
84  // ------------------------------------------------------------------------
85  static std::string base64(const std::vector<uint8_t>& input);
86  // ------------------------------------------------------------------------
87  static std::vector<uint8_t> decode64(std::string input);
88  // ------------------------------------------------------------------------
89  static std::array<uint8_t, 32> sha256(const std::string& input);
90  // ------------------------------------------------------------------------
91  static std::unique_ptr<Crypto> getClientCrypto(size_t tag_size = 4)
92  {
93  assert(!m_client_key.empty());
94  assert(!m_client_iv.empty());
95  assert(tag_size == 4 || tag_size == 16);
96  auto c = std::unique_ptr<Crypto>(new Crypto(decode64(m_client_key),
97  decode64(m_client_iv), tag_size));
98  c->m_packet_counter = 0;
99  return c;
100  }
101  // ------------------------------------------------------------------------
102  static void initClientAES()
103  {
104  std::random_device rd;
105  std::mt19937 g(rd());
106 
107  // Default key and if RAND_bytes failed
108  std::vector<uint8_t> key;
109  for (int i = 0; i < 16; i++)
110  key.push_back((uint8_t)(g() % 255));
111  std::vector<uint8_t> iv;
112  for (int i = 0; i < 12; i++)
113  iv.push_back((uint8_t)(g() % 255));
114  if (!RAND_bytes(key.data(), 16))
115  {
116  Log::warn("Crypto",
117  "Failed to generate cryptographically strong key");
118  }
119  m_client_key = base64(key);
120  m_client_iv = base64(iv);
121  }
122  // ------------------------------------------------------------------------
123  static void resetClientAES()
124  {
125  m_client_key = "";
126  m_client_iv = "";
127  }
128  // ------------------------------------------------------------------------
129  static const std::string& getClientKey() { return m_client_key; }
130  // ------------------------------------------------------------------------
131  static const std::string& getClientIV() { return m_client_iv; }
132  // ------------------------------------------------------------------------
133  Crypto(const std::vector<uint8_t>& key,
134  const std::vector<uint8_t>& iv,
135  size_t tag_size = 4) : m_tag_size(tag_size)
136  {
137  assert(key.size() == 16);
138  assert(iv.size() == 12);
139  assert(m_tag_size == 4 || m_tag_size == 16);
140  std::copy_n(iv.begin(), 12, m_iv.begin());
141  m_packet_counter = 0;
142  m_encrypt = EVP_CIPHER_CTX_new();
143  EVP_CIPHER_CTX_init(m_encrypt);
144  EVP_EncryptInit_ex(m_encrypt, EVP_aes_128_gcm(), NULL, key.data(),
145  iv.data());
146  m_decrypt = EVP_CIPHER_CTX_new();
147  EVP_CIPHER_CTX_init(m_decrypt);
148  EVP_DecryptInit_ex(m_decrypt, EVP_aes_128_gcm(), NULL, key.data(),
149  iv.data());
150  }
151  // ------------------------------------------------------------------------
152  ~Crypto()
153  {
154  EVP_CIPHER_CTX_free(m_encrypt);
155  EVP_CIPHER_CTX_free(m_decrypt);
156  }
157  // ------------------------------------------------------------------------
158  bool encryptConnectionRequest(BareNetworkString& ns);
159  // ------------------------------------------------------------------------
160  bool decryptConnectionRequest(BareNetworkString& ns);
161  // ------------------------------------------------------------------------
162  ENetPacket* encryptSend(BareNetworkString& ns, bool reliable);
163  // ------------------------------------------------------------------------
164  NetworkString* decryptRecieve(ENetPacket* p);
165 
166 };
167 
168 #endif // HEADER_CRYPTO_OPENSSL_HPP
169 
170 #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:163