Socket网络通信安全

前言

    为了保证数据的安全性,在客户端服务器进行通信之前要对数据进行一次封装来保证数据的安全,在接受到数据后在进行拆包,就像是送快递之前要把里面的东西给包装好,在接到快点后在拆开.
    压缩工具可以在网上下载ZipHelper开源的压缩帮助类 数据流读取,CRC16,Xor异或加密类可以直接使用 封装和拆包为示例

封装数据包:

* 先判断是否采用压缩,定义了一个ushort的常量,判断数据的长度大于这个常量就进行压缩,否则就不压缩
* 封装的方法采用了先压缩在异或加密最后进行CRC校验
* 完整的数据包是 "包头"+"包体"=完整数据包
* 包头是ushort类型的数据,存放包体的长度
* 包体包括
    * Boll值--压缩的标志--1个字节
    * ushrot类型的--CRC校验码--2个字节
    * 加密后的数据

封装好的数据包格式

拆封数据包

(根据包头的包体长度拿到包体的数据之后进行拆封数据包)

* 封装数据包时是先进行的压缩再异或加密最后CRC校验,拆包时就是反过来的
* 把包体的数据接到一个byte的数组中
* 包体的长度减去三个字节的长度就是经过压缩并异或的数据长度,用一个数组存放真实数据
* 把包体的所有数据都写入流中
* 用一个变量接受压缩标志
* 用一个ushort变量接受crc校验码
* 最后数据流中剩余的就是真实的数据 ,用前面定义好的数组接收
* 接收到真实数据后计算一下接受到的数据的crc校验码,判断传过来的校验码和计算数据的校验码是否一致,不一致就停止操作数据
* crc一致就证明数据是正确的,直接进行异或解密
* 再通过传输过来的压缩标志来进行判断是否有进行过压缩操作,有压缩就进行解压
* 最后拿到了最真实的数据,就通过传输协议进行获取数据

封包

  /// <summary>
    /// 封装数据包
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    private byte[] MakeData(byte[] data)
    {
        byte[] retBuffer = null;
        //1.获取压缩标志
        bool isCompress = data.Length > m_CompressLen ? true : false;
        //2.判断是否需要压缩
        if (isCompress)
            data = ZlibHelper.CompressBytes(data);
        //3.获取真实数据异或加密后的数据
        data = SecurityUtil.Xor(data);
        //4.获取Crc冗余校验码(压缩&&异或)
        ushort crc = Crc16.CalculateCrc16(data);
        Debug.Log("客户端CRC="+crc);
        using (MMO_MemoryStream ms = new MMO_MemoryStream())
        {
            //5.包体长度写入数据流中
            ms.WriteUShort((ushort)(data.Length + 3));
            //6.压缩标志写入数据流中
            ms.WriteBool(isCompress);
            //7.Crc冗余校验码写入数据流中
            ms.WriteUShort(crc);
            //8.Xor加密后的数据写入流中
            ms.Write(data, 0, data.Length);
            //9.获取Make后的完整数据包
            retBuffer = ms.ToArray();
        }
        return retBuffer;
    }

拆包

//存放接受到的队列中的包体(压缩标志|crc|Xor异或&&压缩后的数据(真实数据))
                        byte[] buffer = m_ReceiveQueue.Dequeue();
                        //存放Xor异或&&压缩后的数据
                        byte[] bufferNew = new byte[buffer.Length - 3];
                        //压缩标志
                        bool isCompress = false;
                        //接受过来的Crc校验码
                        ushort crc = 0;
                        //获取实际数据包体和协议编号
                        using (MMO_MemoryStream ms = new MMO_MemoryStream(buffer))
                        {
                            //从数据流中读取压缩标志
                            isCompress = ms.ReadBool();
                            //从数据流中读取Crc校验码
                            crc = ms.ReadUShort();
                            //从数据流中读取Xor加密的数据
                            ms.Read(bufferNew, 0, bufferNew.Length);
                        }
                        //计算传输过来数据的Crc(压缩&&异或)
                        int newCrc = Crc16.CalculateCrc16(bufferNew);
                        //temp
                        Debug.Log("服务器NewCRC=" + newCrc);
                        if (newCrc == crc)
                        {
                            //异或得到原始数据
                            bufferNew = SecurityUtil.Xor(bufferNew);
                            if (isCompress)
                                //对数据进行解压缩
                                bufferNew = ZlibHelper.DeCompressBytes(bufferNew);
                            ushort protoCode = 0;
                            byte[] protoContent = new byte[bufferNew.Length - 2];
                            using (MMO_MemoryStream ms = new MMO_MemoryStream(bufferNew))
                            {
                                //读取协议编号
                                protoCode = ms.ReadUShort();
                                //读取最原始的数据
                                ms.Read(protoContent, 0, protoContent.Length);
                                //派发协议事件
                                EventDispatcher.Instance.Dispatch(protoCode, protoContent);
                            }
                        }
                        else
                        {
                            break;
                        }

Xor异或加密类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Socket Xor加密
/// </summary>
public sealed class SecurityUtil
{
    #region xorScale 异或因子
    /// <summary>
    /// 异或因子
    /// </summary>
    private static readonly byte[] xorScale = new byte[] { 45, 66, 38, 55, 23, 254, 9, 165, 90, 19, 41, 45, 201, 58, 55, 37, 254, 185, 165, 169, 19, 171 };//.data文件的xor加解密因子
    #endregion
    private SecurityUtil()
    {
    }
    /// <summary>
    /// 对数据进行异或
    /// </summary>
    /// <param name="buffer"></param>
    /// <returns></returns>
    public static byte[] Xor(byte[] buffer)
    {
        //xor加密
        int iScaleLen = xorScale.Length;
        for (int i = 0; i < buffer.Length; i++)
        {
            buffer[i] = (byte)(buffer[i] ^ xorScale[i % iScaleLen]);
        }
        return buffer;
    }
}

CRC冗余校验类

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
// C/C++, 利用OpenSSL库对Socket传输进行安全加密(RSA+AES) // 1. 利用RSA安全传输AES生成密钥所需的Seed(32字节) // 2. 利用AES_encrypt/AES_decrypt对Socket上面的业务数据进行AES加密/解密 // --- // * 理论上只需要AES就能保证全部流程,但由于AES加密所需要的AES-KEY是一个结构 // * 这个一个结构,如果通过网络进行传输,就需要对它进行网络编码,OpenSSL里面没有现成的API // * 所以就引入RSA来完成首次安全的传输,保证Seed不会被窃听 // * 同样,只使用RSA也能完成全部流程,但由于RSA的处理效率比AES低, // * 所以在业务数据传输加密上还是使用AES // --- // 下面的代码包含了上述传输加密流程所需的所有步骤(OpenSSL部分) // 在实际的Socket应用开发时,需要将这些步骤插入到Client/Server网络通信的特定阶段 // --- // 为能完成代码的编译和执行,需要先安装OpenSSL执行库及开发库 // 以Debian为例,需要安装openssl 和 libssl-dev // 编译命令: g++ -o rsa-encrypt rsa-encrypt.cpp -lcrypto // --- // 所需的OpenSSL主要的API及功能描述 // 1. RSA_generate_key() 随机生成一个RSA密钥对,供RSA加密/解密使用 // 2. i2d_RSAPublicKey() 将RSA密钥对里面的公钥提出到一个BUF,用于网络传输给对方 // 3. d2i_RSAPublicKey() 将从网络传过来的公钥信息生成一个加密使用的RSA(它里面只有公钥) // 4. RSA_public_encrypt() 使用RSA的公钥对数据进行加密 // 5. RSA_private_decrypt() 使用RSA的私钥对数据进行加密 // 6. AES_set_encrypt_key() 根据Seed生成AES密钥对中的加密密钥 // 7. AES_set_decrypt_key() 根据Seed生成AES密钥对中的解密密钥 // 8. AES_encrypt() 使用AES加密密钥对数据进行加密 // 9. AES_decrypt() 使用AES解密密钥对数据进行解密 // --- // 一个典型的安全Socket的建立流程, 其实就是如何将Server随机Seed安全发给Client // -- C: Client S:Server // C: RSA_generate_key() --> RSAKey --> i2d_RSAPublicKey(RSAKey) --> RSAPublicKey // C: Send(RSAPublicKey) TO Server // S: Recv() --> RSAPublicKey --> d2i_RSAPublicKey(RSAPublicKey) --> RSAKey // S: Rand() --> Seed --> RSA_public_encrypt(RSAKey, Seed) --> EncryptedSeed // S: Send(EncryptedSeed) TO Client // C: Recv() --> EncryptedSeed --> RSA_private_decrypt(RSAKey, EncryptedSeed) --> Seed // --- 到此, Client和Server已经完成完成传输Seed的处理 // --- 后面的流程是它们怎样使用这个Seed来进行业务数据的安全传输 // C: AES_set_encrypt_key(Seed) --> AESEncryptKey // C: AES_set_decrypt_key(Seed) --> AESDecryptKey // S: AES_set_encrypt_key(Seed) --> AESEncryptKey // S: AES_set_decrypt_key(Seed) --> AESDecryptKey // --- Client传输数据给Server // C: AES_encrypt(AESEncryptKey, Data) --> EncryptedData --> Send() --> Server // S: Recv() --> EncryptedData --> AES_decrypt(AESDecryptKey, EncryptedData) --> Data // --- Server传输数据给Client // S: AES_encrypt(AESEncryptKey, Data) --> EncryptedData --> Send() --> Client // C: Recv() --> EncryptedData --> AES_decrypt(AESDecryptKey, EncryptedData) --> Data / ========================================================================================= */

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值