//************************************************************************ // author: yuzhengyang // date: 2017.6.8 - 2017.6.16 // desc: 文件加密工具 // Copyright (c) yuzhengyang. All rights reserved. //************************************************************************ using Azylee.Core.DataUtils.EncryptUtils; using Azylee.Core.DelegateUtils.ProcessDelegateUtils; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace Azylee.Core.IOUtils.FileUtils { /// /// 文件加密工具 /// public class FileEncryptTool { const string FileType = "Y.Utils.FileEncrypt";//文件类型 禁止修改长度(19位) const string FileVersion = "100001";//类型的版本 禁止修改长度(6位) private static int FileBuffer = 1024 * 1024; public static string FileExt = ".fmencrypt"; /// /// 文件加密 /// /// 源文件 /// 目标文件 /// 加密密码 /// 回调进度 /// 是否覆盖已有目标文件 /// /// >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;//未知错误,操作失败 } /// /// 文件解密 /// /// 源文件 /// 目标文件 /// 解密密码 /// 回调进度 /// 是否覆盖已有目标文件 /// /// >0:操作成功(操作共计秒数) /// -11:要解密的文件不存在 /// -12:解密后的目标文件已存在 /// -20:文件类型不匹配 /// -30:文件头不长度不吻合 /// -90:解锁密码错误 /// -404:未知错误,操作失败 /// public static int Decrypt(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)); List headdata = new List(); using (FileStream fsRead = new FileStream(srcFile, FileMode.Open)) { try { //读取文件类型标识和版本号 byte[] filetype = Encoding.Default.GetBytes(FileType); fsRead.Read(filetype, 0, filetype.Length); string filetypestr = Encoding.Default.GetString(filetype); byte[] fileversion = Encoding.Default.GetBytes(FileVersion); fsRead.Read(fileversion, 0, fileversion.Length); string fileversionstr = Encoding.Default.GetString(fileversion); if (filetypestr != FileType && fileversionstr != FileVersion) return -20;//文件类型不匹配 //读取头部信息个数 byte[] count = new byte[4]; fsRead.Read(count, 0, count.Length); int countint = BitConverter.ToInt32(count, 0); //读取各部分长度和数据 byte[] headlength = new byte[4 * countint]; if (fsRead.Read(headlength, 0, headlength.Length) == headlength.Length) { for (int i = 0; i < countint; i++) { int datalong = BitConverter.ToInt32(headlength, i * 4); byte[] tempdata = new byte[datalong]; fsRead.Read(tempdata, 0, datalong); headdata.Add(Encoding.Default.GetString(tempdata)); } } if (headdata.Count < 5) return -30;//文件头不长度不吻合 if (pwdMd5 != headdata[3]) return -90;//解锁密码错误 using (FileStream fsWrite = new FileStream(dstFile, FileMode.Create)) { int readCount = 0; byte[] buffer = new byte[FileBuffer + 16]; 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[] debyte = AesTool.Decrypt(temp, fmtPwd); fsWrite.Write(debyte, 0, debyte.Length); } else { byte[] debyte = AesTool.Decrypt(buffer, fmtPwd); fsWrite.Write(debyte, 0, debyte.Length); } progress?.Invoke(sender, new ProgressEventArgs(fsRead.Position, fsRead.Length)); } } } catch (Exception e) { } } string md5 = FileTool.GetMD5(dstFile); if (headdata.Count > 1 && md5 == headdata[1]) { return (int)Math.Ceiling((DateTime.Now - beginTime).TotalSeconds);//操作成功 } else { //解密失败后,删除解密的文件 try { File.Delete(dstFile); } catch (Exception e) { } } return -404;//未知错误,操作失败 } } }