Botcraft 1.21.4
Loading...
Searching...
No Matches
AESEncrypter.cpp
Go to the documentation of this file.
1#ifdef USE_ENCRYPTION
2
5#include <openssl/aes.h>
6#include <openssl/rsa.h>
7#include <openssl/x509.h>
8
9#include <random>
10#include <chrono>
11
12#if PROTOCOL_VERSION > 758 /* > 1.18.2 */
13#include <openssl/pem.h>
14
15#include <array>
16#endif
17
18namespace Botcraft
19{
21 {
22 blocksize = 0;
23 encryption_context = nullptr;
24 decryption_context = nullptr;
25 }
26
28 {
29 if (encryption_context != nullptr)
30 {
31 EVP_CIPHER_CTX_free(encryption_context);
32 encryption_context = nullptr;
33 }
34
35 if (decryption_context != nullptr)
36 {
37 EVP_CIPHER_CTX_free(decryption_context);
38 decryption_context = nullptr;
39 }
40 }
41
42
43#if PROTOCOL_VERSION < 759 /* < 1.19 */
44 void AESEncrypter::Init(const std::vector<unsigned char>& pub_key, const std::vector<unsigned char>& input_nonce,
45 std::vector<unsigned char>& raw_shared_secret, std::vector<unsigned char>& encrypted_nonce, std::vector<unsigned char>& encrypted_shared_secret)
46#elif PROTOCOL_VERSION < 761 /* < 1.19.3 */
47 void AESEncrypter::Init(const std::vector<unsigned char>& pub_key, const std::vector<unsigned char>& input_nonce, const std::string& private_key,
48 std::vector<unsigned char>& raw_shared_secret, std::vector<unsigned char>& encrypted_shared_secret,
49 long long int& salt, std::vector<unsigned char>& salted_nonce_signature)
50#else
51 void AESEncrypter::Init(const std::vector<unsigned char>& pub_key, const std::vector<unsigned char>& input_challenge,
52 std::vector<unsigned char>& raw_shared_secret, std::vector<unsigned char>& encrypted_shared_secret,
53 std::vector<unsigned char>& encrypted_challenge)
54#endif
55 {
56 const unsigned char* pub_key_ptr = pub_key.data();
57
58 RSA* rsa = d2i_RSA_PUBKEY(nullptr, &pub_key_ptr, static_cast<long>(pub_key.size()));
59
60 std::mt19937 random_gen(static_cast<unsigned int>(std::chrono::steady_clock::now().time_since_epoch().count()));
61 std::uniform_int_distribution<unsigned int> random_dist(0, 255);
62
63 raw_shared_secret = std::vector<unsigned char>(AES_BLOCK_SIZE);
64
65 for (int i = 0; i < AES_BLOCK_SIZE; ++i)
66 {
67 raw_shared_secret[i] = random_dist(random_gen);
68 }
69
70 int rsa_size = RSA_size(rsa);
71
72 encrypted_shared_secret = std::vector<unsigned char>(rsa_size);
73 RSA_public_encrypt(AES_BLOCK_SIZE, raw_shared_secret.data(), encrypted_shared_secret.data(), rsa, RSA_PKCS1_PADDING);
74#if PROTOCOL_VERSION < 759 /* < 1.19 */
75 // Pre-1.19 behaviour, compute encrypted nonce
76 encrypted_nonce = std::vector<unsigned char>(rsa_size);
77 RSA_public_encrypt(static_cast<int>(input_nonce.size()), input_nonce.data(), encrypted_nonce.data(), rsa, RSA_PKCS1_PADDING);
78#elif PROTOCOL_VERSION < 761 /* < 1.19.3 */
79 // 1.19, 1.19.1 and 1.19.2 behaviour, signature of salted nonce
80 // Generate random salt
81 salt = std::uniform_int_distribution<long long int>(std::numeric_limits<long long int>::min(), std::numeric_limits<long long int>::max())(random_gen);
82 std::array<unsigned char, 8> salt_bytes;
83 for (int i = 0; i < 8; ++i)
84 {
85 salt_bytes[i] = static_cast<unsigned char>((salt >> (8 * (7 - i))) & 0xFF);
86 }
87 // Compute salted nonce hash
88 std::array<unsigned char, SHA256_DIGEST_LENGTH> salted_hash;
89 SHA256_CTX sha256;
90 SHA256_Init(&sha256);
91 SHA256_Update(&sha256, input_nonce.data(), input_nonce.size());
92 SHA256_Update(&sha256, salt_bytes.data(), salt_bytes.size());
93 SHA256_Final(salted_hash.data(), &sha256);
94
95 // Extract signature key from PEM string
96 RSA* rsa_signature = nullptr;
97 const char* c_string = private_key.c_str();
98 BIO* keybio = BIO_new_mem_buf((void*)c_string, -1);
99 rsa_signature = PEM_read_bio_RSAPrivateKey(keybio, &rsa_signature, NULL, NULL);
100 BIO_free(keybio);
101
102 // Compute signature
103 const int rsa_signature_size = RSA_size(rsa_signature);
104 salted_nonce_signature = std::vector<unsigned char>(rsa_signature_size);
105 unsigned int salted_nonce_signature_size;
106 RSA_sign(NID_sha256, salted_hash.data(), static_cast<unsigned int>(salted_hash.size()), salted_nonce_signature.data(), &salted_nonce_signature_size, rsa_signature);
107 RSA_free(rsa_signature);
108 salted_nonce_signature.resize(salted_nonce_signature_size);
109#else
110 // 1.19.3 behaviour, back to compute encrypted challenge
111 encrypted_challenge = std::vector<unsigned char>(rsa_size);
112 RSA_public_encrypt(static_cast<int>(input_challenge.size()), input_challenge.data(), encrypted_challenge.data(), rsa, RSA_PKCS1_PADDING);
113#endif
114 RSA_free(rsa);
115
116 encryption_context = EVP_CIPHER_CTX_new();
117 EVP_EncryptInit_ex(encryption_context, EVP_aes_128_cfb8(), nullptr, raw_shared_secret.data(), raw_shared_secret.data());
118
119 decryption_context = EVP_CIPHER_CTX_new();
120 EVP_DecryptInit_ex(decryption_context, EVP_aes_128_cfb8(), nullptr, raw_shared_secret.data(), raw_shared_secret.data());
121
122 blocksize = EVP_CIPHER_block_size(EVP_aes_128_cfb8());
123 }
124
125 std::vector<unsigned char> AESEncrypter::Encrypt(const std::vector<unsigned char>& in)
126 {
127 if (encryption_context == nullptr)
128 {
129 LOG_WARNING("Warning, trying to encrypt packet while encryption is not initialized yet");
130 return in;
131 }
132
133 std::vector<unsigned char> output;
134 int size = 0;
135
136 output.resize(in.size() + blocksize);
137 EVP_EncryptUpdate(encryption_context, output.data(), &size, in.data(), static_cast<int>(in.size()));
138 output.resize(size);
139
140 return output;
141 }
142
143 std::vector<unsigned char> AESEncrypter::Decrypt(const std::vector<unsigned char>& in)
144 {
145 if (decryption_context == nullptr)
146 {
147 LOG_WARNING("Warning, trying to decrypt packet while decryption is not initialized yet");
148 return in;
149 }
150
151 std::vector<unsigned char> output;
152 int size = 0;
153
154 output.resize(in.size() + blocksize);
155 EVP_DecryptUpdate(decryption_context, output.data(), &size, in.data(), static_cast<int>(in.size()));
156 output.resize(size);
157
158 return output;
159 }
160}
161#endif // USE_ENCRYPTION
#define LOG_WARNING(osstream)
Definition Logger.hpp:44
void Init(const std::vector< unsigned char > &pub_key, const std::vector< unsigned char > &input_nonce, std::vector< unsigned char > &raw_shared_secret, std::vector< unsigned char > &encrypted_shared_secret, std::vector< unsigned char > &encrypted_challenge)
Initialize the encryption context for this connection.
EVP_CIPHER_CTX * decryption_context
std::vector< unsigned char > Encrypt(const std::vector< unsigned char > &in)
EVP_CIPHER_CTX * encryption_context
std::vector< unsigned char > Decrypt(const std::vector< unsigned char > &in)