ResourceFrom:http://www.unitymanual.com/thread-28231-1-1.html
问题:为什么要对xml加密,众所周知的对于一些客户端的游戏或者是单机游戏,xml存档如果不做特殊处理(加密和隐藏)那么玩家自己是可以打开并且修改的。玩过红色警戒的童鞋都知道,可以通过修改参数可以让自己无敌。玩游戏的时候这样固然很爽,但是对于我们开发的游戏可不希望杯别人随意修改参数,那么加密就显得至关重要啦。
解决方法:
1》解决对XML文档加密、解密、对数据的增删改查、对XML文档的存取。对于每一个操作都是有加密和解密处理,代码并没有做优化,反复的加密和解密是个不足之处。该类的代码如下:
using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using System; using System.Security.Cryptography; using System.Text; using System.IO; using System.Security.AccessControl; using System.Security.Principal; using System.Xml; using System.Xml.Serialization; public class LinqToXMLAndEncrypt { static string dataKey = SystemInfo.deviceUniqueIdentifier;//设置秘钥,根据平台而定 //static string xmlpath = Application.persistentDataPath + @"\myXML";//平台相关的路径(移动端) static string xmlpath = Application.dataPath + @"\myXML";//电脑上的路径,移动端没有这个访问权限 /// <summary> /// 初始化一个XML文件 /// </summary> public static void CreateXMLDocument() { XElement root = new XElement("XMLContent",new XElement("IsFirstPlayGame",new XAttribute("MyVaule","0")),new XElement("Herb1",new XElement("Herb2",new XElement("Herb3",new XElement("Level01",/*从level01到LevelDemo是用来表示这个关卡是否玩过,其中MyVaule=1表示玩过,0表示没有*/ new XElement("Level02",new XElement("Level03",new XElement("Level04",new XElement("Level05",new XElement("Level06",new XElement("LevelDemo",new XElement("Level",new XElement("Root","root") ); root.Save(xmlpath); EncrtyptSaveXML(); } private static void EncrtyptSaveXML() { StreamReader sReader = File.OpenText(xmlpath); string xmlData = sReader.ReadToEnd(); sReader.Close(); string xxx = Encrypt(xmlData); StreamWriter writer; writer = File.CreateText(xmlpath); writer.Write(xxx); writer.Close(); } public static XElement DecrtyptLoadXML() { if (hasFile(xmlpath)) { StreamReader sReader = File.OpenText(xmlpath); string xmlData = sReader.ReadToEnd(); sReader.Close(); string xxx = Decrypt(xmlData); StreamWriter writer; writer = File.CreateText(xmlpath); writer.Write(xxx); writer.Close(); XElement root = XElement.Load(xmlpath); return root; } else return null; } public static void SetElementValue(string name,string value) { XElement root = DecrtyptLoadXML(); root.Element(name).SetAttributeValue("MyVaule",value); root.Save(xmlpath); EncrtyptSaveXML(); } /// <summary> /// 在根节点元素之前添加新的元素 /// </summary> /// <param name="name">元素名字</param> /// <param name="value">元素的值</param> public static void AddElement(string name,string value) { XElement root = DecrtyptLoadXML(); root.Element("Root").AddBeforeSelf(new XElement(name,new XAttribute("MyValue",value))); root.Save(xmlpath); EncrtyptSaveXML(); } /// <summary> /// 删除指定的元素 /// </summary> /// <param name="name">要删除的元素名称</param> public static void RemoveElement(string name) { XElement root = DecrtyptLoadXML(); root.Element(name).Remove(); root.Save(xmlpath); EncrtyptSaveXML(); } /// <summary> /// 根据元素名查找元素对应的值 /// </summary> /// <param name="name">元素名</param> /// <returns></returns> public static string GetElementValue(string name) { XElement root = DecrtyptLoadXML(); XAttribute xattr = root.Element(name).Attribute("MyVaule"); string s = xattr.Value; EncrtyptSaveXML(); return s; } /// <summary> /// 内容加密,加密和解密采用相同的key,具体可以自己定义,条件是必须是32位的 /// </summary> /// <param name="toE"></param> /// <returns></returns> private static string Encrypt(string toE) { byte[] keyArray = UTF8Encoding.UTF8.GetBytes("12348578902223367877723456789012"); 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,toEncryptArray.Length); return Convert.ToBase64String(resultArray,resultArray.Length); } /// <summary> /// 内容解密,千万记住解密和加密采用相同的key,必须是32位 /// </summary> /// <param name="toD"></param> /// <returns></returns> private static string Decrypt(string toD) { //加密和解密采用相同的key,具体值自己填,但是必须为32位// byte[] keyArray = UTF8Encoding.UTF8.GetBytes("12348578902223367877723456789012"); 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,toEncryptArray.Length); return UTF8Encoding.UTF8.GetString(resultArray); } /// <summary> /// 判断XML文档是否存在 /// </summary> /// <param name="fileName"></param> /// <returns></returns> public static bool hasFile(string fileName) { return File.Exists(fileName); } /// <summary> /// 读取XML,返回XML的字符串 /// </summary> /// <returns>返回XML的一串字符</returns> public static string LoadXMLForString(bool isDecrypt=true) { if (hasFile(xmlpath)) { StreamReader sReader = File.OpenText(xmlpath); string dataString = sReader.ReadToEnd(); sReader.Close(); if (isDecrypt) { string xxx = Decrypt(dataString); return xxx; } else return dataString; } else { return null; } } }2》测试如下:
简单的建立一个场景Text,可以只有一个主摄像机就行。在建立一个Text脚本,托给摄像机,Text的代码如下:
using UnityEngine; using System.Collections; using System.Linq; using System.Xml.Linq; using System; public class Text : MonoBehavIoUr { bool isDecrypt = false; // Use this for initialization void Start () {Debug.Log ("path =" + Application.dataPath); LinqToXMLAndEncrypt.CreateXMLDocument(); NGUIDebug.Log(LinqToXMLAndEncrypt.LoadXMLForString(isDecrypt)); LinqToXMLAndEncrypt.SetElementValue("Herb1","100"); NGUIDebug.Log(LinqToXMLAndEncrypt.LoadXMLForString(isDecrypt)); LinqToXMLAndEncrypt.AddElement("ZHangXiaob","10000"); NGUIDebug.Log(LinqToXMLAndEncrypt.LoadXMLForString(isDecrypt)); NGUIDebug.Log("ssssss:"+ LinqToXMLAndEncrypt.GetElementValue("Herb1")); } // Update is called once per frame void Update () { } }注意:新增加的元素在一个方法里面是不会立马读出来的,因为XML的操作都是延迟执行的。比如说上面的代码
GUIDebug.Log("ssssss:"+ LinqToXMLAndEncrypt.GetElementValue("Herb1"));处换成GUIDebug.Log("ssssss:"+ LinqToXMLAndEncrypt.GetElementValue("ZHangXiaob "));就会报错。
核心代码中的 public staticstring LoadXMLForString(bool isDecrypt=true)方法是为了方便测试用的,它可以将整个XML读出成为一串字符串
我定义一个参数 bool isDecrypt=true,为true的时候读出来的是解密的也就是正常的,为false的时候读出来是加密的。
运行效果:
未加密:
加密:
自己可以打开生成的存储文件,数据已经是加密的了,(文件位置:Application.dataPath的值处)如图: