关于数据加密,前段时间刚刚用过AES,这里就简单记录一下啦
大概思路就是:
- 直接读取Json文件的数据,转换为二进制流
- 对数据进行加密处理,得到加密后的二进制流
- 将二进制文件保存到本地
- 读取本地加密文件,进行解密操作
- 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/s/1zR8jeyscwvJn71lZnt4Rlw 密码:uqi2
更多推荐
AES加密解密/本地文件读写/Json解析
发布评论