简单的网络数据加密算法

2019-11-17  本文已影响0人  狐度计算

在客户端和服务端交互数据时,经常会用到网络数据加密,以免被抓包后就能直接看出其中的内容。但是越复杂的加解密,对性能的要求就越高,这对于网络交互频繁的场景来说,开销未免过大,所以在这里写了一个比较简单的网络加密,使用的语言是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位,其后才是数据位

上一篇下一篇

猜你喜欢

热点阅读