加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Unity对XML文件加密

发布时间:2020-12-16 06:41:18 所属栏目:百科 来源:网络整理
导读:ResourceFrom:http://www.unitymanual.com/thread-28231-1-1.html 问题:为什么要对xml加密,众所周知的对于一些客户端的游戏或者是单机游戏,xml存档如果不做特殊处理(加密和隐藏)那么玩家自己是可以打开并且修改的。玩过红色警戒的童鞋都知道,可以通过

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的值处)如图:

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读