C#中实现AES算法加密解读
作者:yangzm996
这篇文章主要介绍了C#中实现AES算法加密实例,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
先上效果图
文件和加密文件之间的转换。
先添加辅助类
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("解密成功!"); } } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。