@Override protected void encode(ChannelHandlerContext ctx, Object message, ByteBuf buffer) throws Exception {
final byte[] input = (byte[]) message;
System.out.println("To decode: " + HexTool.toString(input));
final byte[] unencrypted = new byte[input.length];
System.arraycopy(input, 0, unencrypted, 0, input.length);
final byte[] ret = new byte[unencrypted.length + 4];
final byte[] header = send_crypto.getPacketHeader(unencrypted.length);
MapleCustomEncryption.encryptData(unencrypted);
send_crypto.crypt(unencrypted);
System.arraycopy(header, 0, ret, 0, 4);
System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
buffer.writeBytes(ret);
System.out.println("After encode: " + HexTool.toString(ret));
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> message) throws Exception {
DecoderState decoderState = ctx.channel().attr(DECODER_STATE_KEY).get();
if (decoderState == null) {
decoderState = new DecoderState();
ctx.channel().attr(DECODER_STATE_KEY).set(decoderState);
}
if (in.readableBytes() >= 4 && decoderState.packetlength == -1) {
int packetHeader = in.readInt();
if (!PacketEncoder.recvCypher.checkPacket(packetHeader)) {
System.out.println("Invalid packet");
//return;
}
decoderState.packetlength = MapleAESOFB.getPacketLength(packetHeader);
} else if (in.readableBytes() < 4 && decoderState.packetlength == -1) {
return;
}
if (in.readableBytes() >= decoderState.packetlength) {
byte decryptedPacket[] = new byte[decoderState.packetlength];
in.readBytes(decryptedPacket);
System.out.println("Starting decode: " + HexTool.toString(decryptedPacket));
decoderState.packetlength = -1;
PacketEncoder.recvCypher.crypt(decryptedPacket);
MapleCustomEncryption.decryptData(decryptedPacket);
System.out.println("Decoded: " + HexTool.toString(decryptedPacket));
message.add(decryptedPacket);
}
private final static short MAPLE_VERSION = 62;
public static final byte key[] = { 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
(byte) 0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x52,
0x00, 0x00, 0x00 };
public static byte ivRecv[] = { 70, 114, 122, 82 };
public static byte ivSend[] = { 82, 48, 120, 115 };
public static MapleAESOFB send_crypto;
public static MapleAESOFB recvCypher;
static {
ivRecv[3] = (byte) (Math.random() * 255);
ivSend[3] = (byte) (Math.random() * 255);
send_crypto = new MapleAESOFB(key, ivSend, (short) (0xFFFF - MAPLE_VERSION));
recvCypher = new MapleAESOFB(key, ivRecv, MAPLE_VERSION);
}
I just wanted to test the encryption and decryption of data. Unfortunately, everytime I encrypt a packet it becomes a different array of bytes because the IV changes. If I comment the IV crypt part in both client/server I can encrypt on client and decrypt the data on my mocked server.I have a mocked server just replying with a encripted packet, i just want to test the point-to-point encription first and then start with the interation.
If i remove the iv in both mocked server and my client it works.
Something with the iv is messing up with the packet and then the server cant decript it.
However without the encription works...
Btw, i'm not even trying to connect to real server, just a mocked version for now.
IV: 46 72 7A 16IV: 52 30 78 05
Value: 01 0A 0A
Crypt: 3E C1 DA
Decrypt: 16 A8 DB --> This should be 01 0A 0A since we are decrypting. However it prints something else...
IV: 4C CA 74 9F
IV: B9 23 C1 59
package com.maple.br;
import org.junit.BeforeClass;
import org.junit.Test;
import com.maplebr.client.tool.HexTool;
import com.maplebr.client.tool.MapleAESOFB;
public class IVTest {
private final static short MAPLE_VERSION = 62;
public static final byte key[] = { 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, (byte) 0xB4, 0x00, 0x00,
0x00, 0x1B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00 };
public static byte ivRecv[] = { 70, 114, 122, 82 };
public static byte ivSend[] = { 82, 48, 120, 115 };
public static MapleAESOFB send_crypto;
public static MapleAESOFB recvCypher;
@BeforeClass
public static void init() {
ivRecv[3] = (byte) (Math.random() * 255);
ivSend[3] = (byte) (Math.random() * 255);
send_crypto = new MapleAESOFB(key, ivSend.clone(), MAPLE_VERSION);
recvCypher = new MapleAESOFB(key, ivRecv.clone(), MAPLE_VERSION);
}
[USER=196303]TesT[/USER]
public void testIv(){
System.out.println("IV: " + HexTool.toString(recvCypher.getIv()));
System.out.println("IV: " + HexTool.toString(send_crypto.getIv()));
byte test [] = {0x1, 0xA, 0xA};
System.out.println("Value: " + HexTool.toString(test));
byte encripted [] = test.clone();
send_crypto.crypt(encripted);
System.out.println("Crypt: " + HexTool.toString(encripted));
byte unc [] = recvCypher.crypt(encripted);
System.out.println("Decrypt: " + HexTool.toString(unc));//Should print again the AA, right? However it does not..
System.out.println("IV: " + HexTool.toString(recvCypher.getIv()));
System.out.println("IV: " + HexTool.toString(send_crypto.getIv()));
}
}
Thanks! I already know the problem! Now i understand the concept of IV.You are using different IVs for encryption and decryption so there is no way it would decrypt correctly.
Guys, i have fixed the problem with the IV and now i got a question. The algorithm to calculate the packet header on client side v62 is public? If so, could someone link ?
I can see my decripted packet on the server now, however it fails when i try to validate the packet header:
//MapleServerHandler
if (!client.getReceiveCrypto().checkPacket(packetHeader)) {
session.close();
return false;
}
Thank you!
short uRawSeq = in.readShort();
short uDataLen = in.readShort();
short uSeqBase = (short) (((SystemConstants.Client << 8) & 0xFF00));
if (((((((uRawSeq >> 8) ^ (pSocket.m_uSeqRcv >> 16)) & 0xFF) != ((uSeqBase >> 8) & 0xFF))))) {
System.err.println("Incorrect packet header sequencing");
ctx.disconnect();
return;
}
if ( puSeqKey )
v15 = uSeqBase ^ *((_WORD *)puSeqKey + 1);
else
v15 = uSeqBase;
*(_WORD *)v13 = v15;
v16 = v13 + 2;
if ( bEnc )
v17 = v6->m_uOffset ^ v15;
else
v17 = v6->m_uOffset;
*(_WORD *)v16 = v17;
Thanks man!This is how Nexon validates their packets on the server-side:
PHP:short uRawSeq = in.readShort(); short uDataLen = in.readShort(); short uSeqBase = (short) (((SystemConstants.Client << 8) & 0xFF00)); if (((((((uRawSeq >> 8) ^ (pSocket.m_uSeqRcv >> 16)) & 0xFF) != ((uSeqBase >> 8) & 0xFF))))) { System.err.println("Incorrect packet header sequencing"); ctx.disconnect(); return; }
Core client code:
PHP:if ( puSeqKey ) v15 = uSeqBase ^ *((_WORD *)puSeqKey + 1); else v15 = uSeqBase; *(_WORD *)v13 = v15; v16 = v13 + 2; if ( bEnc ) v17 = v6->m_uOffset ^ v15; else v17 = v6->m_uOffset; *(_WORD *)v16 = v17;
public class IVHeaderCheckTest {
public byte iv [] = { 70, 114, 122, 82 };
public MapleAESOFB aes = new MapleAESOFB(Client.MAPLE_KEY, iv, Client.MAPLE_VERSION);
@Before
public void init(){
iv[3] = (byte) (Math.random() * 255);
}
@Test
public void testHeader() {
byte [] header = aes.getPacketHeader(16);
int value = new BigInteger(header).intValue();
System.out.println(value);
boolean result = aes.checkPacket(value);
System.out.println(result);//prints true
Assert.assertTrue("Could not validate the header", result);
}
}
if (!client.getReceiveCrypto().checkPacket(packetHeader)) { session.close();
return false;
}
Hi @Eric.
Thanks for your help, i managed to get in game.
You can find the source here:
You must be registered to see links
However it does not work for MapleLegend and MapleRoyals which was my goal.
You have to send the movement packet to do that.How didn't it work? For mine I got the player to appear in the world but couldn't get them to move around. Did you get somewhere near to that?
I am sending a movement packet but it still not workingOh well
They have some sort of protection in Maple Royals, we cant even check if the server port is open.From what it looks like your packets in "CommonPacketOperations" are missing some stuff. I don't remember exactly but I think for Royals you need to send HWID/MAC in your charSelected. And Legends uses pic for the login.
They have some sort of protection in Maple Royals, we cant even check if the server port is open.