先了解一下什么是AES加密算法
AES高级加密标准又称在加密学Rijndael加密算法
由美国国家标准与技术协会(NIST)所选的高级加密标准(AES)的候选算法。
AES算是Rijndael算法的一种特殊实现,选的分组为128bit(16字节),密钥可以使用128、192 和 256bit三种,而Rijndael使用的密钥和区块长度可以是32位的整数倍,以128位为下限,256比特为上限。加密过程中使用的密钥是由Rijndael密钥生成方案产生。
AES算法过程是在一个4x4字节矩阵(矩阵称为状态state)上运作,初始值是一个文明区块(矩阵一个元素大小就是文明区块的一个byte),加密时,各轮AES加密循环(最后一轮除外)分四步
1.矩阵中每一个字节都与该次轮秘钥做XOR运算;每个子密钥由密钥生成方案产生。
2.通过非线性的替换函数,用查找表的方式把每个字节替换成对应的字节。
3.将矩阵中的每个横列进行循环式位移
4.为了充分混合矩阵中各个直行的操作。这个步骤使用线性转换来混合每列的四个字节
https://blog.csdn.net/qq_28205153/article/details/55798628
这个是详细还有底层
C#的话封装的有一个RijndaelManaged类我们可以调用使用 然后封装一个类
using UnityEngine;
using System.Collections;
using System;
using System.Security.Cryptography;
using System.Text;
public struct RijndaelKey
{
public byte[] key;
public byte[] IV;
public RijndaelKey(byte[] key, byte[] iV)
{
this.key = key;
IV = iV;
}
}
public class Rijndael : MonoBehaviour
{
///
/// Rijndael加密
///
/// 密文
/// 密钥
/// 向量
///
public byte[] Encrypt(byte[] plainData, byte[] key, byte[] IV)
{
if (plainData == null || plainData.Length <= 0)
throw new ArgumentNullException("video");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] encrypted;
//创建RijndaelManaged对象
//使用指定的键和IV。
//用完就会被释放
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = key;
rijAlg.IV = IV;
//设置对称算法的运算模式
rijAlg.Mode = CipherMode.ECB;
//设置填充模式
rijAlg.Padding = PaddingMode.ISO10126;
//创建加密程序以执行流转换。
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
encrypted = encryptor.TransformFinalBlock(plainData, 0, plainData.Length);
}
//从内存流返回加密的字节。
return encrypted;
}
///
/// 解密
///
///
///
///
///
public byte[] Decrypt(byte[] cipherData, byte[] key, byte[] IV)
{
if (cipherData == null || cipherData.Length <= 0)
throw new ArgumentNullException("video");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] decrypted;
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = key;
rijAlg.IV = IV;
rijAlg.Mode = CipherMode.ECB;
rijAlg.Padding = PaddingMode.ISO10126;
//创建解密程序以执行流转换。
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
decrypted = decryptor.TransformFinalBlock(cipherData, 0, cipherData.Length);
}
return decrypted;
}
///
/// 创建Key 和IV在某个目录下
///
///
///
public RijndaelKey CreateKeyAndIV(string path)
{
RijndaelManaged rijma = new RijndaelManaged();
rijma.GenerateKey();
rijma.GenerateIV();
FileTools.CreateFile(path + "/keyTxt.txt", rijma.Key);
FileTools.CreateFile(path + "/IVTxt.txt", rijma.IV);
return new RijndaelKey(rijma.Key, rijma.IV);
}
///
/// 获取Key 和IV
///
///
///
public RijndaelKey GetKeyAndIV(string path)
{
byte[] key = FileTools.ReadFile(path + "/keyTxt.txt");
byte[] IV = FileTools.ReadFile(path + "/IVTxt.txt");
return new RijndaelKey(key, IV);
}
}
这是一个IO读写类
using System.Collections;
using System.IO;
///
/// IO读写类
///
public class FileTools
{
///
/// 创建目录文件夹 有就不创建
///
public static void CreateDirectory(string filePath)
{
if (!string.IsNullOrEmpty(filePath))
{
if (!File.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
}
}
///
/// 创建文件
///
///
///
public static void CreateFile(string filePath, byte[] bytes)
{
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
fs.Write(bytes, 0, bytes.Length);
}
}
///
/// 读取文件
///
///
///
public static byte[] ReadFile(string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] infbytes = new byte[fs.Length];
fs.Read(infbytes, 0, infbytes.Length);
return infbytes;
}
}
}
这个是官方对string加密解密的
https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.cryptostream?redirectedfrom=MSDN&view=netframework-4.8
然后我们要写一个处理视频的工具 在Unity里
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
public class EncryptTools
{
///
/// 复制一份加密的出来
///
///
[MenuItem("Tools/EncryptVideo")]
static void EncryptVideo(MenuCommand cmd)
{
//获取选择文件夹的路径
string[] str = Selection.assetGUIDs;
string path = AssetDatabase.GUIDToAssetPath(str[0]);
string newPath = Application.dataPath + "/StreamingAssets/videoNew";
FileTools.CreateDirectory(newPath);
//获取指定路径下的指定类型资源
DirectoryInfo root = new DirectoryInfo(path);
FileInfo[] files = root.GetFiles("*.mp4");
Rijndael rij = new Rijndael();
RijndaelKey rijKey = rij.CreateKeyAndIV(newPath);
for (int i = 0; i < files.Length; i++)
{
byte[] enBytes = rij.Encrypt(FileTools.ReadFile(files[i].FullName), rijKey.key, rijKey.IV);
string strWriteFile = newPath + "/" + files[i].Name;
FileTools.CreateFile(strWriteFile, enBytes);
EditorUtility.DisplayProgressBar("进度", i + "/" + files.Length + "完成修改值", (float)i / files.Length);
}
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
}
///
/// C#获取指定目录下多种指定类型文件
///
/// 路径
///
static List GetVideoFiles(string filePath)
{
DirectoryInfo di = new DirectoryInfo(filePath);
FileInfo[] files = di.GetFiles();
string fileName;
List list = new List();
for (int i = 0; i < files.Length; i++)
{
fileName = files[i].Name.ToLower();
if (fileName.EndsWith(".mp4") || fileName.EndsWith(".avi"))
{
list.Add(fileName);
}
}
return list;
}
}
这个放在Editor文件夹下 选中你想加密视频的文件夹 然后点击
就OK了 会在StreamingAssets/videoNew生成一份加密的视频和key还有向量 之前的没加密的视频还在 然后是只会加密拷贝当前文件夹下的视频 而不是该文件夹下所有子文件夹的视频
因为我用的是avpro 新版本可以直接读byte[]视频
放一个不完整的处理代码 这个可以粘贴到之前的AvProControl那个类里面使用
private IEnumerator LoadEncryptVideoWithFading(string path)
{
string newPath = Application.dataPath + "/StreamingAssets/videoNew";
path = newPath+"/" + path;
Rijndael rij = new Rijndael();
RijndaelKey rijKey = rij.GetKeyAndIV(newPath);
byte[] enBytes = rij.Decrypt(FileTools.ReadFile(path), rijKey.key, rijKey.IV);
// Wait 3 frames for display object to update
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();
// Load the video
if (Application.isPlaying)
{
if (!mediaPlayer.OpenVideoFromBuffer(enBytes))
{
Debug.LogError("Failed to open video!");
}
else
{
// Wait for the first frame to come through (could also use events for this)
while (Application.isPlaying && (VideoIsReady(mediaPlayer) || AudioIsReady(mediaPlayer)))
{
yield return null;
}
// Wait 3 frames for display object to update
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();
}
}
duration = mediaPlayer.Info.GetDurationMs();
}