csdn下载分会越来越高,所以我转存到百度盘了,有需要的朋友可以从这里下载
百度盘链接
链接:https://pan.baidu.com/s/1bK4sug-eK85fmPgi9DzhcA 提取码:0vp3
源码可以参考github
GitHub
CSDN下载(csdn自动把分调高了…)
最近看了一下加密算法,对加密文件突然很感兴趣,就研究了一下:
加密:
解密:
选择文件:
内存及CPU的使用:
首先,文件要加密就一定要解密,所以一定要找个能解密的算法,这个不用多说……其实加密解密算法也算是C#里自带了,代码如下:
///
/// 加密
///
/// 要加密的 byte[] 数组
///
///
public static byte[] Encrypt(byte[] array, string key)
{
key = FmtPassword(key);
byte[] keyArray = Encoding.UTF8.GetBytes(key);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(array, 0, array.Length);
return resultArray;
}
///
/// 解密
///
/// 要解密的 byte[] 数组
///
///
public static byte[] Decrypt(byte[] array, string key)
{
key = FmtPassword(key);
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(array, 0, array.Length);
return resultArray;
}
这里要注意一点,AES加密的话,密码是需要32位的,不然会提示错误:DES和AES加密:指定键的大小对于此算法无效
所以需要自己把不够长度的密码填充一下(超出长度的也需要处理一下),避免出现这种错误
文件加密的功能网上有很多,我发现有很多直接把文件全部读取出来,然后加密整个文件。这种方法在处理大文件会消耗非常大的内存,所以需要注意不能一次性把文件全加密。
注1: 关于加密的部分,可以只加密文件的一部分数据,这样可以保证加密速度。
注2: 使用流读取部分,循环加密的时候,AES加密后的内容长度会增加,比如要加密一个 byte[1024] 大小的内容,加密后会变成 byte[1024+16] ,这一点可以自己试一试。
进度方面是很有必要的,在加密大文件的时候,如果光等着没有进度也显得很尴尬,所以做一个委托,来把进度回调出来。
// 定义
public delegate void ProgressHandler(object sender, ProgressEventArgs e);
// 使用
progress?.Invoke(sender, new ProgressEventArgs(fsRead.Position, fsRead.Length));
加密文件后的文件结构是要自己重新做定义的,使自己的程序能读懂,并且能成功解密即可。这里贴一个文件加密的方法:
里面有很多我自己写的方法,下面会给链接地址
///
/// 文件加密
///
/// 源文件
/// 目标文件
/// 加密密码
/// 回调进度
/// 是否覆盖已有目标文件
///
/// >0:操作成功(操作共计秒数)
/// -11:要加密的文件不存在
/// -12:加密后的目标文件已存在
/// -404:未知错误,操作失败
///
public static int Encrypt(string srcFile, string dstFile, string password, ProgressDelegate.ProgressHandler progress = null, object sender = null, bool overwrite = true)
{
DateTime beginTime = DateTime.Now;
if (!File.Exists(srcFile)) return -11; //要加密的文件不存在
if (File.Exists(dstFile) && !overwrite) return -12;//加密后的目标文件已存在
string fmtPwd = AesTool.FmtPassword(password);
string pwdMd5 = MD5Tool.Encrypt(MD5Tool.Encrypt(fmtPwd));
string md5 = FileTool.GetMD5(srcFile);
using (FileStream fsRead = new FileStream(srcFile, FileMode.Open))
{
using (FileStream fsWrite = new FileStream(dstFile, FileMode.Create))
{
try
{
//写入文件类型标识和版本号
byte[] filetypeandversion = Encoding.Default.GetBytes(FileType + FileVersion);
fsWrite.Write(filetypeandversion, 0, filetypeandversion.Length);
//文件头部数据定义
List headdata = new List()
{
Encoding.Default.GetBytes(FileType),
Encoding.Default.GetBytes(md5),
Encoding.Default.GetBytes(AesTool.Encrypt(fmtPwd,AesTool.DefaultPassword)),
Encoding.Default.GetBytes(pwdMd5),
Encoding.Default.GetBytes(DateTime.Now.ToString())
};
//写入头部信息个数
byte[] count = BitConverter.GetBytes(headdata.Count);
fsWrite.Write(count, 0, count.Length);
//写入各部分长度
for (int i = 0; i < headdata.Count; i++)
{
byte[] length = BitConverter.GetBytes(headdata[i].Length);
fsWrite.Write(length, 0, length.Length);
}
//写入各部分数据
for (int i = 0; i < headdata.Count; i++)
{
fsWrite.Write(headdata[i], 0, headdata[i].Length);
}
//写入文件源数据
int readCount = 0;
byte[] buffer = new byte[FileBuffer];
while ((readCount = fsRead.Read(buffer, 0, buffer.Length)) > 0)
{
if (readCount != buffer.Length)
{
byte[] temp = new byte[readCount];
Buffer.BlockCopy(buffer, 0, temp, 0, readCount);
byte[] enbyte = AesTool.Encrypt(temp, fmtPwd);
fsWrite.Write(enbyte, 0, enbyte.Length);
}
else
{
byte[] enbyte = AesTool.Encrypt(buffer, fmtPwd);
fsWrite.Write(enbyte, 0, enbyte.Length);
}
progress?.Invoke(sender, new ProgressEventArgs(fsRead.Position, fsRead.Length));
}
return (int)Math.Ceiling((DateTime.Now - beginTime).TotalSeconds);//操作成功
}
catch (Exception e) { }
}
//加密失败后,删除加密的文件
try { File.Delete(dstFile); } catch (Exception e) { }
}
return -404;//未知错误,操作失败
}