简单的网络数据加密算法

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • 实时消息协议---流的分块 版权声明: 版权(c)2009 Adobe系统有限公司。全权所有。 摘要: 本备忘录描...
    一个人zy阅读 1,895评论 0 9
  • 这篇文章主要讲述在Mobile BI(移动商务智能)开发过程中,在网络通信、数据存储、登录验证这几个方面涉及的加密...
    雨_树阅读 2,392评论 0 6
  • Teredo 原理概述 http://www.ipv6bbs.cn/thread-144-1-1.html (出处...
    我是叶问小盆友阅读 1,964评论 0 1
  • 这里先简单介绍单向散列函数、消息摘要和哈希碰撞的的概念 单向散列函数: 将任意长度的信息转换为较短的固定长度的值,...
    坤_7a1e阅读 3,487评论 0 0