KDX Protocol: Difference between revisions

From Hotline Wiki
Jump to navigationJump to search
(TCP packet algorithm)
No edit summary
Line 3: Line 3:


= Algorithms =
= Algorithms =
The following is a list of algorithms discovered in KDX. While I do my best to document and reimplement the algorithms, their purposes, until KDX is fully reimplemented, are only speculation and are subject to clarification as I progress in development.
- Schala
== TCP (client/server based) packets ==
== TCP (client/server based) packets ==
A C implementation of this can be found [https://aluigi.altervista.org/papers/kdxalgo.h here] while a Rust implementation can be found below.
A C implementation of this can be found [https://aluigi.altervista.org/papers/kdxalgo.h here] while a Rust implementation can be found below.

Revision as of 03:31, 11 April 2025

Protocol Overview

Haxial KDX was a non-compatible Hotline clone developed between 2001 and 2005 by Australian-based company Haxial Software Pty. Ltd. It provides everything the Hotline protocol does along with its own array of features such as remote desktop administration, detailed file access, user account classes, custom user icons, multiple public chat rooms, IRC bridging, server categories and accounts on the tracker, and voice chat. Most notable is its extensive use of mixing known standard cryptographic hashes and encryption algorithms of the time (MD5, CRC32, Twofish, etc.) as well as some of its own proprietary algorithms. KDX's news system is a hybrid of Hotline's threaded news system and it's classic bulletin board-style news feed: a threaded news system where each category is its own bulletin board-style feed.

Algorithms

The following is a list of algorithms discovered in KDX. While I do my best to document and reimplement the algorithms, their purposes, until KDX is fully reimplemented, are only speculation and are subject to clarification as I progress in development. - Schala

TCP (client/server based) packets

A C implementation of this can be found here while a Rust implementation can be found below.

  • The function takes a 32-bit key, a data buffer, and its length in bytes
  • The data length is converted from bytes to 32-bit words (dividing by 4)
  • The data buffer is treated as an array of 32-bit integers

For each 32-bit word:

  • The key is updated by left-shifting and adding a constant (0x4878)
  • The data word is XORed with the key (after converting byte order if needed)

The final key value is returned

use bytemuck::{cast_slice, cast_slice_mut};

pub enum CryptError {
    Align(u8, usize),     // expected, got
    Length(usize, usize), // expected, got
}

pub fn tcp_packet_crypt(key: u32, data: &[u8]) -> Result<Vec<u8>, CryptError> {
    if data.len() & 3 != 0 {
        return Err(CryptError::Align(4, data.len() & 3));
    }

    let mut output = vec![0u8; data.len()];
    let out_blocks: &mut [u32] = cast_slice_mut(&mut output[..]);
    let mut key = key;
    let in_blocks: &[u32] = cast_slice(data);

    in_blocks
        .iter()
        .zip(out_blocks.iter_mut())
        .for_each(|(&input, out)| {
            key = key.wrapping_shl(1).wrapping_add(0x4878); // 'Hx'
            *out = input ^ key.to_be();
        });

    Ok(output)
}