0. 传送门
https://github.com/jeanpeng/Netty4Android.git (欢迎star)
1. 协议的确定
- 协议头——4字节,标识协议体的长度
- 协议体——包括4字节扩展信息+传参,其中扩展信息里包括协议加密类型,传参为key,value键值对类型的数据,数据格式为4字节key长度+key+4字节value长度+value
2.协议加解密
- 客户端随机生成16位密钥,通过RSA非对称加密方式将密钥同步给服务器
- 密钥同步后,使用该密钥通过AES对称加密的方式对协议进行加密,然后进行数据传输
3.协议封装和解封装
package com.**.nettylib.netty.codec;
import com.**.nettylib.constant.NetworkConfig;
import com.**.nettylib.netty.Request;
import com.**.nettylib.netty.util.AESUtils;
import com.**.nettylib.netty.util.ExtendInfo;
import com.**.nettylib.netty.util.GZIPUtils;
import com.**.nettylib.netty.util.KeyManager;
import com.**.nettylib.netty.util.MsgEncryptType;
import com.**.nettylib.netty.util.ProtocolUtil;
import com.**.nettylib.netty.util.RSAUtils;
import java.io.ByteArrayOutputStream;
import java.util.Map;
import java.util.Set;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/**
* Created by james on 2018/7/30.
* 加密协议组包,支持处理粘包和半包
*/
public class MessageEncryptEncoder extends MessageToByteEncoder<Request> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, Request request, ByteBuf byteBuf) throws Exception {
byteBuf.writeBytes(encodeResponse(request));
}
public byte[] encodeResponse(Request request) {
try {
Map<String, String> properties = request.toMap();
Set<Map.Entry<String, String>> propertiesSet = properties.entrySet();
ByteArrayOutputStream bodyStream = new ByteArrayOutputStream();
for (Map.Entry<String, String> property : propertiesSet) {
String propertyName = property.getKey();
String propertyValue = property.getValue();
bodyStream.write(ProtocolUtil.stringToByteArray(propertyName, "utf-8"));
bodyStream.write(ProtocolUtil.stringToByteArray(propertyValue, "utf-8"));
}
byte[] bodyBytes = bodyStream.toByteArray();// 数据部分
bodyStream.close();
ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
ExtendInfo ext = request.getExt();
byte[] extBytes = ext.toExtBytes();
int msgEncryptType = ext.getMsgEncryptType();
if (MsgEncryptType.NONO == msgEncryptType) {
// do noting
} else if (MsgEncryptType.RSA == msgEncryptType) {
bodyBytes = doEncodeOfRSA(bodyBytes);
} else if (MsgEncryptType.AES == msgEncryptType) {
bodyBytes = doEncodeOfAES(bodyBytes);
}
responseStream.write(ProtocolUtil.intToByteArray(bodyBytes.length + extBytes.length));
responseStream.write(extBytes);
responseStream.write(bodyBytes);
byte[] responseBytes = responseStream.toByteArray();// 整个响应包
responseStream.close();
return responseBytes;
} catch (Exception e) {
return null;
}
}
private byte[] doEncodeOfRSA(byte[] bodyBytes) {
// 先压缩,再加密
return RSAUtils.publicEncrypt(GZIPUtils.compress(bodyBytes), NetworkConfig.RSA_PUBLIC_KEY);
}
private byte[] doEncodeOfAES(byte[] bodyBytes) {
String password = KeyManager.aesKey;
// 先压缩,再加密
return AESUtils.encrypt(GZIPUtils.compress(bodyBytes), password);
}
}
package com.**.nettylib.netty.codec;
import com.**.nettylib.netty.util.AESUtils;
import com.**.nettylib.netty.util.ExtendInfo;
import com.**.nettylib.netty.util.GZIPUtils;
import com.**.nettylib.netty.util.KeyManager;
import com.**.nettylib.netty.util.MsgEncryptType;
import com.**.nettylib.netty.util.ProtocolUtil;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDeco