Skip to content

encrypt

Utilities to handle EO data encryption.

interleave(data)

Interleaves a sequence of bytes. When encrypting EO data, bytes are "woven" into each other.

Used when encrypting packets and data files.

Example
[0, 1, 2, 3, 4, 5] -> [0, 5, 1, 4, 2, 3]

This is an in-place operation.

Parameters:

Name Type Description Default
data bytearray

The data to interleave.

required
Source code in src/eolib/encrypt/encryption_utils.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def interleave(data: bytearray) -> None:
    """
    Interleaves a sequence of bytes. When encrypting EO data, bytes are "woven" into each other.

    Used when encrypting packets and data files.

    Example:
        ```
        [0, 1, 2, 3, 4, 5] -> [0, 5, 1, 4, 2, 3]
        ```

    This is an in-place operation.

    Args:
        data (bytearray): The data to interleave.
    """
    buffer = bytearray(len(data))
    i = 0
    ii = 0

    while i < len(data):
        buffer[i] = data[ii]
        i += 2
        ii += 1

    i -= 1

    if len(data) % 2 != 0:
        i -= 2

    while i >= 0:
        buffer[i] = data[ii]
        i -= 2
        ii += 1

    data[:] = buffer

deinterleave(data)

Deinterleaves a sequence of bytes. This is the reverse of interleave.

Used when decrypting packets and data files.

Example
[0, 1, 2, 3, 4, 5] -> [0, 2, 4, 5, 3, 1]

This is an in-place operation.

Parameters:

Name Type Description Default
data bytearray

The data to deinterleave.

required
Source code in src/eolib/encrypt/encryption_utils.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def deinterleave(data: bytearray) -> None:
    """
    Deinterleaves a sequence of bytes. This is the reverse of interleave.

    Used when decrypting packets and data files.

    Example:
        ```
        [0, 1, 2, 3, 4, 5] -> [0, 2, 4, 5, 3, 1]
        ```

    This is an in-place operation.

    Args:
        data (bytearray): The data to deinterleave.
    """
    buffer = bytearray(len(data))
    i = 0
    ii = 0

    while i < len(data):
        buffer[ii] = data[i]
        i += 2
        ii += 1

    i -= 1

    if len(data) % 2 != 0:
        i -= 2

    while i >= 0:
        buffer[ii] = data[i]
        i -= 2
        ii += 1

    data[:] = buffer

flip_msb(data)

Flips the most significant bits of each byte in a sequence of bytes. (Values 0 and 128 are not flipped.)

Used when encrypting and decrypting packets.

Example
[0, 1, 127, 128, 129, 254, 255] -> [0, 129, 255, 128, 1, 126, 127]

This is an in-place operation.

Parameters:

Name Type Description Default
data bytearray

The data to flip most significant bits on.

required
Source code in src/eolib/encrypt/encryption_utils.py
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def flip_msb(data: bytearray) -> None:
    """
    Flips the most significant bits of each byte in a sequence of bytes.
    (Values 0 and 128 are not flipped.)

    Used when encrypting and decrypting packets.

    Example:
        ```
        [0, 1, 127, 128, 129, 254, 255] -> [0, 129, 255, 128, 1, 126, 127]
        ```

    This is an in-place operation.

    Args:
        data (bytearray): The data to flip most significant bits on.
    """
    for i in range(len(data)):
        if data[i] & 0x7F != 0:
            data[i] = data[i] ^ 0x80

swap_multiples(data, multiple)

Swaps the order of contiguous bytes in a sequence of bytes that are divisible by a given multiple value.

Used when encrypting and decrypting packets and data files.

Example
multiple = 3
[10, 21, 27] -> [10, 27, 21]

This is an in-place operation.

Parameters:

Name Type Description Default
data bytearray

The data to swap bytes in.

required
multiple int

The multiple value.

required

Raises: ValueError: If multiple is less than 1.

Source code in src/eolib/encrypt/encryption_utils.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def swap_multiples(data: bytearray, multiple: int) -> None:
    """
    Swaps the order of contiguous bytes in a sequence of bytes that are divisible by a given
    multiple value.

    Used when encrypting and decrypting packets and data files.

    Example:
        ```
        multiple = 3
        [10, 21, 27] -> [10, 27, 21]
        ```

    This is an in-place operation.

    Args:
        data (bytearray): The data to swap bytes in.
        multiple (int): The multiple value.
    Raises:
        ValueError: If multiple is less than 1.
    """
    if multiple < 0:
        raise ValueError("multiple must be a positive number")

    if multiple == 0:
        return

    sequence_length = 0

    for i in range(len(data) + 1):
        if i != len(data) and data[i] % multiple == 0:
            sequence_length += 1
        else:
            if sequence_length > 1:
                for ii in range(sequence_length // 2):
                    b = data[i - sequence_length + ii]
                    data[i - sequence_length + ii] = data[i - ii - 1]
                    data[i - ii - 1] = b

            sequence_length = 0

server_verification_hash(challenge)

This hash function is used by the game client to verify communication with a genuine server during connection initialization.

Parameters:

Name Type Description Default
challenge int

The challenge value sent by the client. Should be no larger than 11,092,110.

required

Returns:

Name Type Description
int int

The hashed challenge value.

Remarks
  • The client sends an integer value to the server in the INIT_INIT client packet, where it is referred to as the challenge.
  • The server hashes the value and sends the hash back in the INIT_INIT server packet.
  • The client hashes the value and compares it to the hash sent by the server.
  • If the hashes don't match, the client drops the connection.
Warning
  • Oversized challenges may result in negative hash values, which cannot be represented properly in the EO protocol.
See Also
Source code in src/eolib/encrypt/server_verification_utils.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def server_verification_hash(challenge: int) -> int:
    """
    This hash function is used by the game client to verify communication with a genuine server
    during connection initialization.

    Args:
        challenge (int): The challenge value sent by the client.
                         Should be no larger than 11,092,110.

    Returns:
        int: The hashed challenge value.

    Remarks:
        - The client sends an integer value to the server in the `INIT_INIT` client packet, where it
          is referred to as the `challenge`.
        - The server hashes the value and sends the hash back in the `INIT_INIT` server packet.
        - The client hashes the value and compares it to the hash sent by the server.
        - If the hashes don't match, the client drops the connection.

    Warning:
        - Oversized challenges may result in negative hash values, which cannot be represented
          properly in the EO protocol.

    See Also:
        - [`InitInitClientPacket.challenge`][eolib.protocol._generated.net.client.InitInitClientPacket.challenge]
        - [`InitInitServerPacket.ReplyCodeDataOk.challenge_response`][eolib.protocol._generated.net.server.InitInitServerPacket.ReplyCodeDataOk.challenge_response]
    """
    challenge += 1
    return (
        110905
        + (_mod(challenge, 9) + 1) * _mod(11092004 - challenge, ((challenge % 11) + 1) * 119) * 119
        + _mod(challenge, 2004)
    )