FBI破门而入解锁电脑文件只看到一串乱码,这是美剧中经常出现的桥段,每每看到此处我都会被男主的高智商折服。在这个信息量爆炸的时代,无论你是极客,还是码农,都应该了解数据加密,因为它对每个人都有切身影响。
AES,又称为Rijindael加密法, AES发明者中的Vincent Rijmen和Joan Daemen,他们俩把他们的姓结合在一起给AES取乳名为:Rijndael。AES是非常安全的,其中256位的AES甚至是美国神马安全局的标准,今天我们就用它来给电脑文件加解密!
1.AES加密文件
/// <summary> /// AES加密文件的方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button2_Click(object sender, EventArgs e) { //检查被加密文件 if (this.textBox1.Text == "") { MessageBox.Show("请选择被加密文件!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } //获得被加密文件名 string MyInFileName = this.textBox1.Text; //获得加密输出文件名 string MyOutFileName = this.textBox3.Text; //创建输入和输出文件流 FileStream MyInFileStream = new FileStream(MyInFileName, FileMode.Open, FileAccess.Read); FileStream MyOutFileStream = new FileStream(MyOutFileName, FileMode.OpenOrCreate, FileAccess.Write); MyOutFileStream.SetLength(0); //每次的中间流. byte[] InsertData = new byte[100]; //代表已经加密流的大小 int CompletedLength = 0; //代表要加密文件总的大小 long InFileSize = MyInFileStream.Length; //AES加密 RijndaelManaged aes = new RijndaelManaged();//AES的发明者,Vincent Rijmen和Joan Daemen也在他们之中,他们俩把他们的姓结合在一起给AES取乳名为:Rijndael。 aes.Key = Encoding.UTF8.GetBytes(this.PasswordMD5(textBox2.Text));//key是需要32位 aes.IV = Encoding.UTF8.GetBytes(this.PasswordMD5(textBox2.Text).Substring(8, 16));//IV需要16位 aes.Mode = CipherMode.CBC;//加密块链模式,不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。 aes.Padding = PaddingMode.PKCS7; ICryptoTransform transform = aes.CreateEncryptor(); //创建加密流 CryptoStream EncryptStream = new CryptoStream(MyOutFileStream, transform, CryptoStreamMode.Write); //从输入文件中读取流,然后加密到输出文件中 while (CompletedLength < InFileSize) { //每次写入加密文件的数据大小 int Length = MyInFileStream.Read(InsertData, 0, 100); EncryptStream.Write(InsertData, 0, Length); CompletedLength += Length; } //关闭流 EncryptStream.Close(); MyOutFileStream.Close(); MyInFileStream.Close(); MessageBox.Show("文件加密已经操作成功!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); }
2.AES解密文件
/// <summary> /// AES解密文件的方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button4_Click(object sender, EventArgs e) { //检查被解密文件 if (this.textBox1.Text == "") { MessageBox.Show("请选择被解密文件!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } try { //获得要解密的文件名 string MyInFileName = this.textBox1.Text; //获得要保存的文件名 string MyOutFileName = this.textBox3.Text; //创建输入和输出文件流 FileStream MyInFileStream = new FileStream(MyInFileName, FileMode.Open, FileAccess.Read); FileStream MyOutFileStream = new FileStream(MyOutFileName, FileMode.OpenOrCreate, FileAccess.Write); MyOutFileStream.SetLength(0); //每次的中间流. byte[] InsertData = new byte[100]; //代表已经解密的流的大小 int MyCompletedSize = 0; //代表要解密文件总的大小 long MyFileSize = MyInFileStream.Length; //AES解密 RijndaelManaged aes = new RijndaelManaged();//AES的发明者,Vincent Rijmen和Joan Daemen也在他们之中,他们俩把他们的姓结合在一起给AES取乳名为:Rijndael。 aes.Key = Encoding.UTF8.GetBytes(this.PasswordMD5(textBox2.Text));//key是需要32位 aes.IV = Encoding.UTF8.GetBytes(this.PasswordMD5(textBox2.Text).Substring(8, 16));//IV需要16位 aes.Mode = CipherMode.CBC;//加密块链模式,不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。 aes.Padding = PaddingMode.PKCS7; ICryptoTransform transform = aes.CreateDecryptor(); //创建解密流 CryptoStream DecryptStream = new CryptoStream(MyOutFileStream, transform, CryptoStreamMode.Write); //从输入文件中读取流,然后解密到输出文件中 while (MyCompletedSize < MyFileSize) { //每次写入解密流的大小 int length = MyInFileStream.Read(InsertData, 0, 100); DecryptStream.Write(InsertData, 0, length); MyCompletedSize += length; } //关闭流 DecryptStream.Close(); MyOutFileStream.Close(); MyInFileStream.Close(); MessageBox.Show("文件解密操作成功!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception Err) { MessageBox.Show("文件解密操作有误:" + "" + Err + "", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
3.MD5
AES256的key需要32位,IV需要16位,考虑到手动敲入32/16位密码比较繁琐,所以我用了一个 PasswordMD5的方法将密码处理为 32 位。
/// <summary> /// 用MD5将密钥处理为32位 /// </summary> /// <param name="password"></param> /// <returns></returns> public string PasswordMD5(string password) { //首次加密 MD5 md5 = MD5.Create(); byte[] bs = Encoding.UTF8.GetBytes(password); byte[] hs = md5.ComputeHash(bs); StringBuilder sb = new StringBuilder(); foreach (byte b in hs) { sb.Append(b.ToString("x2")); } //再次加密 byte[] nbs = Encoding.UTF8.GetBytes(password); byte[] nhs = md5.ComputeHash(nbs); StringBuilder nsb = new StringBuilder(); foreach (byte nb in nhs) { nsb.Append(nb.ToString("x2")); } return nsb.ToString(); }
4.操作说明
加密:
1)点击”浏览文件”按钮,选择需要加密的文件(图片、文本或表格等),自动生成文件路径。
2)在”输出文件名”框中输入保存文件名(包括路径),因为使用了文件的输入流和输出流,所以输入和输出文件名不能相同。
3)在”密钥”框输入密码,由于使用了MD5处理自动转化成32位,所以对密码长度无要求。
4)点击”加密文件”按钮即可输出加密文件,源文件依然存在互不影响。
解密:
解密操作与加密一致,输入之前设定的加密密钥进行解密。
补充:
加密后输出的文件,打开时可能什么也看不到,并不是文件损坏,依然可以正常解密。
代码全文:
using System; using System.IO; using System.Text; using System.Windows.Forms; using System.Security.Cryptography; namespace EncryptedFile { public partial class Form1 : Form { public Form1() { InitializeComponent(); } /// <summary> /// 文件浏览对话框 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button1_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "所有文件|*.*"; ofd.ValidateNames = true; ofd.CheckPathExists = true; ofd.CheckFileExists = true; if (ofd.ShowDialog() == DialogResult.OK) { string strFileName = ofd.FileName; textBox1.Text = strFileName; } } /// <summary> /// 用MD5将密钥处理为32位 /// </summary> /// <param name="password"></param> /// <returns></returns> public string PasswordMD5(string password) { //首次加密 MD5 md5 = MD5.Create(); byte[] bs = Encoding.UTF8.GetBytes(password); byte[] hs = md5.ComputeHash(bs); StringBuilder sb = new StringBuilder(); foreach (byte b in hs) { sb.Append(b.ToString("x2")); } //再次加密 byte[] nbs = Encoding.UTF8.GetBytes(password); byte[] nhs = md5.ComputeHash(nbs); StringBuilder nsb = new StringBuilder(); foreach (byte nb in nhs) { nsb.Append(nb.ToString("x2")); } return nsb.ToString(); } /// <summary> /// AES加密文件的方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button2_Click(object sender, EventArgs e) { //检查被加密文件 if (this.textBox1.Text == "") { MessageBox.Show("请选择被加密文件!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } //获得被加密文件名 string MyInFileName = this.textBox1.Text; //获得加密输出文件名 string MyOutFileName = this.textBox3.Text; //创建输入和输出文件流 FileStream MyInFileStream = new FileStream(MyInFileName, FileMode.Open, FileAccess.Read); FileStream MyOutFileStream = new FileStream(MyOutFileName, FileMode.OpenOrCreate, FileAccess.Write); MyOutFileStream.SetLength(0); //每次的中间流. byte[] InsertData = new byte[100]; //代表已经加密流的大小 int CompletedLength = 0; //代表要加密文件总的大小 long InFileSize = MyInFileStream.Length; //AES加密 RijndaelManaged aes = new RijndaelManaged();//AES的发明者,Vincent Rijmen和Joan Daemen也在他们之中,他们俩把他们的姓结合在一起给AES取乳名为:Rijndael。 aes.Key = Encoding.UTF8.GetBytes(this.PasswordMD5(textBox2.Text));//key是需要32位 aes.IV = Encoding.UTF8.GetBytes(this.PasswordMD5(textBox2.Text).Substring(8, 16));//IV需要16位 aes.Mode = CipherMode.CBC;//加密块链模式,不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。 aes.Padding = PaddingMode.PKCS7; ICryptoTransform transform = aes.CreateEncryptor(); //创建加密流 CryptoStream EncryptStream = new CryptoStream(MyOutFileStream, transform, CryptoStreamMode.Write); //从输入文件中读取流,然后加密到输出文件中 while (CompletedLength < InFileSize) { //每次写入加密文件的数据大小 int Length = MyInFileStream.Read(InsertData, 0, 100); EncryptStream.Write(InsertData, 0, Length); CompletedLength += Length; } //关闭流 EncryptStream.Close(); MyOutFileStream.Close(); MyInFileStream.Close(); MessageBox.Show("文件加密已经操作成功!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } /// <summary> /// AES解密文件的方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Button4_Click(object sender, EventArgs e) { //检查被解密文件 if (this.textBox1.Text == "") { MessageBox.Show("请选择被解密文件!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } try { //获得要解密的文件名 string MyInFileName = this.textBox1.Text; //获得要保存的文件名 string MyOutFileName = this.textBox3.Text; //创建输入和输出文件流 FileStream MyInFileStream = new FileStream(MyInFileName, FileMode.Open, FileAccess.Read); FileStream MyOutFileStream = new FileStream(MyOutFileName, FileMode.OpenOrCreate, FileAccess.Write); MyOutFileStream.SetLength(0); //每次的中间流. byte[] InsertData = new byte[100]; //代表已经解密的流的大小 int MyCompletedSize = 0; //代表要解密文件总的大小 long MyFileSize = MyInFileStream.Length; //AES解密 RijndaelManaged aes = new RijndaelManaged();//AES的发明者,Vincent Rijmen和Joan Daemen也在他们之中,他们俩把他们的姓结合在一起给AES取乳名为:Rijndael。 aes.Key = Encoding.UTF8.GetBytes(this.PasswordMD5(textBox2.Text));//key是需要32位 aes.IV = Encoding.UTF8.GetBytes(this.PasswordMD5(textBox2.Text).Substring(8, 16));//IV需要16位 aes.Mode = CipherMode.CBC;//加密块链模式,不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。 aes.Padding = PaddingMode.PKCS7; ICryptoTransform transform = aes.CreateDecryptor(); //创建解密流 CryptoStream DecryptStream = new CryptoStream(MyOutFileStream, transform, CryptoStreamMode.Write); //从输入文件中读取流,然后解密到输出文件中 while (MyCompletedSize < MyFileSize) { //每次写入解密流的大小 int length = MyInFileStream.Read(InsertData, 0, 100); DecryptStream.Write(InsertData, 0, length); MyCompletedSize += length; } //关闭流 DecryptStream.Close(); MyOutFileStream.Close(); MyInFileStream.Close(); MessageBox.Show("文件解密操作成功!", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception Err) { MessageBox.Show("文件解密操作有误:" + "" + Err + "", "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void Button3_Click(object sender, EventArgs e) { System.Diagnostics.Process.Start("https://www.daboke.com");//欢迎访问大博客,探索更多编程实战案例! } private void Button5_Click(object sender, EventArgs e) { System.Diagnostics.Process.Start("https://www.daboke.com/program/aes");//原文链接! } } }
代码链接:
原文链接: