前言:Unity中通过xml格式保存游戏数据是非常常见的,但是如果不进行加密则非常容易被别人在外部通过修改xml文件修改游戏数据,因此加密xml是非常必要的。
一、工具类
创建一个名叫EncryptXmlDocument的c#文件,并复制下面代码到其中,作为xml加密工具类。
using UnityEngine;
using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Xml;
namespace EncryptUtility
{
public class EncryptXmlDocument
{
/// <summary>
/// 内容加密,加密和解密采用相同的key,具体可以自己定义,条件是必须是32位的
/// </summary>
/// <param name="toE"></param>
/// <returns></returns>
private string Encrypt(string toE)
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(EncryptKey);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateEncryptor();
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toE);
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
/// <summary>
/// 内容解密,千万记住解密和加密采用相同的key,必须是32位
/// </summary>
/// <param name="toD"></param>
/// <returns></returns>
private string Decrypt(string toD)
{
//加密和解密采用相同的key,具体值自己填,但是必须为32位//
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(EncryptKey);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateDecryptor();
byte[] toEncryptArray = Convert.FromBase64String(toD);
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
return UTF8Encoding.UTF8.GetString(resultArray);
}
/// <summary>
/// 判断XML文档是否存在
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static bool IsFileExist(string fileName)
{
return File.Exists(fileName);
}
public void Load(string filename)
{
if (IsFileExist(filename))
{
StreamReader sReader = File.OpenText(filename);
string dataString = sReader.ReadToEnd();
sReader.Close();
string xxx = Decrypt(dataString);
_doc.LoadXml(xxx);
}
}
public void Save(string filename)
{
string xxx = Encrypt(_doc.InnerXml);
StreamWriter writer;
writer = File.CreateText(filename);
writer.Write(xxx);
writer.Close();
}
public XmlDocument Instance { get { return _doc; } }
private XmlDocument _doc = new XmlDocument();
string dataKey = SystemInfo.deviceUniqueIdentifier; // 设置秘钥,根据平台而定
public string EncryptKey = "12348578902223367877723456789012"; // 有需要自己修改,必须为32位
}
}
二、测试
创建一个名叫XmlEncryptExample 的c#文件,并复制下面代码到其中,新建一个场景并将XmlEncryptExample组件拖动到一个物体上,然后点击运行。
using UnityEngine;
using System.Collections;
using System.Linq;
using System.Xml.Linq;
using System;
using System.IO;
using System.Xml;
using EncryptUtility;
public class XmlEncryptExample : MonoBehaviour
{
public string xmlpath;
// Use this for initialization
void Start()
{
xmlpath = Application.persistentDataPath + "/Data/myXML.xml";
var dir = Path.GetDirectoryName(xmlpath);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
EncryptXmlDocument doc = new EncryptXmlDocument();
if(File.Exists(xmlpath))
{
doc.Load(xmlpath);
}
else
{
XmlElement root = doc.Instance.CreateElement("XMLContent");
root.AppendChild( doc.Instance.CreateElement("IsFirstPlayGame"));
root.AppendChild(doc.Instance.CreateElement("Herb1"));
root.AppendChild(doc.Instance.CreateElement("Herb2"));
root.AppendChild(doc.Instance.CreateElement("Herb3"));
doc.Instance.AppendChild(root);
}
Debug.Log(doc.Instance.InnerXml);
doc.Save(xmlpath);
}
}
运行结果如下:
正确加载了从加密xml中读取的内容。(若不存在加密xml文件则会在首次运行时自动创建)