这是我参与8月更文挑战的第29天,活动详情查看:8月更文挑战
概述
前两篇文章分别介绍了使用时间和限制使用次数进行加密,其实加密的方式还有很多种,今天主要介绍下通过获取计算机的硬件信息进行加密,但是这种方法加密效果不是很好,这个要分很多种情况。首先一起来看一下优缺点
优缺点
优点:
- 在用户使用过该软件之后,不能够将其复制到别的设备上使用,仅可以一台机器使用 缺点:
- 一个没有运行过新打包出来的程序可以随意复制,没法做到控制
如果程序是联网的还好说,可以达成一个安装包进行安装次数统计等限制,离线版的就没有办法了。如果有哪位小伙伴有更好的方法欢迎留言交流讨论。
还有一种方法是提前知道用户电脑的MAC地址或设备唯一标识,然后直接写入到程序中或者说存到本地进行读取。
思路分析
目前就作者知道的是Unity可以获取电脑的MAC地址和设备唯一标识符,这两个信息是每个电脑都不可能一样的,可以用来进行加密。
首先在Unity在StreamAssets下创建一个txt,写入一条加密数据,内容可以自己定,程序启动之后,对数据进行解密,看是否和规定的数据一样,相同说明程序是第一次运行,获取本机的MAC地址,并通过加密算法写入本地。如果不相同,说明数据已经写入过,解密,和本地MAC地址进行对比,相同,则继续,否则程序不可用。
也可以直接将本地的MAC地址或设备唯一标识直接写入程序中,这样就可以固定一台机器使用(前提是要获取用户电脑信息)
功能实现
数据加密
首先我们来看一下数据是如何加密的,然后我们在进行下一步。这里我们使用的是RijndaelManaged加密解码。需要导入命名空间 using System.Security.Cryptography;,需要注意的是,该加密方式需要使用一个32位的key(自己设定就可以了,可以在程序中设置为只读的),数据加密和解密的时候key必须相同,否则会出现数据解析结果不同或出现错误的情况,主要代码如下
/// <summary>
/// 加密数据
/// </summary>
public static string Encrypt(string Text, string sKey)
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(sKey);
RijndaelManaged encryption = new RijndaelManaged();
encryption.Key = keyArray;
encryption.Mode = CipherMode.ECB;
encryption.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = encryption.CreateEncryptor();
byte[] _EncryptArray = UTF8Encoding.UTF8.GetBytes(Text);
byte[] resultArray = cTransform.TransformFinalBlock(_EncryptArray, 0, _EncryptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
/// <summary>
/// 解密数据
/// </summary>
/// <param name="Text">要解密的内容</param>
/// <param name="sKey">key,必须为32位,要和加密时的key相同</param>
/// <returns></returns>
public static string Decrypt(string Text, string sKey)
{
try
{
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(sKey);
RijndaelManaged decipher = new RijndaelManaged();
decipher.Key = keyArray;
decipher.Mode = CipherMode.ECB;
decipher.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = decipher.CreateDecryptor();
byte[] _EncryptArray = Convert.FromBase64String(Text);
byte[] resultArray = cTransform.TransformFinalBlock(_EncryptArray, 0, _EncryptArray.Length);
return UTF8Encoding.UTF8.GetString(resultArray);
}
catch
{
return "解密错误";
}
}
通过调用上面的两个代码,我们可在Unity中测试一下
//需要加密的字符串
string encrypt = string.Empty;
//加密后的字符串
string desEncrypt = string.Empty;
//key,加密和解密都需要用到
readonly string key = "45621488631456644633443346324661";
// Start is called before the first frame update
void Start()
{
encrypt = "我是测试数据123";
desEncrypt = DESEncrypt.Encrypt(encrypt, key);
Debug.Log(encrypt + ">>加密结果为>>" + desEncrypt);
Debug.Log(desEncrypt + ">>解密结果为>>" + DESEncrypt.Decrypt(desEncrypt, key));
}
运行结果
获取MAC地址
首先我们需要在脚本中引用System.Net.NetworkInformation程序集,然后使用NetworkInterface中的GetAllNetworkInterfaces()可以获取所有的网络相关信息,其中GetPhysicalAddress()方法就可以拿到设备的物理地址即Mac地址。要获取所有信息之后再遍历找到MAC地址。具体代码如下:
/// <summary>
/// 获取MAC地址(物理地址)
/// </summary>
/// <returns></returns>
private static string GetMacAddress()
{
string physicalAddress = "";
NetworkInterface[] allInfo = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface adaper in allInfo)
{
if (adaper.Description == "en0")
{
physicalAddress = adaper.GetPhysicalAddress().ToString();
break;
}
else
{
physicalAddress = adaper.GetPhysicalAddress().ToString();
if (physicalAddress != "")
{
break;
}
}
}
return physicalAddress;
}
运行结果:
获取设备唯一标识
在Unity中有一个类SystemInfo,是专门用来获取设备的信息的,具体后期文章中会有介绍,内容有点多。本篇想要获取设备的唯一标识,只需要一句话即可,如下
SystemInfo.deviceUniqueIdentifier;
他返回的就是设备的唯一标识
运行结果就是
验证
首先我们创建一个txt文本放到StreamingAssets下,然后用程序生成一条加密的初始化判断语句,写入TXT中。
//程序第一运行
readonly string firstPlayStr = "这是程序的第一次运行!";
// Start is called before the first frame update
void Start()
{
//这里加密一条数据用来初始化第一次
Debug.Log(DESEncrypt.Encrypt(firstPlayStr, key));
}
将打印的信息复制到文本中。(手动复制,不是程序复制,没打包之前的操作)
然后读取文本,解密,对比数据。这里使用的是设备唯一标识。
读取文本,先看本地是否有文件,有就读,没有直接退出程序
/// <summary>
/// 读取数据
/// </summary>
/// <returns></returns>
private string ReadTxt()
{
string str = string.Empty;
//如果有数据就读
if (File.Exists(path))
{
StreamReader sr = new StreamReader(path);
str = sr.ReadToEnd();
sr.Close();
}
else
{
//没有数据直接退出
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
return str;
}
然后和读取的数据的解密结果进行对比,结果等于程序第一次运行,则获取设备唯一标识,并加密,然后写入到txt中,如果结果不是程序第一次运行,也不和设备唯一标识相同,退出程序
//读取数据
path = Application.streamingAssetsPath + "/info.txt";
string readString = DESEncrypt.Decrypt(ReadTxt(), key);
//解密后的数据是程序第一次运行的数据
if (readString == firstPlayStr)
{
//写入唯一标识的加密数据
WriteTxt(new string[] { DESEncrypt.Encrypt(SystemInfo.deviceUniqueIdentifier, key) });
}
else
{
//和本机设备标识对比
if (SystemInfo.deviceUniqueIdentifier.Equals(readString))
{
//验证通过
}
else
{
//验证失败
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
}
写入数据
/// <summary>
/// 写入数据
/// </summary>
/// <param name="contents"></param>
public void WriteTxt(string[] contents)
{
if (!File.Exists(path))
{
//文件不存在,退出程序
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
else
{
StreamWriter sw = new StreamWriter(path);
foreach (var item in contents)
{
sw.WriteLine(item);
}
sw.Close();
}
}
源代码分享
这个就不上效果图了,直接上源代码吧,一共有两个,感兴趣的可以下载下来看看 GitHub下载地址:点击这里跳转下载
写在最后
所有分享的内容均为作者在日常开发过程中使用过的各种小功能点,分享出来也变相的回顾一下,如有写的不好的地方还请多多指教。欢迎大家相互学习进步。本片文章就先写到这里,希望对你能够有所帮助