4

I would like to ask if you have any idea or approach to reverse engineer a decryption algorithm to find the opposite encryption function. I do have all required keys and fields and of course the decryption source code, which I reverse engineered already.

I have analyzed the code and kinda know how it works but can`t figure out how to reverse (in the sense of undoing the encryption of) it.

The following information is available to me:

// I have all these fields (filled correctly)

    public byte[] Keychain;
    public uint Step, Mul, HeaderXor, Key;

The decryption function looks like this:

public void Decrypt(byte[] packet) {
        fixed (byte* pp = packet, pk = Keychain) {
            uint size = (uint)GetPacketSize(packet);
            uint header = (first) ? /* Checks if it is a partial packet (It isnt!)*/
                0x000eb7e2 :
                *((uint*)&pp[0]) ^ HeaderXor; 
                // HeaderXor is an unsigned int
                // It also changes after each decryption and if the key changes

            if (first) 
                first = false;

            uint token = *((uint*)&pp[0]);
            *((uint*)&pp[0]) = header;
            token &= 0x3FFF;    // Get only last 14 bits
            token *= Mul * 4;   
            // Mul is an unsigned int and changes sometimes
            token = *((uint*)&pk[token]);

            uint i, r, t;
            size -= r = (size - 8) & 3; // Make size dividable by 4

            for (i = 8; i < size; i += 4) {
                t = *((uint*)&pp[i]);
                token ^= t;
                *((uint*)&pp[i]) = token;

                t &= 0x3FFF;
                token = *((uint*)&pk[t * Mul * 4]);
            }

            t = 0xFFFFFFFF >> 8 * (4 - (int)r);
            token &= t;
            *((uint*)&pp[i]) ^= token; // If something is left over ( if size - 8 == 5 then size & 3 has rest of 1)
            * ((uint*)&pp[4]) = 0;

            Step++;
            Step &= 0x3FFF;
            HeaderXor = *((uint*)&pk[Step * Mul * 4]);
        }
    }

Example results:

// Encrypted data
// 5b 54 34 23
// cc c2 5a a3
// 81 7e d6 27
// 36 c4 8f 36
// b9 3b 6f ce
// f4 8e 72 5b
// 
// Decrypted data
// e2 b7 18 00
// 00 00 00 00
// be 00 56 00
// 2f 00 58 00
// 30 00 59 00
// 31 00 01 00

So, do you have any approach ? Maybe this source code can offer some more informations, but its Server-To-Client:

https://bitbucket.org/dignityteam/minerva/src/e149a219b6783070de71820ea359f1b27cebda63/src/ObjectBuddy/Cryption.cs?at=develop&fileviewer=file-view-default

I think, the Server-To-Client encryption is not the right thing. The decryption code I posted above does returns right results but is not the same as you can see at the linked page.

1 Answer 1

5

Good news, You're lucky!

What you're facing in front of you is a stream cipher. Why is that good? because the way stream ciphers are built makes them extremely easy to reverse - the decryption and encryption functions of stream ciphers are actually the same function.

A stream cipher is a symmetric key cipher where plaintext digits are combined with a pseudorandom cipher digit stream (keystream). In a stream cipher each plaintext digit is encrypted one at a time with the corresponding digit of the keystream, to give a digit of the ciphertext stream. Since encryption of each digit is dependent on the current state of the cipher, it is also known as state cipher. In practice, a digit is typically a bit and the combining operation an exclusive-or (XOR).

Stream ciphers are basically generating a sequence (or a stream) of bytes, and those bytes are mixed with the message in a byte-per-byte fashion, nearly always using a XOR operation. That's also the case with your function, see the line token ^= t;. Since two XOR operations with the same value cancel each other, XORing a byte of the encrypted message with the same stream again on the receiving end will actually decrypt it.

If you have the keys and all input needed to generate the stream in the first place, simply applying the same function again will provide you with the original message.

6
  • Thanks for these informations. I will try to run the same function on this decrypted data. I will keep you up to date.
    – bitQUAKE
    Commented Sep 10, 2016 at 21:19
  • Hi, I tried to convert it back. You are absolutely right, these cipher algorithms do use the same algorithm to en/decrypt. But in my case there was a rapidly changing key between server and client. I used the algorithm from decryption to rebuild the next key and it works pretty good now :)
    – bitQUAKE
    Commented Sep 13, 2016 at 18:31
  • Stream ciphers must be in sync with each other to gerentee they generate the same sequence I both ends. This is done by either :-) sending the sync with the message or b) guessing based on previous location and trying several values. I can elaborate on that if you're interested with N edit
    – NirIzr
    Commented Sep 13, 2016 at 18:35
  • What do you mean by: I can elaborate on that if you're interested with N edit ? :)
    – bitQUAKE
    Commented Sep 13, 2016 at 18:42
  • Sorry, with an edit. I meant I can edit my answer and add more info about that
    – NirIzr
    Commented Sep 13, 2016 at 18:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.