资源打包参考另一篇博客,Unity 简单打包脚本
AES(Advanced Encryption Standard)是一种对称加密算法,是目前广泛使用的加密标准之一。AES使用相同的密钥来进行加密和解密,密钥长度可以是128位、192位或256位。它将数据分成固定长度的数据块,然后对每个数据块进行加密。AES算法采用替代、置换和混合的技术,通过多轮的操作来实现高强度的加密。
C#提供了内置的加密库,其中包括对AES加密算法的支持,需要添加命名空间System.Security.Cryptography
使用AES算法,除了密钥,还需要一个IV(Initialization Vector,初始化向量)作用是在加密中引入随机性,以确保相同的明文在每次加密时都产生不同的密文,从而增强加密的安全性。
加密算法通常可以用于加密任何类型的文件,这里以加密bundle为例子
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
public static class AesEncryption
{
private static string keyString = "YourSecretKey123";
private static string ivString = "123456";
private static byte[] key = Encoding.UTF8.GetBytes(keyString);
//IV 必须是 16 字节
private static byte[] iv = Encoding.UTF8.GetBytes(ivString.PadRight(16, '\0'));
public static bool EncryptFile(string inputPath, string outputPath)
{
try
{
using (Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
// 读取待加密的文件
using (FileStream inputFileStream = new FileStream(inputPath, FileMode.Open, FileAccess.Read))
{
// 创建一个内存流,用于存放加密后的数据
using (MemoryStream memoryStream = new MemoryStream())
{
// 创建加密转换器和加密流
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
inputFileStream.CopyTo(cryptoStream);
cryptoStream.FlushFinalBlock();
// 获取加密后的数据
byte[] encryptedData = memoryStream.ToArray();
// 将加密后的内容写入输出文件
File.WriteAllBytes(outputPath, encryptedData);
}
}
}
}
return true;
}
catch(Exception e)
{
Debug.LogError(e.ToString());
return false;
}
}
public static byte[] DecryptFile(string inputPath)
{
try
{
using (Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
// 打开加密后的文件
using (FileStream inputFile = new FileStream(inputPath, FileMode.Open, FileAccess.Read))
{
// 创建一个内存流,用于存放解密后的数据
using (MemoryStream outputStream = new MemoryStream())
{
// 创建解密转换器和解密流
using (ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
using (CryptoStream cryptoStream = new CryptoStream(inputFile, decryptor, CryptoStreamMode.Read))
{
// 将加密后的文件内容解密并写入内存流
cryptoStream.CopyTo(outputStream);
}
// 获取解密后的数据
return outputStream.ToArray();
}
}
}
}
catch (Exception e)
{
Debug.LogError("解密失败:" + e.ToString());
return null;
}
}
}
代码中的密钥和 IV 可以设置成通过网络传输获取,或者把代码打成 dll,然后加壳
Editor下测试加密文件
using System.IO;
using UnityEditor;
using UnityEngine;
public static class EncryptionBundle
{
public static bool EncryptionFile(string inputPath, string outputPath)
{
return AesEncryption.EncryptFile(inputPath, outputPath);
}
[MenuItem("Tools/加密资源")]
public static void BuildDirectory()
{
string inputPath = Application.streamingAssetsPath;
string outputPath = Application.dataPath + "/EncryptionAsset/";
string[] files = Directory.GetFiles(inputPath);
for (int i = 0; i < files.Length; i++)
{
string filePath = files[i];
if (filePath.EndsWith(".meta"))
{
continue;
}
string fileName = Path.GetFileName(filePath);
bool result = EncryptionFile(filePath, outputPath + fileName);
Debug.Log("加密" + (result ? "成功" : "失败") + " " + filePath);
}
AssetDatabase.Refresh();
}
}
运行时先解密,然后从内存中加载bundle
using System.Collections.Generic;
using UnityEngine;
public class LoadEncryptedBundle : MonoBehaviour
{
private AssetBundleManifest _manifest;
private List<string> _abList = new List<string>();
private Dictionary<string, GameObject> _assetDict = new Dictionary<string, GameObject>();
//加密后资源所在路径
private string encryptionPath = Application.dataPath + "/EncryptionAsset/";
void Start()
{
LoadManifest();
LoadGameObject("plane");
}
private void LoadManifest()
{
AssetBundle assetBundle = DecryptionFile(encryptionPath + "StreamingAssets");
_manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
private AssetBundle DecryptionFile(string path)
{
byte[] bytes = AesEncryption.DecryptFile(path);
if (bytes != null)
{
return AssetBundle.LoadFromMemory(bytes);
}
return null;
}
private void LoadGameObject(string abName)
{
if (string.IsNullOrEmpty(abName))
return;
abName = abName.ToLower();
//先加载依赖资源
string[] dependens = _manifest.GetAllDependencies(abName);
for (int i = 0; i < dependens.Length; ++i)
{
if (!_abList.Contains(dependens[i]))
{
DecryptionFile(encryptionPath + dependens[i]);
_abList.Add(dependens[i]);
}
}
if (!_abList.Contains(abName))
{
AssetBundle ab = DecryptionFile(encryptionPath + abName);
_abList.Add(abName);
_assetDict.Add(abName, ab.LoadAsset<GameObject>(abName));
}
if (_assetDict.ContainsKey(abName))
{
GameObject.Instantiate(_assetDict[abName]);
}
}
}