AES加密解密/本地文件读写/Json解析

关于数据加密,前段时间刚刚用过AES,这里就简单记录一下啦
大概思路就是:

  1. 直接读取Json文件的数据,转换为二进制流
  2. 对数据进行加密处理,得到加密后的二进制流
  3. 将二进制文件保存到本地
  4. 读取本地加密文件,进行解密操作
  5. Json解析
    (刚开始的做法,是把二进制文件转化为字符串,然后保存,在读取的时候出现了问题,报错存贮的和读取的字符串不一致,应该是中间数据转换的时候格式有问题,就直接保存了二进制文件)

加密解密部分:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Text;
using System.Security.Cryptography;

namespace AESEncrypt
{
    public class AESEncryptTool : MonoBehaviour
    {
        private static AESEncryptTool instance;
        public static AESEncryptTool Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new GameObject("AESEncryptTool").AddComponent<AESEncryptTool>();
                    instance.Init();
                }
                return instance;
            }
        }

        byte[] _keyBytes;
        byte[] _ivBytes;

        //初始化
        void Init()
        {
            //获取密码, 密码写在预设体, 不要写在代码里, 防止外界直接通过代码窃取
            UnityEngine.Object obj = Resources.Load("AESEncryptPassword");
            if(obj == null)
            {
                Debug.Log("<color=red> Init Error , Not Resources.Load(AEDEncryptPassword) </color>");
            }
            GameObject go = obj as GameObject;
            AEDEncryptPassword code = go.GetComponent<AEDEncryptPassword>();

            _keyBytes = Encoding.UTF8.GetBytes(code.CryptKey);
            _ivBytes = Encoding.UTF8.GetBytes(code.CryptIV);
        }

        //加密数据
        public byte[] Encrypt(byte[] contentBytes)
        {
            RijndaelManaged rm = new RijndaelManaged();
            rm.Key = _keyBytes;
            rm.IV = _ivBytes;
            rm.Mode = CipherMode.CBC;
            rm.Padding = PaddingMode.PKCS7;
            ICryptoTransform ict = rm.CreateEncryptor();
            byte[] resultBytes = ict.TransformFinalBlock(contentBytes, 0, contentBytes.Length);
            //return Convert.ToBase64String(resultBytes, 0, resultBytes.Length);
            return resultBytes;
        }

        //解密数据
        public byte[] Decipher(byte[] contentBytes)
        {
            RijndaelManaged rm = new RijndaelManaged();
            rm.Key = _keyBytes;
            rm.IV = _ivBytes;
            rm.Mode = CipherMode.CBC;
            rm.Padding = PaddingMode.PKCS7;
            ICryptoTransform ict = rm.CreateDecryptor();
            byte[] resultBytes = ict.TransformFinalBlock(contentBytes, 0, contentBytes.Length);
            //return Encoding.UTF8.GetString(resultBytes);
            return resultBytes;
        }

    }
}

文件读取保存到本地部分:
//因为加密操作只需要在编辑器环境下运行一次,这里把加密环节单独放到一个场景,便于单独操作,打包的时候也不需要打包该场景

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;

public class AESEncryption : MonoBehaviour
{
    //在一帧内处理指定数量文件, 可根据单个Json数据量及电脑处理速度修改参数
    [SerializeField] int OnceWriteFileMaxCount = 10;
    
    //读取的Json文件路径, 生成的加密文件路径, 从Asset下一级开始
    [SerializeField] string jsonPath_file;
    [SerializeField] string dataPath_file;

    //读取的Json文件夹路径, 生成的加密文件夹路径, 从Asset下一级开始
    [SerializeField] string jsonPath_folder;
    [SerializeField] string dataPath_folder;

    void Awake()
    {
        jsonPath_file = Application.dataPath + "/" + jsonPath_file;
        dataPath_file = Application.dataPath + "/" + dataPath_file;

        jsonPath_folder = Application.dataPath + "/" + jsonPath_folder;
        dataPath_folder = Application.dataPath + "/" + dataPath_folder;
    }

    void Start()
    {
        StartCoroutine(EncryptAll());
    }

    IEnumerator EncryptAll()
    {
        yield return StartCoroutine(WriteEncryptFile(jsonPath_file, dataPath_file));

        yield return new WaitForEndOfFrame();

        yield return StartCoroutine(WriteEncryptFolder(jsonPath_folder, dataPath_folder));
    }

    //删除原文件
    public void DeletJsonFile(string jsonPath)
    {
        if (Directory.Exists(jsonPath))
        {
            Directory.Delete(jsonPath, true);
            Debug.Log("文件夹已删除");
        }
        else
            Debug.Log("文件夹不存在");
    }

    //加密文件, 所有的Json在一个文件夹下
    public void WriteEncryptFromFile(string jsonPath, string dataPath)
    {
        StartCoroutine(WriteEncryptFile(jsonPath, dataPath));
    }

    //加密文件夹, Json路径文件夹下嵌套一层文件夹, 即所有的Json分类在多个子文件夹下
    public void WriteEncryptFromFolder(string jsonPath, string dataPath)
    {
        StartCoroutine(WriteEncryptFolder(jsonPath, dataPath));
    }

    // ------

    IEnumerator WriteEncryptFile(string jsonPath, string dataPath)
    {
        //Debug.Log("<color=green> 开始加密文件 </color>");

        if (!Directory.Exists(jsonPath))
        {
            Debug.Log("<color=red> 该目录不存在  </color>" + jsonPath);
            yield break;
        }
        //删除原有文件夹及文件, 重新创建
        if (Directory.Exists(dataPath))
        {
            Directory.Delete(dataPath, true);
            //Debug.Log("文件夹存在,删除");
        }
        Directory.CreateDirectory(dataPath);
        //Debug.Log("新建文件夹  " + dataPath);

        //生成新文件

        //获取文件夹下所有文件
        DirectoryInfo directoryInfo = new DirectoryInfo(jsonPath);
        FileInfo[] fileInfo = directoryInfo.GetFiles("*.json", SearchOption.AllDirectories);

        int count = 0;
        for (int i = 0; i < fileInfo.Length; i++)
        {
            //是否是Json
            if (fileInfo[i].Name.EndsWith(".json", StringComparison.Ordinal))
            {
                //读取问价内容
                byte[] bytes = File.ReadAllBytes(fileInfo[i].FullName);
                //加密文件内容
                byte[] jsonBytes = AESEncrypt.AESEncryptTool.Instance.Encrypt(bytes);
                //生成加密后的新文件
                FileStream fileStream = new FileStream(dataPath + "//" + fileInfo[i].Name.Replace("json", "bytes"), FileMode.Create);
                fileStream.Write(jsonBytes, 0, jsonBytes.Length);
                fileStream.Flush();
                fileStream.Close();
                fileStream.Dispose();
                count++;

                //在一帧内处理指定数量文件, 可根据单个Json数据量及电脑处理速度修改参数
                if (i % OnceWriteFileMaxCount == 0)
                    yield return new WaitForEndOfFrame();
            }
        }
        Debug.Log("<color=green> 文件加密完成,共有文件 :</color>" + count);
    }

    IEnumerator WriteEncryptFolder(string jsonPath, string dataPath)
    {
        //检查路径
        if (!Directory.Exists(jsonPath))
        {
            Debug.Log("<color=red> 该目录不存在  </color>" + jsonPath);
            yield break;
        }
        //删除原有加密文件夹及文件, 重新创建
        if (Directory.Exists(dataPath))
        {
            Directory.Delete(dataPath, true);
            //Debug.Log("文件夹存在,删除");
        }
        Directory.CreateDirectory(dataPath);
        //Debug.Log("新建文件夹  " + dataPath);

        //获取指定路径下面的所有资源文件夹
        //返回满足指定条件的所有文件和子目录的路径及名称
        string[] directoryEntries = Directory.GetFileSystemEntries(jsonPath);
        string tmpPath;
        int i = 0, folderCount = 0;
        while (i < directoryEntries.Length)
        {
            tmpPath = directoryEntries[i];
            //判断是否为文件夹
            if (!tmpPath.Contains("."))
            {
                //依次加密
                yield return StartCoroutine(WriteEncryptFile(tmpPath, tmpPath.Replace(jsonPath, dataPath)));
                folderCount++;
                yield return new WaitForEndOfFrame();
            }
            i++;
        }
        Debug.Log("<color=blue> 文件夹加密完成,共有文件夹 :</color>" + folderCount);
    }

}

数据解密读取部分:
//在游戏运行过程中,数据读取

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
using System.Text;
using System.IO;

public class DataModel
{
    public int level;
    public string str;
}

public class DataManager : MonoBehaviour
{
    string resourcesPath01 = "File/FileData";
    string resourcesPath02 = "Folder/FolderData";

    //保存数据
    Dictionary<int, DataModel> allDataDic = new Dictionary<int, DataModel>();

    void Start ()
    {
        DataModel dataModel = GetDataByLevel(1);
        Debug.Log(dataModel.level + "  " + dataModel.str);
	}
	
    public DataModel GetDataByLevel(int level)
    {
        //是否已经读取过一次
        if (allDataDic.ContainsKey(level))
        {
            return allDataDic[level];
        }
        else
        {
            //读取解密数据
            string jsonStr = null;
            try
            {
                TextAsset textAsset = Resources.Load<TextAsset>(resourcesPath01 + "/level" + level);

                if (textAsset == null)
                    return null;

                byte[] bytes = textAsset.bytes;

                byte[] txtBytes = AESEncrypt.AESEncryptTool.Instance.Decipher(bytes);
                jsonStr = Encoding.UTF8.GetString(txtBytes);
            }
            catch (FileNotFoundException error)
            {
                Debug.Log(error);
                Debug.Log("<color=red> 该文件不存在  </color>" + resourcesPath01 + "/level" + level);
            }
            DataModel dataModel = null;
            if (!string.IsNullOrEmpty(jsonStr))
            {
                try
                {
                    dataModel = JsonConvert.DeserializeObject<DataModel>(jsonStr);
                }
                catch (JsonReaderException error)
                {
                    Debug.Log(error);
                    Debug.Log("<color=red> Json数据解析错误 : level </color>" + "/level" + level);
                }
            }
            if (dataModel != null)
            {
                allDataDic.Add(level, dataModel);
                //Debug.Log("<color=green> Json 解密 解析 Success : level </color>" + "/level" + level);
            }
            else
                Debug.Log("<color=red> 未获取到Json数据 : level </color>" + "/level" + level);

            return dataModel;
        }
    }

}

主要的代码就是以上三部分,下面是完整的Demo,方便大家理解整个过程~
链接:https://pan.baidu.com/s/1zR8jeyscwvJn71lZnt4Rlw 密码:uqi2

猜你喜欢

转载自blog.csdn.net/qq_39108767/article/details/82120321
今日推荐