目录
- 先上效果图
- 先添加辅助类
- 开始实现
- 总结
先上效果图
文件和加密文件之间的转换。
先添加辅助类
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 | |
{ | |
private static string _aesKeyVector = "q2T_=R/*33vc"; | |
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"; | |
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(); | |
} | |
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); | |
} | |
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(); | |
} | |
} | |
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("解密成功!"); | |
} | |
} | |
} |