【23】万魂杀服务器开发之CS之间通信数据的加解密、CRC校验防止篡改数据

in 编程
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
package com.loncent.network.mina.codec;

import com.loncent.network.mina.session.MinaConnect;
import com.loncent.network.mina.utils.NetConst;
import com.loncent.server.core.CmdPkg;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;

public class ClientProtocolCodec {

    static public final int ENC_KEY = 0x5a21f;
    private final Log log = LogFactory.getLog(ClientProtocolCodec.class);

    public IoBuffer encode(CmdPkg pkg, IoSession session) {
        if (pkg == null) {
            return null;
        }
        MinaConnect minaConnect = (MinaConnect) session.getAttribute(NetConst.NET_SESSION);
        if (minaConnect == null) {
            log.error("连接尚未建立成功,不能编码消息!");
            return null;
        }
        byte[] data = this.addCompressSignByte(pkg.toByteArray());
        int resume = 0;
        int s_pkgKey = minaConnect.getS_PkgKey();
        byte s_crc1 = (byte) ((~(s_pkgKey % 0x100)) & 0xff);
        for (int i = 0, len = data.length; i < len; i++) {
            resume += data[i];
            data[i] = encryptByte(data[i], s_crc1);
        }
        byte s_crc2 = (byte) ((resume % 0x100) & 0xff);

        byte[] tmpb = new byte[data.length + 1];
        System.arraycopy(data, 0, tmpb, 1, data.length);
        tmpb[0] = encryptByte(s_crc2, s_crc1);
//        log.error("发送日志 commandid:"+ pkg.getCommandID() +  ":s_pkgKey:" + s_pkgKey + " s_crc1:" + s_crc1 + " s_crc2=" + s_crc2 + " resume:"+resume + " tmpb[0]="+tmpb[0] );

        tmpb = addHead(tmpb);

        IoBuffer buffer = IoBuffer.allocate(tmpb.length);
        buffer.put(tmpb);
        buffer.flip();
        return buffer;
    }


    public CmdPkg decode(byte[] data, IoSession session) throws Exception {
        if (data == null) {
            return null;
        }

        MinaConnect minaConnect = (MinaConnect) session.getAttribute(NetConst.NET_SESSION);
        if (minaConnect == null) {
            //非玩家请求不处理
            log.error("连接尚未建立成功,不能解码消息!");
            return null;
        }

        int r_pkgKey = minaConnect.getR_PkgKey();
        int resume = 0;
        byte s_crc1 = (byte) ((~(r_pkgKey % 0x100)) & 0xff);
        for (int i = 1, len = data.length; i < len; i++) {
            data[i] = decryptByte(data[i], s_crc1);
            resume += data[i];
        }

        data[0] = decryptByte(data[0], s_crc1);
        byte s_crc2 = (byte) ((resume % 0x100) & 0xff);

//        log.debug("r_pkgKey:" + r_pkgKey);
        if (data[0] != s_crc2) {
            log.error("解码数据包时错误.");
            throw new Exception("attempt to modify netpkg ,break conn.  r_pkgKey:" + r_pkgKey);
        }

        //移除CRC校验位和压缩位
        byte[] tmpb = new byte[data.length - 2];
        System.arraycopy(data, 2, tmpb, 0, data.length - 2);
        //tmpb = removeCompressSignByte(tmpb);
        return new CmdPkg(tmpb);
    }

    private byte encryptByte(byte b, byte key) {
        int i = b & 0xff;
        i = (i + key) % 0x100;
        b = (byte) ((~(i & 0xff)) & 0xff);
        b = (byte) ((b ^ ((key << 4) | (key >>> 4))) & 0xff);
        return b;
    }

    private byte decryptByte(byte b, byte key) {
        b = (byte) ((b ^ ((key << 4) | (key >>> 4))) & 0xff);
        b = (byte) ((~b) & 0xff);
        int i = b & 0xff;
        i = (i + 256 - key) % 0x100;
        return (byte) (i & 0xff);
    }

    /**
     * 增加压缩字节标志
     */
    private byte[] addCompressSignByte(byte[] buf) {
        byte[] temp = new byte[buf.length + 1];
        System.arraycopy(buf, 0, temp, 1, buf.length);
        return temp;
    }

    /**
     * 移除压缩位
     *
     * @param buf
     * @return
     */
    private byte[] removeCompressSignByte(byte[] buf) {
        byte[] temp = new byte[buf.length - 1];
        System.arraycopy(buf, 1, temp, 0, temp.length);
        return temp;
    }

    /**
     * 添加包头
     *
     * @param buf
     * @return
     */
    private byte[] addHead(byte[] buf) {
        byte[] nsd = new byte[buf.length + NetConst.CODE_LENGTH];
        int dlen = buf.length;
        nsd[0] = (byte) ((dlen >> 24) & 0xff);
        nsd[1] = (byte) ((dlen >> 16) & 0xff);
        nsd[2] = (byte) ((dlen >> 8) & 0xff);
        nsd[3] = (byte) (dlen & 0xff);
        System.arraycopy(buf, 0, nsd, NetConst.CODE_LENGTH, buf.length);
        return nsd;
    }
}

CS之间通信数据的加解密、CRC校验防止篡改数据。

------------------------------------------------------------------------

package com.loncent.network.mina.session;

import com.google.protobuf.Message;
import com.loncent.network.mina.codec.ClientProtocolCodec;
import com.loncent.server.core.CmdPkg;
import com.loncent.server.game.gmtool.GameMaster;
import com.loncent.server.thirdparty.ServerStatusManager;
import com.loncent.server.wxgame.player.WXPlayerCharacter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;

import java.net.InetSocketAddress;

public class MinaConnect implements IConnect {

    protected Log logger = LogFactory.getLog(getClass());
    protected IoSession session;
    private InetSocketAddress remoteAddress;
    private int remoteType;
    private String remoteName;
    private int remoteSid;
    private String remoteGroup;
    private long ping;
    private long roleId;
    private boolean connected;
    private long id = -1L;
    private int s_pkgKey = ClientProtocolCodec.ENC_KEY, r_pkgKey = ClientProtocolCodec.ENC_KEY;
    private WXPlayerCharacter player;
    private GameMaster gameMaster;


    public MinaConnect() {
        this.ping(System.currentTimeMillis());
        player = new WXPlayerCharacter(true);
        player.setSession(this);
    }

    public MinaConnect(IoSession session) {
        this.session = session;
    }

    public String getRemoteName() {
        return this.remoteName;
    }

    public void setRemoteName(String remoteName) {
        this.remoteName = remoteName;
    }

    public InetSocketAddress getRemoteAdress() {
        return this.remoteAddress;
    }

    public void setRemoteAddress(InetSocketAddress soketAddress) {
        this.remoteAddress = soketAddress;
    }

    public String getRemoteIp() {
        if (this.remoteAddress == null && this.session != null) {
            this.remoteAddress = (InetSocketAddress) this.session.getRemoteAddress();
        }

        return this.remoteAddress == null ? null : this.remoteAddress.getAddress().getHostAddress();
    }

    public GameMaster getGameMaster() {
        return gameMaster;
    }

    public void setGameMaster(GameMaster gameMaster) {
        this.gameMaster = gameMaster;
    }

    public String getRemoteGroup() {
        return this.remoteGroup;
    }

    public void setRemoteGroup(String remoteGroup) {
        this.remoteGroup = remoteGroup;
    }

    public int getRemoteSTypeid() {
        return this.remoteSid;
    }

    public void setRemoteSTypeid(int remoteSid) {
        this.remoteSid = remoteSid;
    }

    public int getRemoteSType() {
        return this.remoteType;
    }

    public void setRemoteSType(int type) {
        this.remoteType = type;
    }

    public void setConnected(boolean connected) {
        this.connected = connected;
    }

    public boolean isConnect() {
        return this.connected;
    }

    public void send(IoBuffer buf) {
        if (this.session != null) {
            if (this.isConnect() && this.session.isConnected()) {
                this.session.write(buf);
            }

        }
    }

    public void send(Message protobufMsg) {
        if (this.session != null) {
            if (this.isConnect() && this.session.isConnected()) {
                this.session.write(protobufMsg);
            }

        }
    }

    public void send(CmdPkg cmd) {
        if (this.session != null) {
            if (this.isConnect() && this.session.isConnected()) {
                this.session.write(cmd);
                //统计
                ServerStatusManager.instance.incSendBytes(cmd.getData().length);
                ServerStatusManager.instance.incSendCount();
            }

        }
    }

    public Object getAttachment() {
        return this.session;
    }

    public void setAttachment(Object obj) {
        if (obj == null) {
            this.session = null;
        } else {
            if (!(obj instanceof IoSession)) {
                throw new IllegalArgumentException("minaConnect ,obj is not IoSession ,obj=" + obj.getClass().getName());
            }

            this.session = (IoSession) obj;
            this.setId(this.session.getId());
        }

    }

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public void close() {
        if (this.session != null) {
            //this.session.close(true);
            session.closeNow();
        }

    }

    public void ping(long time) {
        this.ping = time;
    }

    public long getPing() {
        return this.ping;
    }

    public int getWriteSize() {
        return this.session != null ? this.session.getWriteRequestQueue().size() : 0;
    }

    public String getInfo() {
        StringBuffer sb = new StringBuffer();
        if (this.session == null) {
            return "";
        } else {
            this.session.updateThroughput(System.currentTimeMillis(), false);
            sb.append("\n" + this.getRemoteName() + "\n");
            sb.append("\t[WriteRequestQueue()] :" + this.session.getWriteRequestQueue().size() + " ");
            sb.append("[WrittenBytes] :" + this.session.getWrittenBytes() + " ");
            sb.append("[WrittenBytesThroughput] :" + (int) this.session.getWrittenBytesThroughput() + " ");
            sb.append("[WrittenMessages] :" + (int) this.session.getWrittenMessages() + " ");
            sb.append("[WrittenMessagesThroughput] :" + (int) this.session.getWrittenMessagesThroughput() + " ");
            sb.append("\n");
            sb.append("\t[ReadBytes] :" + this.session.getReadBytes() + " ");
            sb.append("[ReadBytesThroughput] :" + (int) this.session.getReadBytesThroughput() + " ");
            sb.append("[ReadMessage]s :" + this.session.getReadMessages() + " ");
            sb.append("[ReadMessagesThroughput] :" + this.session.getReadMessagesThroughput() + " ");
            sb.append("[ScheduledWriteBytes] :" + this.session.getScheduledWriteBytes() + " ");
            sb.append("[ScheduledWriteMessages] :" + this.session.getScheduledWriteMessages() + "\n");
            return sb.toString();
        }
    }

    public long getRoleId() {
        return this.roleId;
    }

    public void setRoleId(long roleId) {
        this.roleId = roleId;
    }

    public WXPlayerCharacter getPlayer() {
        return player;
    }

    public synchronized int getS_PkgKey()
    {
        s_pkgKey++;
        if (s_pkgKey == Integer.MAX_VALUE) {
            s_pkgKey = ClientProtocolCodec.ENC_KEY;
        }
        return s_pkgKey;
    }

    public synchronized  int getR_PkgKey()
    {
        r_pkgKey++;
        if (r_pkgKey == Integer.MAX_VALUE) {
            r_pkgKey = ClientProtocolCodec.ENC_KEY;
        }
        return r_pkgKey;
    }
}

 

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看