90 lines
2.3 KiB
C++
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;
|
|
}; |