在客户端和服务端交互数据时,经常会用到网络数据加密,以免被抓包后就能直接看出其中的内容。但是越复杂的加解密,对性能的要求就越高,这对于网络交互频繁的场景来说,开销未免过大,所以在这里写了一个比较简单的网络加密,使用的语言是c#。
这个加密方法是客户端发送到服务端的数据加密,和服务端发送到客户端的数据加密方式不一致的,在简单的基础上增加了一点点安全性。
此示例仅仅只是流程,最终结果是由具体需求而定。
具体流程:
定义:_passArr自定义的秘钥盒数组
客户端发送到服务端:
(1)客户端获取此时的unique_Idx(16进制,这里设置初始为99)
(2)将unique_Idx与_passArr长度进行模运算,获得此时的起始key
(3)将数据包中的每个字节数据与key自加后_passArr长度进行模运算取得的索引值进行'异或'运算
(4)将数据存入结构体
服务端发送到客户端:
(1)服务端将要发送的(协议号*10+子协议号)与与_passArr长度进行模运算,获得此时的起始key
(2)将数据包中的每个字节数据与key自加后_passArr长度进行模运算取得的索引值进行'异或'运算
(3)将数据存入结构体
服务端发送到客户端(1)部分可由服务端和客户端协商好固定算法,只是此处用协议号和子协议号来进行计算。
具体代码实现:
using System;
using System.Collections.Generic;
namespace NetNodeTest
{
class Program
{
//用于存储网络包的结构体
public struct NetPacket
{
public byte[] packet;
public byte mId;
public byte sId;
}
//秘钥盒,可打乱顺序自定义
private static readonly byte[] _passArr =
{
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,
58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,
84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,
108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,
148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,
168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,
188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,
228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,
248,249,250,251,252,253,254,255,
};
//秘钥盒长度
private static UInt16 _len = (UInt16)(_passArr.Length-1);
//默认唯一起始秘钥索引
private static uint unique_Idx = 99;
static void Main(string[] args)
{
byte[] array =
{
8,9,87,91,97,88,92,63
};
Console.Write("原始数据:");
PrintArray(array);
Console.Write("\n");
Console.Write("客户端发送给服务端的加密数据:");
NetPacket packet = C2SPacketSend(array, 1, 2);
PrintArray(packet.packet);
Console.Write("\n");
Console.Write("服务端接收客户端的数据解密:");
PrintArray(C2SPacketReceive(packet).packet);
Console.Write("\n");
Console.Write("服务端发送给客户端加密的数据:");
packet = S2CPacketSend(array, 1, 2);
PrintArray(packet.packet);
Console.Write("\n");
Console.Write("服务端接收客户端的数据解密:");
PrintArray(S2CPacketReceive(packet).packet);
}
//获取唯一id索引,当大于16位后重新回到初始数值,初始索引可以自己定义,这里用99
static UInt16 GetUniIndex()
{
if (unique_Idx > 65536) unique_Idx = 99;
unique_Idx += 1;
return (UInt16)unique_Idx;
}
/*
返回客户端发送给服务端的数据消息
packet:客户端数据包,sId:协议号,mId:子协议号
*/
public static NetPacket C2SPacketSend(byte[] packet, byte sId, byte mId)
{
UInt16 index = GetUniIndex(); //获取唯一id,每次获取后唯一id都会往上加1
uint key = (UInt16)(index % _len); //将获取的唯一id与len进行模运算获得秘钥索引key
NetPacket c2SPacket;
c2SPacket.packet = new byte[packet.Length + 2];
c2SPacket.packet[0] = (byte)(index >> 8); //右移8位,取出高8位放入(秘钥key为16位,无法放入字节数组中,则右移8位后取高8位,放入数据包索引0的位置,用于服务端获取索引值解密)
c2SPacket.packet[1] = (byte) index; //直接舍弃高8位放入(放入低八位时直接强制转换,舍去高8位,放入数据包索引1的位置,用于服务端获取索引值解密)
c2SPacket.sId = sId;//存入协议号
c2SPacket.mId = mId;//存子协议号
for (int i = 2; i < c2SPacket.packet.Length; i++, key = ((key + 1) % _len))
{
c2SPacket.packet[i] = (byte)(packet[i-2] ^ _passArr[key]);//对数据包的每个字节与秘钥盒对应的key的索引进行异或(加密)
}
return c2SPacket;
}
/*
返回客户端发送给服务端解密后的数据消息
packet:接收客户端数据包
*/
public static NetPacket C2SPacketReceive(NetPacket netPacket)
{
UInt16 index = (UInt16)(netPacket.packet[0] << 8 | netPacket.packet[1]); //将秘钥包的0索引左移8位,得到高8位是0的16进制数,再与低8(索引1)位作'与'运算,得出整个16位index
uint key = (UInt16) (index%_len);//将获取的唯一id与len进行模运算获得秘钥索引key
NetPacket c2SPacket;
c2SPacket.packet = new byte[netPacket.packet.Length - 2];
c2SPacket.sId = netPacket.sId;//存入协议号
c2SPacket.mId = netPacket.mId;//存子协议号
for (int i = 0; i < c2SPacket.packet.Length; i++, key = ((key + 1) % _len))
{
c2SPacket.packet[i] = (byte)(netPacket.packet[i+2] ^ _passArr[key]);//对数据包的每个字节与秘钥盒对应的key的索引进行异或(解密)
}
return c2SPacket;
}
/*
返回服务端发送给客户端解密后的数据消息
packet:接收服务端数据包
*/
public static NetPacket S2CPacketReceive(NetPacket netPacket)
{
uint key = (UInt16)((netPacket.sId * 10 + netPacket.mId) % _len); //key由前后端定好的规则算出(此处的sId和mId分别为用于前后端通信,收发数据包的协议号和子协议号)
NetPacket s2CPacket;
s2CPacket.packet = new byte[netPacket.packet.Length];
s2CPacket.sId = netPacket.sId;//存入协议号
s2CPacket.mId = netPacket.mId;//存子协议号
for (int i = 0; i < s2CPacket.packet.Length; i++, key = (key + 1) % _len)
{
s2CPacket.packet[i] = (byte)(netPacket.packet[i] ^ _passArr[key]);//对数据包的每个字节与秘钥盒对应的key的索引进行异或(解密)
}
return s2CPacket;
}
/*
返回服务端发送给客户端解密后的数据消息
packet:接收服务端数据包
*/
public static NetPacket S2CPacketSend(byte[] packet, byte sId, byte mId)
{
uint key = (UInt16)((sId * 10 + mId) % _len); //key由前后端定好的规则算出(此处的sId和mId分别为用于前后端通信,收发数据包的协议号和子协议号)
NetPacket s2CPacket;
s2CPacket.sId = sId;//存入协议号
s2CPacket.mId = mId;//存子协议号
s2CPacket.packet = new byte[packet.Length];
for (int i = 0; i < s2CPacket.packet.Length; i++, key = (key + 1) % _len)
{
s2CPacket.packet[i] = (byte)(packet[i] ^ _passArr[key]);//对数据包的每个字节与秘钥盒对应的key的索引进行异或(加密)
}
return s2CPacket;
}
//打印数组
public static void PrintArray(byte[] packet)
{
foreach (var value in packet)
{
Console.Write(value + ",");
}
}
}
}
结果如下:
打印结果.png
ps:客户端发送给服务端数据的前2位分别是index的高8位和低8位,其后才是数据位
网友评论