clean crypto and rc4
This commit is contained in:
parent
4feb3ef685
commit
53a84d3ca7
@ -21,7 +21,7 @@
|
|||||||
#include "Mutex.h"
|
#include "Mutex.h"
|
||||||
#include "opcodemgr.h"
|
#include "opcodemgr.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "crypto/Crypto.h"
|
#include "crypto/crypto.h"
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ struct ServerSessionStats {
|
|||||||
uint32 unknown4; // Unknown field 4
|
uint32 unknown4; // Unknown field 4
|
||||||
uint32 received_packets2; // Duplicate received packets count
|
uint32 received_packets2; // Duplicate received packets count
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
// External opcode manager
|
// External opcode manager
|
||||||
@ -167,11 +167,11 @@ protected:
|
|||||||
// Packet statistics
|
// Packet statistics
|
||||||
uint32 received_packets; // Total packets received
|
uint32 received_packets; // Total packets received
|
||||||
uint32 sent_packets; // Total packets sent
|
uint32 sent_packets; // Total packets sent
|
||||||
|
|
||||||
// Remote endpoint information
|
// Remote endpoint information
|
||||||
uint32 remote_ip; // Remote IP address
|
uint32 remote_ip; // Remote IP address
|
||||||
uint16 remote_port; // Remote port number
|
uint16 remote_port; // Remote port number
|
||||||
|
|
||||||
// Packet buffers
|
// Packet buffers
|
||||||
uint8 buffer[8192]; // Main packet buffer
|
uint8 buffer[8192]; // Main packet buffer
|
||||||
unsigned char* oversize_buffer; // Buffer for oversized packets
|
unsigned char* oversize_buffer; // Buffer for oversized packets
|
||||||
@ -180,16 +180,16 @@ protected:
|
|||||||
unsigned char* rogue_buffer; // Buffer for rogue/malformed packets
|
unsigned char* rogue_buffer; // Buffer for rogue/malformed packets
|
||||||
uint32 roguebuf_offset; // Offset in rogue buffer
|
uint32 roguebuf_offset; // Offset in rogue buffer
|
||||||
uint32 roguebuf_size; // Size of rogue buffer
|
uint32 roguebuf_size; // Size of rogue buffer
|
||||||
|
|
||||||
// Protocol configuration
|
// Protocol configuration
|
||||||
uint8 app_opcode_size; // Size of application opcodes
|
uint8 app_opcode_size; // Size of application opcodes
|
||||||
EQStreamType StreamType; // Type of this stream
|
EQStreamType StreamType; // Type of this stream
|
||||||
bool compressed; // Stream supports compression
|
bool compressed; // Stream supports compression
|
||||||
bool encoded; // Stream supports encoding/encryption
|
bool encoded; // Stream supports encoding/encryption
|
||||||
|
|
||||||
// Write buffer for outgoing packets
|
// Write buffer for outgoing packets
|
||||||
unsigned char write_buffer[2048];
|
unsigned char write_buffer[2048];
|
||||||
|
|
||||||
// Retransmission timing
|
// Retransmission timing
|
||||||
uint32 retransmittimer; // Current retransmit timer
|
uint32 retransmittimer; // Current retransmit timer
|
||||||
uint32 retransmittimeout; // Retransmit timeout value
|
uint32 retransmittimeout; // Retransmit timeout value
|
||||||
@ -244,7 +244,7 @@ protected:
|
|||||||
long MaxAckReceived; // Highest ack sequence received
|
long MaxAckReceived; // Highest ack sequence received
|
||||||
long NextAckToSend; // Next ack sequence to send
|
long NextAckToSend; // Next ack sequence to send
|
||||||
long LastAckSent; // Last ack sequence sent
|
long LastAckSent; // Last ack sequence sent
|
||||||
|
|
||||||
// Acknowledgment accessor methods
|
// Acknowledgment accessor methods
|
||||||
long GetMaxAckReceived();
|
long GetMaxAckReceived();
|
||||||
long GetNextAckToSend();
|
long GetNextAckToSend();
|
||||||
@ -293,16 +293,16 @@ public:
|
|||||||
int32 stream_buffer_size; // Size of compression buffer
|
int32 stream_buffer_size; // Size of compression buffer
|
||||||
bool eq2_compressed; // Stream uses EQ2 compression
|
bool eq2_compressed; // Stream uses EQ2 compression
|
||||||
int8 compressed_offset; // Offset for compressed data
|
int8 compressed_offset; // Offset for compressed data
|
||||||
|
|
||||||
// Client version management
|
// Client version management
|
||||||
int16 client_version; // Client protocol version
|
int16 client_version; // Client protocol version
|
||||||
int16 GetClientVersion() { return client_version; }
|
int16 GetClientVersion() { return client_version; }
|
||||||
void SetClientVersion(int16 version) { client_version = version; }
|
void SetClientVersion(int16 version) { client_version = version; }
|
||||||
|
|
||||||
// Session attempt management
|
// Session attempt management
|
||||||
void ResetSessionAttempts() { reconnectAttempt = 0; }
|
void ResetSessionAttempts() { reconnectAttempt = 0; }
|
||||||
bool HasSessionAttempts() { return reconnectAttempt > 0; }
|
bool HasSessionAttempts() { return reconnectAttempt > 0; }
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
EQStream() {
|
EQStream() {
|
||||||
init();
|
init();
|
||||||
@ -314,7 +314,7 @@ public:
|
|||||||
encoded = false;
|
encoded = false;
|
||||||
app_opcode_size = 2;
|
app_opcode_size = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
EQStream(sockaddr_in addr);
|
EQStream(sockaddr_in addr);
|
||||||
// Destructor
|
// Destructor
|
||||||
virtual ~EQStream() {
|
virtual ~EQStream() {
|
||||||
@ -322,32 +322,32 @@ public:
|
|||||||
MOutboundQueue.lock();
|
MOutboundQueue.lock();
|
||||||
SetState(CLOSED);
|
SetState(CLOSED);
|
||||||
MOutboundQueue.unlock();
|
MOutboundQueue.unlock();
|
||||||
|
|
||||||
// Clean up data structures
|
// Clean up data structures
|
||||||
RemoveData();
|
RemoveData();
|
||||||
|
|
||||||
// Clean up allocated resources
|
// Clean up allocated resources
|
||||||
safe_delete(crypto);
|
safe_delete(crypto);
|
||||||
safe_delete(combine_timer);
|
safe_delete(combine_timer);
|
||||||
safe_delete(resend_que_timer);
|
safe_delete(resend_que_timer);
|
||||||
safe_delete_array(oversize_buffer);
|
safe_delete_array(oversize_buffer);
|
||||||
safe_delete_array(rogue_buffer);
|
safe_delete_array(rogue_buffer);
|
||||||
|
|
||||||
// Clean up combine queue
|
// Clean up combine queue
|
||||||
MCombineQueueLock.lock();
|
MCombineQueueLock.lock();
|
||||||
for (auto cmb = combine_queue.begin(); cmb != combine_queue.end(); ++cmb) {
|
for (auto cmb = combine_queue.begin(); cmb != combine_queue.end(); ++cmb) {
|
||||||
safe_delete(*cmb);
|
safe_delete(*cmb);
|
||||||
}
|
}
|
||||||
MCombineQueueLock.unlock();
|
MCombineQueueLock.unlock();
|
||||||
|
|
||||||
// Clean up compression stream
|
// Clean up compression stream
|
||||||
deflateEnd(&stream);
|
deflateEnd(&stream);
|
||||||
|
|
||||||
// Clean up out-of-order packets
|
// Clean up out-of-order packets
|
||||||
for (auto oop = OutOfOrderpackets.begin(); oop != OutOfOrderpackets.end(); ++oop) {
|
for (auto oop = OutOfOrderpackets.begin(); oop != OutOfOrderpackets.end(); ++oop) {
|
||||||
safe_delete(oop->second);
|
safe_delete(oop->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WRITE_PACKETS
|
#ifdef WRITE_PACKETS
|
||||||
if (write_packets) {
|
if (write_packets) {
|
||||||
fclose(write_packets);
|
fclose(write_packets);
|
||||||
@ -357,19 +357,19 @@ public:
|
|||||||
// Factory and initialization
|
// Factory and initialization
|
||||||
void SetFactory(EQStreamFactory* f) { Factory = f; }
|
void SetFactory(EQStreamFactory* f) { Factory = f; }
|
||||||
void init(bool resetSession = true);
|
void init(bool resetSession = true);
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
void SetMaxLen(uint32 length) { MaxLen = length; }
|
void SetMaxLen(uint32 length) { MaxLen = length; }
|
||||||
int8 getTimeoutDelays() { return timeout_delays; }
|
int8 getTimeoutDelays() { return timeout_delays; }
|
||||||
void addTimeoutDelay() { timeout_delays++; }
|
void addTimeoutDelay() { timeout_delays++; }
|
||||||
|
|
||||||
// EQ2-specific packet handling
|
// EQ2-specific packet handling
|
||||||
void EQ2QueuePacket(EQ2Packet* app, bool attempted_combine = false);
|
void EQ2QueuePacket(EQ2Packet* app, bool attempted_combine = false);
|
||||||
void PreparePacket(EQ2Packet* app, int8 offset = 0);
|
void PreparePacket(EQ2Packet* app, int8 offset = 0);
|
||||||
void UnPreparePacket(EQ2Packet* app);
|
void UnPreparePacket(EQ2Packet* app);
|
||||||
void EncryptPacket(EQ2Packet* app, int8 compress_offset, int8 offset);
|
void EncryptPacket(EQ2Packet* app, int8 compress_offset, int8 offset);
|
||||||
void FlushCombinedPacket();
|
void FlushCombinedPacket();
|
||||||
|
|
||||||
// General packet transmission
|
// General packet transmission
|
||||||
void SendPacket(EQApplicationPacket* p);
|
void SendPacket(EQApplicationPacket* p);
|
||||||
void QueuePacket(EQProtocolPacket* p);
|
void QueuePacket(EQProtocolPacket* p);
|
||||||
@ -390,11 +390,11 @@ public:
|
|||||||
|
|
||||||
// Stream state management
|
// Stream state management
|
||||||
void SetActive(bool val) { streamactive = val; }
|
void SetActive(bool val) { streamactive = val; }
|
||||||
|
|
||||||
// Low-level packet operations
|
// Low-level packet operations
|
||||||
void WritePacket(int fd, EQProtocolPacket* p);
|
void WritePacket(int fd, EQProtocolPacket* p);
|
||||||
void EncryptPacket(uchar* data, int16 size);
|
void EncryptPacket(uchar* data, int16 size);
|
||||||
|
|
||||||
// Session management
|
// Session management
|
||||||
uint32 GetKey() { return Key; }
|
uint32 GetKey() { return Key; }
|
||||||
void SetKey(uint32 k) { Key = k; }
|
void SetKey(uint32 k) { Key = k; }
|
||||||
@ -404,7 +404,7 @@ public:
|
|||||||
// Packet processing
|
// Packet processing
|
||||||
void Process(const unsigned char* data, uint32 length);
|
void Process(const unsigned char* data, uint32 length);
|
||||||
void ProcessPacket(EQProtocolPacket* p, EQProtocolPacket* lastp = nullptr);
|
void ProcessPacket(EQProtocolPacket* p, EQProtocolPacket* lastp = nullptr);
|
||||||
|
|
||||||
// Embedded packet handling
|
// Embedded packet handling
|
||||||
bool ProcessEmbeddedPacket(uchar* pBuffer, uint16 length, int8 opcode = OP_Packet);
|
bool ProcessEmbeddedPacket(uchar* pBuffer, uint16 length, int8 opcode = OP_Packet);
|
||||||
bool HandleEmbeddedPacket(EQProtocolPacket* p, int16 offset = 2, int16 length = 0);
|
bool HandleEmbeddedPacket(EQProtocolPacket* p, int16 offset = 2, int16 length = 0);
|
||||||
@ -439,11 +439,11 @@ public:
|
|||||||
// Outbound queue management
|
// Outbound queue management
|
||||||
void OutboundQueueClear();
|
void OutboundQueueClear();
|
||||||
bool HasOutgoingData();
|
bool HasOutgoingData();
|
||||||
|
|
||||||
// Key exchange and RSA
|
// Key exchange and RSA
|
||||||
void SendKeyRequest();
|
void SendKeyRequest();
|
||||||
int16 processRSAKey(EQProtocolPacket* p, uint16 subpacket_length = 0);
|
int16 processRSAKey(EQProtocolPacket* p, uint16 subpacket_length = 0);
|
||||||
|
|
||||||
// Data cleanup
|
// Data cleanup
|
||||||
void RemoveData() {
|
void RemoveData() {
|
||||||
InboundQueueClear();
|
InboundQueueClear();
|
||||||
@ -462,13 +462,13 @@ public:
|
|||||||
MInUse.unlock();
|
MInUse.unlock();
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PutInUse() {
|
void PutInUse() {
|
||||||
MInUse.lock();
|
MInUse.lock();
|
||||||
active_users++;
|
active_users++;
|
||||||
MInUse.unlock();
|
MInUse.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseFromUse() {
|
void ReleaseFromUse() {
|
||||||
MInUse.lock();
|
MInUse.lock();
|
||||||
if (active_users > 0) {
|
if (active_users > 0) {
|
||||||
@ -501,7 +501,7 @@ public:
|
|||||||
void Close() { SendDisconnect(); }
|
void Close() { SendDisconnect(); }
|
||||||
bool CheckActive() { return (GetState() == ESTABLISHED); }
|
bool CheckActive() { return (GetState() == ESTABLISHED); }
|
||||||
bool CheckClosed() { return GetState() == CLOSED; }
|
bool CheckClosed() { return GetState() == CLOSED; }
|
||||||
|
|
||||||
// Stream configuration
|
// Stream configuration
|
||||||
void SetOpcodeSize(uint8 s) { app_opcode_size = s; }
|
void SetOpcodeSize(uint8 s) { app_opcode_size = s; }
|
||||||
void SetStreamType(EQStreamType t);
|
void SetStreamType(EQStreamType t);
|
||||||
@ -514,7 +514,7 @@ public:
|
|||||||
// Rate limiting and flow control
|
// Rate limiting and flow control
|
||||||
void Decay();
|
void Decay();
|
||||||
void AdjustRates(uint32 average_delta);
|
void AdjustRates(uint32 average_delta);
|
||||||
|
|
||||||
// Resend timer
|
// Resend timer
|
||||||
Timer* resend_que_timer; // Timer for checking resend queue
|
Timer* resend_que_timer; // Timer for checking resend queue
|
||||||
};
|
};
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
// Copyright (C) 2007-2025 EQ2EMulator
|
|
||||||
// Licensed under GPL v3
|
|
||||||
#include "Crypto.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include "../common/packet_dump.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
void test();
|
|
||||||
int64 Crypto::RSADecrypt(uchar* text, int16 size){
|
|
||||||
int64 ret = 0;
|
|
||||||
uchar* buffer = new uchar[8];
|
|
||||||
for(int i=7;i>=0;i--)
|
|
||||||
buffer[7-i] = text[i];
|
|
||||||
memcpy(&ret, buffer, 8);
|
|
||||||
safe_delete_array(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Crypto::RC4Decrypt(uchar* text, int32 size){
|
|
||||||
MCrypto.lock();
|
|
||||||
client->Cypher(text, size);
|
|
||||||
MCrypto.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Crypto::RC4Encrypt(uchar* text, int32 size){
|
|
||||||
MCrypto.lock();
|
|
||||||
server->Cypher(text, size);
|
|
||||||
MCrypto.unlock();
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
|||||||
// Copyright (C) 2007-2025 EQ2EMulator
|
|
||||||
// Licensed under GPL v3
|
|
||||||
#ifndef _CRYPTO_H
|
|
||||||
#define _CRYPTO_H
|
|
||||||
#include <string>
|
|
||||||
#include <mutex>
|
|
||||||
#include "RC4.h"
|
|
||||||
#include "../common/types.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
class Crypto {
|
|
||||||
public:
|
|
||||||
~Crypto(){ safe_delete(client); safe_delete(server); }
|
|
||||||
Crypto() { rc4_key = 0; encrypted = false; client = 0; server = 0; };
|
|
||||||
|
|
||||||
static int64 RSADecrypt(uchar* text, int16 size);
|
|
||||||
void RC4Encrypt(uchar* text, int32 size);
|
|
||||||
void RC4Decrypt(uchar* text, int32 size);
|
|
||||||
int64 getRC4Key() { return rc4_key; }
|
|
||||||
void setRC4Key(int64 key) {
|
|
||||||
rc4_key = key;
|
|
||||||
if(key > 0){
|
|
||||||
encrypted = true;
|
|
||||||
client = new RC4(~key);
|
|
||||||
server = new RC4(key);
|
|
||||||
uchar temp[20];
|
|
||||||
client->Cypher(temp, 20);
|
|
||||||
server->Cypher(temp, 20);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
encrypted = false;
|
|
||||||
safe_delete(client);
|
|
||||||
safe_delete(server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool isEncrypted(){ return encrypted; }
|
|
||||||
void setEncrypted(bool in_val){ encrypted = in_val; }
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
RC4* server;
|
|
||||||
RC4* client;
|
|
||||||
bool encrypted;
|
|
||||||
int64 rc4_key;
|
|
||||||
mutex MCrypto;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
|||||||
// Copyright (C) 2007-2025 EQ2EMulator
|
|
||||||
// Licensed under GPL v3
|
|
||||||
#include "RC4.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static bool g_bInitStateInitialized = false;
|
|
||||||
static uchar g_byInitState[256];
|
|
||||||
|
|
||||||
RC4::RC4(int64 nKey)
|
|
||||||
{
|
|
||||||
if( !g_bInitStateInitialized )
|
|
||||||
{
|
|
||||||
for(int16 i = 0; i < 256; i++ )
|
|
||||||
g_byInitState[i] = i;
|
|
||||||
}
|
|
||||||
Init(nKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
RC4::~RC4()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void RC4::Init(int64 nKey)
|
|
||||||
{
|
|
||||||
memcpy(m_state, g_byInitState, 256);
|
|
||||||
m_x = 0;
|
|
||||||
m_y = 0;
|
|
||||||
|
|
||||||
ulong dwKeyIndex = 0;
|
|
||||||
ulong dwStateIndex = 0;
|
|
||||||
uchar* pKey = (uchar*)&nKey;
|
|
||||||
for(int16 i = 0; i < 256; i++ )
|
|
||||||
{
|
|
||||||
ulong dwTemp = m_state[i];
|
|
||||||
dwStateIndex += pKey[dwKeyIndex] + dwTemp;
|
|
||||||
dwStateIndex &= 0xFF;
|
|
||||||
m_state[i] = m_state[dwStateIndex];
|
|
||||||
m_state[dwStateIndex] = (uchar)dwTemp;
|
|
||||||
dwKeyIndex++;
|
|
||||||
dwKeyIndex &= 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A = m_state[X + 1]
|
|
||||||
// B = m_state[Y + A]
|
|
||||||
// C ^= m_state[(A + B)]
|
|
||||||
|
|
||||||
// X = 20
|
|
||||||
// Y = ?
|
|
||||||
// C = 0
|
|
||||||
// m_state[(A + B)] = Cypher Byte
|
|
||||||
|
|
||||||
void RC4::Cypher(uchar* pBuffer, int32 nLength)
|
|
||||||
{
|
|
||||||
int32 nOffset = 0;
|
|
||||||
uchar byKey1 = m_x;
|
|
||||||
uchar byKey2 = m_y;
|
|
||||||
if( nLength > 0 )
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
byKey1++;
|
|
||||||
uchar byKeyVal1 = m_state[byKey1];
|
|
||||||
|
|
||||||
byKey2 += byKeyVal1;
|
|
||||||
uchar byKeyVal2 = m_state[byKey2];
|
|
||||||
|
|
||||||
m_state[byKey1] = byKeyVal2;
|
|
||||||
m_state[byKey2] = byKeyVal1;
|
|
||||||
|
|
||||||
pBuffer[nOffset++] ^= m_state[(byKeyVal1 + byKeyVal2) & 0xFF];
|
|
||||||
} while( nOffset < nLength );
|
|
||||||
}
|
|
||||||
m_x = byKey1;
|
|
||||||
m_y = byKey2;
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
// Copyright (C) 2007-2025 EQ2EMulator
|
|
||||||
// Licensed under GPL v3
|
|
||||||
#ifndef _EQ2_RC4_H
|
|
||||||
#define _EQ2_RC4_H
|
|
||||||
#include "../common/types.h"
|
|
||||||
class RC4
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RC4(int64 nKey);
|
|
||||||
~RC4();
|
|
||||||
|
|
||||||
void Init(int64 nKey);
|
|
||||||
void Cypher(uchar* pData, int32 nLen);
|
|
||||||
|
|
||||||
private:
|
|
||||||
uchar m_state[256];
|
|
||||||
uchar m_x;
|
|
||||||
uchar m_y;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
53
source/common/crypto/crypto.cpp
Normal file
53
source/common/crypto/crypto.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright (C) 2007-2025 EQ2EMulator
|
||||||
|
// Licensed under GPL v3
|
||||||
|
|
||||||
|
#include "crypto.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cstring>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
int64 Crypto::RSADecrypt(uchar* text, int16 size) noexcept
|
||||||
|
{
|
||||||
|
int64 ret = 0;
|
||||||
|
std::array<uchar, 8> buffer{};
|
||||||
|
|
||||||
|
for (int i = 7; i >= 0; --i) {
|
||||||
|
buffer[7 - i] = text[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(&ret, buffer.data(), 8);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Crypto::RC4Decrypt(uchar* text, int32 size) noexcept
|
||||||
|
{
|
||||||
|
const std::lock_guard<std::mutex> lock(m_crypto_mutex);
|
||||||
|
client->Cypher(text, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Crypto::RC4Encrypt(uchar* text, int32 size) noexcept
|
||||||
|
{
|
||||||
|
const std::lock_guard<std::mutex> lock(m_crypto_mutex);
|
||||||
|
server->Cypher(text, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Crypto::setRC4Key(int64 key) noexcept
|
||||||
|
{
|
||||||
|
rc4_key = key;
|
||||||
|
|
||||||
|
if (key > 0) {
|
||||||
|
encrypted = true;
|
||||||
|
client = std::make_unique<RC4>(~key);
|
||||||
|
server = std::make_unique<RC4>(key);
|
||||||
|
|
||||||
|
std::array<uchar, 20> temp{};
|
||||||
|
client->Cypher(temp.data(), 20);
|
||||||
|
server->Cypher(temp.data(), 20);
|
||||||
|
} else {
|
||||||
|
encrypted = false;
|
||||||
|
client.reset();
|
||||||
|
server.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
35
source/common/crypto/crypto.h
Normal file
35
source/common/crypto/crypto.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (C) 2007-2025 EQ2EMulator
|
||||||
|
// Licensed under GPL v3
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "rc4.h"
|
||||||
|
#include "../types.h"
|
||||||
|
|
||||||
|
class Crypto
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Crypto() noexcept = default;
|
||||||
|
~Crypto() = default;
|
||||||
|
|
||||||
|
static int64 RSADecrypt(uchar* text, int16 size) noexcept;
|
||||||
|
void RC4Encrypt(uchar* text, int32 size) noexcept;
|
||||||
|
void RC4Decrypt(uchar* text, int32 size) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]] int64 getRC4Key() const noexcept { return rc4_key; }
|
||||||
|
void setRC4Key(int64 key) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]] bool isEncrypted() const noexcept { return encrypted; }
|
||||||
|
void setEncrypted(bool in_val) noexcept { encrypted = in_val; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<RC4> server{};
|
||||||
|
std::unique_ptr<RC4> client{};
|
||||||
|
bool encrypted{false};
|
||||||
|
int64 rc4_key{0};
|
||||||
|
std::mutex m_crypto_mutex{};
|
||||||
|
};
|
64
source/common/crypto/rc4.cpp
Normal file
64
source/common/crypto/rc4.cpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (C) 2007-2025 EQ2EMulator
|
||||||
|
// Licensed under GPL v3
|
||||||
|
|
||||||
|
#include "rc4.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
static constexpr std::array<uchar, 256> get_init_state() noexcept
|
||||||
|
{
|
||||||
|
std::array<uchar, 256> state{};
|
||||||
|
std::iota(state.begin(), state.end(), 0);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const auto g_init_state = get_init_state();
|
||||||
|
|
||||||
|
RC4::RC4(int64 key) noexcept
|
||||||
|
{
|
||||||
|
Init(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RC4::Init(int64 key) noexcept
|
||||||
|
{
|
||||||
|
m_state = g_init_state;
|
||||||
|
m_x = 0;
|
||||||
|
m_y = 0;
|
||||||
|
|
||||||
|
ulong key_index = 0;
|
||||||
|
ulong state_index = 0;
|
||||||
|
const auto* key_ptr = reinterpret_cast<const uchar*>(&key);
|
||||||
|
|
||||||
|
for (int16 i = 0; i < 256; ++i) {
|
||||||
|
const ulong temp = m_state[i];
|
||||||
|
state_index += key_ptr[key_index] + temp;
|
||||||
|
state_index &= 0xFF;
|
||||||
|
m_state[i] = m_state[state_index];
|
||||||
|
m_state[state_index] = static_cast<uchar>(temp);
|
||||||
|
key_index++;
|
||||||
|
key_index &= 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RC4::Cypher(uchar* data, int32 length) noexcept
|
||||||
|
{
|
||||||
|
uchar key1 = m_x;
|
||||||
|
uchar key2 = m_y;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < length; ++i) {
|
||||||
|
++key1;
|
||||||
|
const uchar key_val1 = m_state[key1];
|
||||||
|
|
||||||
|
key2 += key_val1;
|
||||||
|
const uchar key_val2 = m_state[key2];
|
||||||
|
|
||||||
|
m_state[key1] = key_val2;
|
||||||
|
m_state[key2] = key_val1;
|
||||||
|
|
||||||
|
data[i] ^= m_state[(key_val1 + key_val2) & 0xFF];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_x = key1;
|
||||||
|
m_y = key2;
|
||||||
|
}
|
22
source/common/crypto/rc4.h
Normal file
22
source/common/crypto/rc4.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (C) 2007-2025 EQ2EMulator
|
||||||
|
// Licensed under GPL v3
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../types.h"
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
class RC4
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit RC4(int64 key) noexcept;
|
||||||
|
~RC4() = default;
|
||||||
|
|
||||||
|
void Init(int64 key) noexcept;
|
||||||
|
void Cypher(uchar* data, int32 length) noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<uchar, 256> m_state{};
|
||||||
|
uchar m_x{};
|
||||||
|
uchar m_y{};
|
||||||
|
};
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user