com.vethrfolnir.game.network.mu.crypt.MuEncoder.java Source code

Java tutorial

Introduction

Here is the source code for com.vethrfolnir.game.network.mu.crypt.MuEncoder.java

Source

/**
 * Copyright (C) 2013-2014 Project-Vethrfolnir
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.vethrfolnir.game.network.mu.crypt;

import static com.vethrfolnir.game.network.mu.crypt.MuCryptUtils.GetHeaderSize;
import static com.vethrfolnir.game.network.mu.crypt.MuCryptUtils.GetPacketSize;
import io.netty.buffer.*;

import java.io.File;
import java.nio.ByteOrder;

import com.vethrfolnir.services.assets.AssetManager;

import corvus.corax.*;
import corvus.corax.config.CorvusConfig;

/**
 * @author Vlad
 *
 */
public final class MuEncoder {
    //private static final MuLogger log = MuLogger.getLogger(MuEncoder.class);

    // Internal use
    private static ByteBufAllocator alloc = //UnpooledByteBufAllocator.DEFAULT;
            PooledByteBufAllocator.DEFAULT;

    public static ByteBuf EncodePacket(ByteBuf buff, int serial) {
        int header = GetHeaderSize(buff);
        int packetSize = GetPacketSize(buff);
        int contentSize = packetSize - header;

        int encodedSize = (((contentSize / 8) + (((contentSize % 8) > 0) ? 1 : 0)) * 11) + header;

        int size = header;
        int originalHead = buff.getUnsignedByte(0);

        ByteBuf out = alloc.heapBuffer(encodedSize, encodedSize);

        //buff.writerIndex(buff.writerIndex() + 1);
        short[] Contents = new short[contentSize + 1];
        Contents[0] = (short) serial; // XXX:  Check this

        buff.readerIndex(header - 1);

        buff.setByte(header - 1, serial);

        MuCryptUtils.readAsUByteArray(buff, Contents);

        //System.out.println("Encoding: "+PrintData.printData(Contents));

        size += EncodeBuffer(Contents, out, header, (contentSize + 1));

        out.writerIndex(0);

        // Header
        out.writeByte(originalHead);

        // Size write
        switch (originalHead) {
        case 0xc3:
            out.writeByte(size);
            break;
        case 0xC4:
            out.writeByte(size >> 8);
            out.writeByte(size & 0xFF);
            break;
        }

        out.writerIndex(size);

        return out;
    }

    /**
     * @param contents
     * @param out
     * @param header
     * @param Size
     * @param toServer 
     * @return 
     */
    private static int EncodeBuffer(short[] contents, ByteBuf out, int header, int Size) {
        int i = 0;
        int EncSize = 0;

        while (i < Size) {
            short[] Encrypted = new short[11];

            if (i + 8 < Size) {
                short[] Decrypted = new short[8];
                System.arraycopy(contents, i, Decrypted, 0, 8);
                BlockEncode(Encrypted, Decrypted, 8, MuKeyFactory.getServerToClientPacketEncKeys());
            } else {
                short[] Decrypted = new short[Size - i];
                System.arraycopy(contents, i, Decrypted, 0, Decrypted.length);

                BlockEncode(Encrypted, Decrypted, (Size - i), MuKeyFactory.getServerToClientPacketEncKeys());
            }

            out.writerIndex(header + EncSize);
            for (int j = 0; j < Encrypted.length; j++) {
                out.writeByte(Encrypted[j]);
            }

            i += 8;
            EncSize += 11;
        }

        return EncSize;
    }

    /**
     * @param encrypted
     * @param decrypted
     * @param convertor 
     * @param Size
     * @param Keys
     */
    private static void BlockEncode(short[] OutBuf, short[] InBuf, int Size, long[] Keys) {
        short[] Finale = new short[2];
        Finale[0] = (short) Size;
        Finale[0] ^= 0x3D;
        Finale[1] = 0xF8;

        for (int i = 0; i < Size; i++)
            Finale[1] ^= InBuf[i];

        Finale[0] ^= Finale[1];

        ShiftBytes(OutBuf, 0x48, Finale, 0x00, 0x10);

        //System.err.println("Encode block: ------------------ Size: "+Size);
        //System.err.println(PrintData.printData(InBuf));
        //System.err.println();

        long[] Ring = new long[4];
        char[] CryptBuf = new char[4];

        // Here was a block copy, that wasent really needed
        CryptBuf[0] = convertShort(InBuf[0], InBuf.length > 1 ? InBuf[1] : 0x00);
        CryptBuf[1] = convertShort(InBuf.length > 2 ? InBuf[2] : 0x00, InBuf.length > 3 ? InBuf[3] : 0x00);
        CryptBuf[2] = convertShort(InBuf.length > 4 ? InBuf[4] : 0x00, InBuf.length > 5 ? InBuf[5] : 0x00);
        CryptBuf[3] = convertShort(InBuf.length > 6 ? InBuf[6] : 0x00, InBuf.length > 7 ? InBuf[7] : 0x00);

        Ring[0] = ((Keys[8] ^ (CryptBuf[0])) * Keys[4]) % Keys[0];
        Ring[1] = ((Keys[9] ^ (CryptBuf[1] ^ (Ring[0] & 0xFFFF))) * Keys[5]) % Keys[1];
        Ring[2] = ((Keys[10] ^ (CryptBuf[2] ^ (Ring[1] & 0xFFFF))) * Keys[6]) % Keys[2];
        Ring[3] = ((Keys[11] ^ (CryptBuf[3] ^ (Ring[2] & 0xFFFF))) * Keys[7]) % Keys[3];

        //Buffer.BlockCopy(CryptBuf, 0, InBuf, 0, (int)Size);

        Ring[0] = Ring[0] ^ Keys[8] ^ (Ring[1] & 0xFFFF);
        Ring[1] = Ring[1] ^ Keys[9] ^ (Ring[2] & 0xFFFF);
        Ring[2] = Ring[2] ^ Keys[10] ^ (Ring[3] & 0xFFFF);

        //Current ring here 1d4b 57ae 74ce 8866 
        short[] Shift = new short[4];

        // 4B 1D 00 00 - after block copy must achive this
        //Buffer.BlockCopy(Ring, 0, Shift, 0, 4);
        copyRingArray(Ring[0], Shift);
        ShiftBytes(OutBuf, 0x00, Shift, 0x00, 0x10);
        ShiftBytes(OutBuf, 0x10, Shift, 0x16, 0x02);

        //Buffer.BlockCopy(Ring, 4, Shift, 0, 4);
        copyRingArray(Ring[1], Shift);
        ShiftBytes(OutBuf, 0x12, Shift, 0x00, 0x10);
        ShiftBytes(OutBuf, 0x22, Shift, 0x16, 0x02);

        //Buffer.BlockCopy(Ring, 8, Shift, 0, 4);
        copyRingArray(Ring[2], Shift);
        ShiftBytes(OutBuf, 0x24, Shift, 0x00, 0x10);
        ShiftBytes(OutBuf, 0x34, Shift, 0x16, 0x02);

        //Buffer.BlockCopy(Ring, 12, Shift, 0, 4);
        copyRingArray(Ring[3], Shift);
        ShiftBytes(OutBuf, 0x36, Shift, 0x00, 0x10);
        ShiftBytes(OutBuf, 0x46, Shift, 0x16, 0x02);
    }

    private static void copyRingArray(long ring, short[] shift) {
        short[] ss = intToByteArray((int) ring);
        for (int i = 0; i < ss.length; i++) {
            shift[i] = (short) (ss[i]);
        }
    }

    private static final short[] intToByteArray(int value) { // little endiness
        return new short[] { (short) (value & 0xff), (short) (value >> 8 & 0xff), (short) (value >> 16 & 0xff),
                (short) (value >>> 24) };
    }

    private static char convertShort(int b1, int b2) {
        char result = (char) (b1 & 0xff);
        result |= b2 << 8 & 0xff00;
        return result;
    }

    private static long ShiftBytes(short[] OutBuf, long Arg_4, short[] InBuf, long Arg_C, long Arg_10) {
        long Size = ((((Arg_10 + Arg_C) - 1) / 8) + (1 - (Arg_C / 8)));
        short[] Tmp = new short[20];
        System.arraycopy(InBuf, (int) (Arg_C / 8), Tmp, 0, (int) Size);
        long Var_4 = (Arg_10 + Arg_C) & 0x7;

        if (Var_4 != 0) // Pay attention, too many casts, look for negatives
            Tmp[(int) (Size - 1)] = (short) (Tmp[(int) (Size - 1)] & 0xFF << (int) (8 - Var_4));

        Arg_C &= 0x7;

        ShiftRight(Tmp, (int) Size, (int) Arg_C);
        ShiftLeft(Tmp, (int) Size + 1, (int) (Arg_4 & 0x7));

        if ((Arg_4 & 0x7) > Arg_C)
            ++Size;
        if (Size != 0)
            for (int i = 0; i < Size; ++i)
                OutBuf[(int) (i + (Arg_4 / 8))] = (short) ((byte) (OutBuf[(int) (i + (Arg_4 / 8))] | Tmp[i])
                        & 0xFF);

        return Arg_10 + Arg_4;
    }

    private static void ShiftLeft(short[] Data, int Size, int Shift) {
        if (Shift == 0)
            return;
        for (int i = 1; i < Size; i++)
            Data[Size - i] = (byte) ((Data[Size - i] >> Shift) | ((Data[Size - i - 1]) << (8 - Shift)));

        Data[0] = (short) ((byte) (Data[0] >> Shift) & 0xFF);
    }

    private static void ShiftRight(short[] Data, int Size, int Shift) {
        if (Shift == 0)
            return;
        for (int i = 1; i < Size; i++)
            Data[i - 1] = (byte) ((Data[i - 1] << Shift) | (Data[i] >> (8 - Shift)));

        Data[Size - 1] = (short) ((byte) (Data[Size - 1] << Shift) & 0xFF);
    }

    public static void main(String[] args) {
        Corax.Install(new CoraxBuilder() {

            @Override
            protected void build(Corax corax) {
                CorvusConfig.WorkingDirectory = new File("./dist/GameServer");
                Corax.config().loadDirectory("/config");
                bind(AssetManager.class).as(Scope.Singleton);
                ;
            }
        });

        MuKeyFactory.parse();
        System.out.println("");

        //byte[] data = PacketUtils.hex2Bytes("C3 44 F3 03 42 E6 33 00 00 00 00 00 00 00 FA 00 00 00 00 00 00 01 25 84 0A 00 2D 00 32 00 12 00 28 00 56 00 56 00 59 00 59 00 C8 00 C8 00 10 00 20 00 12 00 B0 B4 1D 00 03 00 00 00 04 00 00 00 00 00 04 00");
        byte[] data = PacketUtils.hex2Bytes(
                "C4 00 2D 01 F3 10 03 00 00 00 12 00 00 10 00 FF FF FF FF FF 0C 14 08 1E 00 00 D0 00 FF FF FF FF FF 0D 14 10 1E 00 00 D0 00 FF FF FF FF");
        ByteBuf buff = Unpooled.buffer().order(ByteOrder.LITTLE_ENDIAN);
        buff.writeBytes(data);

        ByteBuf out = EncodePacket(buff, 0x02);

        byte[] arr = new byte[out.readableBytes()];
        out.readBytes(arr);

        //System.out.println(PrintData.printData(out.nioBuffer()));
        //System.out.println("C3-65-22-EF-31-62-4B-D5-32-2F-B1-AA-9F-45-1B-08-45-D2-96-92-B1-51-37-02-45-1B-1F-83-13-D1-F3-9C-E6-67-52-9C-F7-0F-7C-CD-9B-E1-EC-B4-E8-DD-3D-33-0D-44-C2-73-52-48-4E-CD-F8-98-77-44-8B-99-FA-64-71-A6-FD-C8-35-92-35-B9-95-3D-A2-3C-81-C5-F0-0F-4E-1D-F0-81-34-72-2B-E8-C9-FC-36-05-31-36-80-D0-80-BB-0C-C2-FC");
        System.out.println("C3-0D-FE-53-65-66-18-AB-51-01-C1-4D-77");
        System.out.println(PacketUtils.byteArrayToHex(arr).toUpperCase());
    }
}