eq2go/old/common/rc4.hpp
2025-08-06 19:00:30 -05:00

90 lines
2.3 KiB
C++

// Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) - GPL v3 License
#pragma once
#include <array>
#include <cstdint>
#include <cstring>
// RC4 stream cipher implementation for cryptographic operations
class RC4
{
public:
// Initialize RC4 cipher with 64-bit key value
RC4(std::int64_t key)
{
if (!init_state_initialized) {
for (std::int16_t i = 0; i < 256; i++)
init_state[i] = static_cast<std::uint8_t>(i);
init_state_initialized = true;
}
Init(key);
}
// Destructor - cleanup cipher state
~RC4() = default;
// Initialize or reinitialize cipher with new key
void Init(std::int64_t key)
{
// Copy initial state array to working state
std::memcpy(state.data(), init_state.data(), 256);
x = 0;
y = 0;
// Key scheduling algorithm (KSA)
std::uint32_t key_index = 0;
std::uint32_t state_index = 0;
auto* key_bytes = reinterpret_cast<std::uint8_t*>(&key);
for (std::int16_t i = 0; i < 256; i++) {
std::uint32_t temp = state[i];
state_index += key_bytes[key_index] + temp;
state_index &= 0xFF;
state[i] = state[state_index];
state[state_index] = static_cast<std::uint8_t>(temp);
key_index++;
key_index &= 7; // Wrap around 8-byte key
}
}
// Encrypt/decrypt data buffer using RC4 stream cipher
// RC4 is symmetric - same operation for encrypt and decrypt
void Cypher(std::uint8_t* buffer, std::int32_t length)
{
std::int32_t offset = 0;
std::uint8_t key1 = x;
std::uint8_t key2 = y;
if (length > 0) {
do {
// Pseudo-random generation algorithm (PRGA)
key1++;
std::uint8_t key_val1 = state[key1];
key2 += key_val1;
std::uint8_t key_val2 = state[key2];
// Swap state values
state[key1] = key_val2;
state[key2] = key_val1;
// XOR buffer byte with keystream byte
buffer[offset++] ^= state[(key_val1 + key_val2) & 0xFF];
} while (offset < length);
}
// Update cipher state
x = key1;
y = key2;
}
private:
std::array<std::uint8_t, 256> state; // RC4 internal state array
std::uint8_t x; // First state index
std::uint8_t y; // Second state index
// Static initialization state shared across all instances
static inline bool init_state_initialized = false;
static inline std::array<std::uint8_t, 256> init_state;
};