C#中实现AES算法加密解读
作者:yangzm996 发布时间:2022-09-17 16:49:36
标签: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("解密成功!");
}
}
}
来源:https://blog.csdn.net/weixin_39448579/article/details/119953604


猜你喜欢
- 本文实例为大家分享了Unity2D游戏回旋镖实现的具体代码,供大家参考,具体内容如下以下我举出2种同使用情况的回旋镖那么回旋镖需要怎么做呢?
- 前言相信每位Android开发者都用过Toast,都知道是弹出消息的。类似于js里面的alert,C#里面的MesageBox。当然andr
- 再使用整型转string的时候感觉有点棘手,因为itoa不是标准C里面的,而且即便是有itoa,其他类型转string不是很方便。后来去网上
- Java进阶之FileUpload完成上传的实例 FileUpload是Apache commons下面
- 开发前准备支付宝开发平台.支付宝沙箱环境申请使用!!!重点 授权回调地址必须要写全路径也就是controller最终路径(下面有具体细节)R
- 在Flutter开发过程中,我门有时候需要对一些数据进行本地的持久化存储,使用sp文件形式虽然也能解决问题,但是有时数据量较大的时候,显然我
- MyBaties的基本配置标签1-全局配置文件(xxx.properties)引入的两种方式resource:引入类路径下的资源url:引入
- 在开发过程中,与用户交互式免不了会用到对话框以实现更好的用户体验,所以掌握几种对话框的实现方法还是非常有必要的。在看具体实例之前先对Aler
- 编写程序,实现顺序表的下列功能:从键盘输入数据建立一个顺序表输出该顺序表往顺序表中插入数据从顺序表中删除数据给定数据,进行查找,给出查找成功
- 本文实例为大家分享了Java使用单链表实现约瑟夫环的具体代码,供大家参考,具体内容如下构建一个单向的环形链表思路1.先创建第一个节点, 让f
- 夏天到了、小雪来给大家降降温话不多说、直接进入主题主要功能模块设计:登录注册、首页信息浏览、选课分类查看、选课详情查看、评论交流、收藏、浏览
- IO流Java中IO流分为两种,字节流和字符流,顾名思义字节流就是按照字节来读取和写入的,字符刘是按照字符来存取的;常用的文件读取用的就是字
- 注册中心呢 就是springcloud的一个核心组件 所有微服务的基石 微服务的核心思想就是分布式 所有的服务分开管理 但这些服务分开后该如
- 一、简介线程安全概念:线程安全是指在当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出
- 前言当我们在手机上使用360安全卫士时,手机屏幕上时刻都会出现一个小浮动窗口,点击该浮动窗口可跳转到安全卫士的操作界面,而且该浮动窗口不受其
- java 深拷贝与浅拷贝机制详解概要:在Java中,拷贝分为深拷贝和浅拷贝两种。java在公共超类Object中实现了一种叫做c
- 嵌套查询使用Fluent Mybatis, 不用手写一行xml文件或者Mapper文件,在dao类中即可使用java api构造中比较复杂的
- 效果图如下所示: 1、在Adapter中加入如下代码<pre style="background-color:#2
- 简介Java注解是JDK1.5引入的一种注释机制,它不会改变编译器的编译方式,Java编译器对包含注解和不包含注解的代码会生成相同的Java
- 原因:feign传值出错无法接收到传值由于是POST所以添加@RequestBody进行尝试解决:错误原因是未添加@RequestBody尝