C#中实现AES算法加密解读
短信预约 -IT技能 免费直播动态提醒
先上效果图
文件和加密文件之间的转换。
先添加辅助类
public class AES_EnorDecrypt
{
//定义默认密钥
private static byte[] _aesKeyByte = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
private static string _aesKeyStr = Encoding.UTF8.GetString(_aesKeyByte);
/// <summary>
/// 随机生成密钥,默认密钥长度为32,不足在加密时自动填充空格
/// </summary>
/// <param name="n">密钥长度</param>
/// <returns></returns>
public static string GetIv(int n)
{
string s = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] arrChar = new char[s.Length];
for (int i = 0; i < s.Length; i++)
{
arrChar[i] = Convert.ToChar(s.Substring(i, 1));
}
StringBuilder num = new StringBuilder();
Random rnd = new Random(DateTime.Now.Millisecond);
for (int i = 0; i < n; i++)
{
num.Append(arrChar[rnd.Next(0, arrChar.Length)].ToString());
}
_aesKeyByte = Encoding.UTF8.GetBytes(num.ToString());
return _aesKeyStr = Encoding.UTF8.GetString(_aesKeyByte);
}
/// <summary>
/// AES加密,针对文本类文件
/// </summary>
/// <param name="Data">被加密的明文</param>
/// <param name="Key">密钥</param>
/// <param name="Vector">密钥向量</param>
/// <returns>密文</returns>
public static string AESEncrypt(string Data, string Key, string Vector)
{
byte[] plainBytes = Encoding.UTF8.GetBytes(Data);
byte[] bKey = new byte[32];
Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
byte[] bVector = new byte[16];
Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
byte[] Cryptograph = null;//加密后的密文
Rijndael Aes = Rijndael.Create();
try
{
using (MemoryStream Memory = new MemoryStream())
{
//把内存流对象包装成加密流对象
using (CryptoStream Encryptor = new CryptoStream(Memory, Aes.CreateEncryptor(bKey, bVector), CryptoStreamMode.Write))
{
Encryptor.Write(plainBytes, 0, plainBytes.Length);
Encryptor.FlushFinalBlock();
Cryptograph = Memory.ToArray();
}
}
}
catch
{
Cryptograph = null;
}
return Convert.ToBase64String(Cryptograph);
}
/// <summary>
/// AES加密,任意文件
/// </summary>
/// <param name="Data">被加密的明文</param>
/// <param name="Key">密钥</param>
/// <param name="Vector">密钥向量</param>
/// <returns>密文</returns>
public static byte[] AESEncrypt(byte[] Data, string Key, string Vector)
{
byte[] bKey = new byte[32];
Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
byte[] bVector = new byte[16];
Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
byte[] Cryptograph = null;//加密后的密文
Rijndael Aes = Rijndael.Create();
try
{
using (MemoryStream Memory = new MemoryStream())
{
//把内存流对象包装成加密流对象
using (CryptoStream Encryptor = new CryptoStream(Memory, Aes.CreateEncryptor(bKey, bVector), CryptoStreamMode.Write))
{
Encryptor.Write(Data, 0, Data.Length);
Encryptor.FlushFinalBlock();
Cryptograph = Memory.ToArray();
}
}
}
catch
{
Cryptograph = null;
}
return Cryptograph;
}
/// <summary>
/// AES解密,针对文本文件
/// </summary>
/// <param name="Data">被解密的密文</param>
/// <param name="Key">密钥</param>
/// <param name="Vector">密钥向量</param>
/// <returns>明文</returns>
public static string AESDecrypt(string Data, string Key, string Vector)
{
byte[] encryptedBytes = Convert.FromBase64String(Data);
byte[] bKey = new byte[32];
Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
byte[] bVector = new byte[16];
Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
byte[] original = null;//解密后的明文
Rijndael Aes = Rijndael.Create();
try
{
using (MemoryStream Memory = new MemoryStream(encryptedBytes))
{
//把内存流对象包装成加密对象
using (CryptoStream Decryptor = new CryptoStream(Memory, Aes.CreateDecryptor(bKey, bVector), CryptoStreamMode.Read))
{
//明文存储区
using (MemoryStream originalMemory = new MemoryStream())
{
byte[] Buffer = new byte[1024];
int readBytes = 0;
while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0)
{
originalMemory.Write(Buffer, 0, readBytes);
}
original = originalMemory.ToArray();
}
}
}
}
catch
{
original = null;
}
return Encoding.UTF8.GetString(original);
}
/// <summary>
/// AES解密,任意文件
/// </summary>
/// <param name="Data">被解密的密文</param>
/// <param name="Key">密钥</param>
/// <param name="Vector">密钥向量</param>
/// <returns>明文</returns>
public static byte[] AESDecrypt(byte[] Data, string Key, string Vector)
{
byte[] bKey = new byte[32];
Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);
byte[] bVector = new byte[16];
Array.Copy(Encoding.UTF8.GetBytes(Vector.PadRight(bVector.Length)), bVector, bVector.Length);
byte[] original = null;//解密后的明文
Rijndael Aes = Rijndael.Create();
try
{
using (MemoryStream Memory = new MemoryStream(Data))
{
//把内存流对象包装成加密对象
using (CryptoStream Decryptor = new CryptoStream(Memory, Aes.CreateDecryptor(bKey, bVector), CryptoStreamMode.Read))
{
//明文存储区
using (MemoryStream originalMemory = new MemoryStream())
{
byte[] Buffer = new byte[1024];
int readBytes = 0;
while ((readBytes = Decryptor.Read(Buffer, 0, Buffer.Length)) > 0)
{
originalMemory.Write(Buffer, 0, readBytes);
}
original = originalMemory.ToArray();
}
}
}
}
catch
{
original = null;
}
return original;
}
}
AES是块加密,块的长度是16字节,如果原文不到16的字节,就会进行填充至16个字节。
开始实现
界面布局
textbox1为文件位置,textbox2为密码。
设置好后
public partial class FormAes : Form
{
#region 属性
private static string _aesKeyVector = "q2T_=R/*33vc";
#endregion
public FormAes()
{
InitializeComponent();
}
/// <summary>
/// 选择文件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void textBox1_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Multiselect = true;//该值确定是否可以选择多个文件
dialog.Title = "请选择文件夹";
dialog.Filter = "所有文件(*.*)|*.*";
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
textBox1.Text = dialog.FileName;
}
}
/// <summary>
/// 加密
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(textBox1.Text.Trim()) || string.IsNullOrWhiteSpace(textBox2.Text.Trim()))
return;
backgroundWorker1.RunWorkerAsync();
}
/// <summary>
/// 解密
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(textBox1.Text.Trim()) || string.IsNullOrWhiteSpace(textBox2.Text.Trim()))
return;
backgroundWorker2.RunWorkerAsync();
}
/// <summary>
/// 后台线程执行的方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
string KeyVector = _aesKeyVector;//密钥向量
string path = Path.GetDirectoryName(textBox1.Text);
string name = Path.GetFileName(textBox1.Text);
name += ".En";
#region 加密
FileStream sr = new FileStream(textBox1.Text, FileMode.Open, FileAccess.Read);
FileStream sw = new FileStream(path + "\\" + name, FileMode.Create, FileAccess.Write);
if (sr.Length > 50 * 1024 * 1024)//如果文件大于50M,采取分块加密,按50MB读写
{
byte[] mybyte = new byte[52428800];//每50MB加密一次
int numBytesRead = 52428800;//每次加密的流大小
long leftBytes = sr.Length;//剩余需要加密的流大小
long readBytes = 0;//已经读取的流大小
//每50MB加密后会变成50MB+16B
byte[] encrpy = new byte[52428816];
while (true)
{
if (leftBytes > numBytesRead)
{
sr.Read(mybyte, 0, mybyte.Length);
encrpy = AES_EnorDecrypt.AESEncrypt(mybyte, textBox2.Text, KeyVector);
sw.Write(encrpy, 0, encrpy.Length);
leftBytes -= numBytesRead;
readBytes += numBytesRead;
backgroundWorker1.ReportProgress((int)(readBytes * 100 / sr.Length));
}
else//重新设定读取流大小,避免最后多余空值
{
byte[] newByte = new byte[leftBytes];
sr.Read(newByte, 0, newByte.Length);
byte[] newWriteByte;
newWriteByte = AES_EnorDecrypt.AESEncrypt(newByte, textBox2.Text, KeyVector);
sw.Write(newWriteByte, 0, newWriteByte.Length);
readBytes += leftBytes;
backgroundWorker1.ReportProgress((int)(readBytes * 100 / sr.Length));
break;
}
}
}
else
{
byte[] mybyte = new byte[sr.Length];
sr.Read(mybyte, 0, (int)sr.Length);
mybyte = AES_EnorDecrypt.AESEncrypt(mybyte, textBox2.Text, KeyVector);
sw.Write(mybyte, 0, mybyte.Length);
backgroundWorker1.ReportProgress(100);
}
sr.Close();
sw.Close();
#endregion
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
/// <summary>
/// 执行完成时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("加密成功!");
}
/// <summary>
/// 后台线程执行的方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
try
{
string KeyVector = _aesKeyVector;//密钥向量
string path = Path.GetDirectoryName(textBox1.Text);
string name = Path.GetFileName(textBox1.Text);
if (name.EndsWith(".En"))
{
name = name.Remove(name.Length - 3, 3);
}
#region 解密
FileStream sr = new FileStream(textBox1.Text, FileMode.Open, FileAccess.Read);
FileStream sw = new FileStream(path + "\\" + name, FileMode.Create, FileAccess.Write);
if (sr.Length > 50 * 1024 * 1024)//如果文件大于50M,采取分块解密,按50MB读写
{
byte[] mybyte = new byte[52428816];//解密缓冲区50MB+16B
byte[] decrpt = new byte[52428800];//解密后的50MB
int numBytesRead = 52428816;//每次解密的流大小
long leftBytes = sr.Length;//剩余需要解密的流大小
long readBytes = 0;//已经读取的流大小
try
{
while (true)
{
if (leftBytes > numBytesRead)
{
sr.Read(mybyte, 0, mybyte.Length);
decrpt = AES_EnorDecrypt.AESDecrypt(mybyte, textBox2.Text, KeyVector);
sw.Write(decrpt, 0, decrpt.Length);
leftBytes -= numBytesRead;
readBytes += numBytesRead;
backgroundWorker2.ReportProgress((int)(readBytes * 100 / sr.Length));
}
else//重新设定读取流大小,避免最后多余空值
{
byte[] newByte = new byte[leftBytes];
sr.Read(newByte, 0, newByte.Length);
byte[] newWriteByte;
newWriteByte = AES_EnorDecrypt.AESDecrypt(newByte, textBox2.Text, KeyVector);
sw.Write(newWriteByte, 0, newWriteByte.Length);
readBytes += leftBytes;
backgroundWorker2.ReportProgress((int)(readBytes * 100 / sr.Length));
break;
}
}
}
catch
{
sr.Close();
sw.Close();
File.Delete(path + "\\" + name);
e.Cancel = true;
}
sr.Close();
sw.Close();
}
else
{
byte[] mybyte = new byte[(int)sr.Length];
sr.Read(mybyte, 0, (int)sr.Length);
try
{
mybyte = AES_EnorDecrypt.AESDecrypt(mybyte, textBox2.Text, KeyVector);
sw.Write(mybyte, 0, mybyte.Length);
backgroundWorker2.ReportProgress(100);
}
catch
{
sr.Close();
sw.Close();
File.Delete(path + "\\" + name);
e.Cancel = true;
}
sr.Close();
sw.Close();
}
#endregion
}
catch
{
e.Cancel = true;
}
}
private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
/// <summary>
/// 执行完成时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void backgroundWorker2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("解密失败\n密码错误或加密文件被篡改,无法解密");
}
else
{
MessageBox.Show("解密成功!");
}
}
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341