23
4月
2020

FBI破门而入解锁电脑文件只看到一串乱码

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.操作说明

interface

图1-主界面

加密:

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");//原文链接!
        }
    }
}

代码链接:

EncryptedFile

原文链接:

https://www.daboke.com/program/aes.html

You may also like...

发表评论

邮箱地址不会被公开。

微信 OR 支付宝 扫描二维码
为本文作者 打个赏
pay_weixin pay_weixin
最喜欢你一言不合就打赏的样子了^_^