Update openssl calls to use EVP interface (#5072)
Some checks failed
Build / Linux (push) Has been cancelled
Build / Windows (push) Has been cancelled

This commit is contained in:
Knightly 2026-04-25 13:49:03 -10:00 committed by GitHub
parent 6694281f22
commit 6d6cc8ca95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 119 additions and 32 deletions

View File

@ -19,9 +19,9 @@
#include "common/compiler_macros.h"
#ifdef EQEMU_USE_OPENSSL
#include <openssl/des.h>
#include <openssl/sha.h>
#include <openssl/md5.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/provider.h>
#endif
#ifdef EQEMU_USE_MBEDTLS
#include <mbedtls/des.h>
@ -33,6 +33,8 @@
#include <cstring>
#include <string>
#include <memory>
#ifdef ENABLE_SECURITY
#include <sodium.h>
@ -128,23 +130,92 @@ const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buff
#endif
#ifdef EQEMU_USE_OPENSSL
DES_key_schedule k;
DES_cblock v;
memset(&k, 0, sizeof(DES_key_schedule));
memset(&v, 0, sizeof(DES_cblock));
// Decrypt requires block-aligned input; encrypt zero-pads a trailing
// partial block to match the legacy DES_ncbc_encrypt semantics the
// game protocol expects.
if (!enc && buffer_in_sz && buffer_in_sz % 8 != 0) {
return nullptr;
}
PUSH_DISABLE_DEPRECATED_WARNINGS()
DES_ncbc_encrypt((const unsigned char*)buffer_in, (unsigned char*)buffer_out, (long)buffer_in_sz, &k, &v, enc);
POP_DISABLE_DEPRECATED_WARNINGS()
unsigned char key[8] = {0};
unsigned char iv[8] = {0};
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
return nullptr;
}
bool result = EVP_CipherInit_ex2(ctx, EVP_des_cbc(), key, iv, enc, nullptr) == 1;
if (result) {
EVP_CIPHER_CTX_set_padding(ctx, 0);
const unsigned char* src = reinterpret_cast<const unsigned char*>(buffer_in);
size_t src_len = buffer_in_sz;
std::unique_ptr<unsigned char[]> padded;
if (enc && buffer_in_sz % 8 != 0) {
src_len = ((buffer_in_sz / 8) + 1) * 8;
padded.reset(new unsigned char[src_len]());
memcpy(padded.get(), buffer_in, buffer_in_sz);
src = padded.get();
}
int outl = 0;
int final_len = 0;
result = EVP_CipherUpdate(ctx, reinterpret_cast<unsigned char*>(buffer_out), &outl, src, static_cast<int>(src_len)) == 1
&& EVP_CipherFinal_ex(ctx, reinterpret_cast<unsigned char*>(buffer_out) + outl, &final_len) == 1;
}
EVP_CIPHER_CTX_free(ctx);
if (!result) {
return nullptr;
}
#endif
return buffer_out;
}
#ifdef EQEMU_USE_OPENSSL
static OSSL_PROVIDER *s_legacy_provider = nullptr;
static OSSL_PROVIDER *s_default_provider = nullptr;
#endif
bool eqcrypt_init()
{
#ifdef EQEMU_USE_OPENSSL
if (!s_default_provider) {
s_default_provider = OSSL_PROVIDER_load(nullptr, "default");
}
if (!s_legacy_provider) {
s_legacy_provider = OSSL_PROVIDER_load(nullptr, "legacy");
}
if (!s_default_provider || !s_legacy_provider) {
char buf[256];
while (auto err = ERR_get_error()) {
ERR_error_string_n(err, buf, sizeof(buf));
LogError("OpenSSL provider load failure: {}", buf);
}
return false;
}
#endif
return true;
}
void eqcrypt_shutdown()
{
#ifdef EQEMU_USE_OPENSSL
if (s_legacy_provider) {
OSSL_PROVIDER_unload(s_legacy_provider);
s_legacy_provider = nullptr;
}
if (s_default_provider) {
OSSL_PROVIDER_unload(s_default_provider);
s_default_provider = nullptr;
}
#endif
}
std::string eqcrypt_md5(const std::string &msg)
{
std::string ret;
@ -167,14 +238,12 @@ std::string eqcrypt_md5(const std::string &msg)
unsigned char md5_digest[16];
char tmp[4];
PUSH_DISABLE_DEPRECATED_WARNINGS()
MD5((const unsigned char*)msg.c_str(), msg.length(), md5_digest);
POP_DISABLE_DEPRECATED_WARNINGS()
for (int i = 0; i < 16; ++i) {
sprintf(&tmp[0], "%02x", md5_digest[i]);
ret.push_back(tmp[0]);
ret.push_back(tmp[1]);
if (EVP_Digest(msg.data(), msg.length(), md5_digest, nullptr, EVP_md5(), nullptr) == 1) {
for (int i = 0; i < 16; ++i) {
sprintf(&tmp[0], "%02x", md5_digest[i]);
ret.push_back(tmp[0]);
ret.push_back(tmp[1]);
}
}
#endif
@ -203,12 +272,12 @@ std::string eqcrypt_sha1(const std::string &msg)
unsigned char sha_digest[20];
char tmp[4];
SHA1((const unsigned char*)msg.c_str(), msg.length(), sha_digest);
for (int i = 0; i < 20; ++i) {
sprintf(&tmp[0], "%02x", sha_digest[i]);
ret.push_back(tmp[0]);
ret.push_back(tmp[1]);
if (EVP_Digest(msg.data(), msg.length(), sha_digest, nullptr, EVP_sha1(), nullptr) == 1) {
for (int i = 0; i < 20; ++i) {
sprintf(&tmp[0], "%02x", sha_digest[i]);
ret.push_back(tmp[0]);
ret.push_back(tmp[1]);
}
}
#endif
@ -237,12 +306,12 @@ std::string eqcrypt_sha512(const std::string &msg)
unsigned char sha_digest[64];
char tmp[4];
SHA512((const unsigned char*)msg.c_str(), msg.length(), sha_digest);
for (int i = 0; i < 64; ++i) {
sprintf(&tmp[0], "%02x", sha_digest[i]);
ret.push_back(tmp[0]);
ret.push_back(tmp[1]);
if (EVP_Digest(msg.data(), msg.length(), sha_digest, nullptr, EVP_sha512(), nullptr) == 1) {
for (int i = 0; i < 64; ++i) {
sprintf(&tmp[0], "%02x", sha_digest[i]);
ret.push_back(tmp[0]);
ret.push_back(tmp[1]);
}
}
#endif

View File

@ -48,10 +48,20 @@ namespace CryptoHash {
}
std::string GetEncryptionByModeId(uint32 mode);
// DES-CBC with an all-zero key and IV (EQ login protocol obfuscation, not security).
// On encrypt, a trailing partial block is zero-padded to the next 8-byte boundary, so
// buffer_out must be at least ((buffer_in_sz + 7) / 8) * 8 bytes. On decrypt, buffer_in_sz
// must already be a multiple of 8 or the call returns nullptr.
const char *eqcrypt_block(const char *buffer_in, size_t buffer_in_sz, char *buffer_out, bool enc);
std::string eqcrypt_hash(const std::string &username, const std::string &password, int mode);
bool eqcrypt_verify_hash(const std::string &username, const std::string &password, const std::string &pwhash, int mode);
// OpenSSL 3.0 moved DES behind the "legacy" provider; these load/unload it
// for the lifetime of the process. No-op when built against mbedtls.
bool eqcrypt_init();
void eqcrypt_shutdown();
struct EncryptionResult {
std::string password;
int mode = 0;

View File

@ -26,6 +26,7 @@
#include "common/platform.h"
#include "common/timer.h"
#include "common/types.h"
#include "loginserver/encryption.h"
#include "loginserver/login_server.h"
#include "loginserver/loginserver_command_handler.h"
#include "loginserver/loginserver_webserver.h"
@ -160,6 +161,11 @@ int main(int argc, char **argv)
RegisterExecutablePlatform(ExePlatformLogin);
set_exception_handler();
if (!eqcrypt_init()) {
LogError("Failed to initialize crypto providers");
return 1;
}
LogInfo("Logging System Init");
if (argc == 1) {
@ -280,5 +286,7 @@ int main(int argc, char **argv)
LogInfo("Server Manager Shutdown");
delete server.server_manager;
eqcrypt_shutdown();
return 0;
}