FileEncryptTool.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. //************************************************************************
  2. // https://github.com/yuzhengyang
  3. // author: yuzhengyang
  4. // date: 2017.6.8 - 2017.6.16
  5. // desc: 文件加密工具
  6. // Copyright (c) yuzhengyang. All rights reserved.
  7. //************************************************************************
  8. using System;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Linq;
  12. using System.Text;
  13. using Y.Utils.DataUtils.EncryptUtils;
  14. using Y.Utils.DelegateUtils;
  15. namespace Y.Utils.IOUtils.FileUtils
  16. {
  17. /// <summary>
  18. /// 文件加密工具
  19. /// </summary>
  20. public class FileEncryptTool
  21. {
  22. const string FileType = "Y.Utils.FileEncrypt";//文件类型 禁止修改长度(19位)
  23. const string FileVersion = "100001";//类型的版本 禁止修改长度(6位)
  24. private static int FileBuffer = 1024 * 1024;
  25. public static string FileExt = ".fmencrypt";
  26. /// <summary>
  27. /// 文件加密
  28. /// </summary>
  29. /// <param name="srcFile">源文件</param>
  30. /// <param name="dstFile">目标文件</param>
  31. /// <param name="password">加密密码</param>
  32. /// <param name="progress">回调进度</param>
  33. /// <param name="overwrite">是否覆盖已有目标文件</param>
  34. /// <returns>
  35. /// >0:操作成功(操作共计秒数)
  36. /// -11:要加密的文件不存在
  37. /// -12:加密后的目标文件已存在
  38. /// -404:未知错误,操作失败
  39. /// </returns>
  40. public static int Encrypt(string srcFile, string dstFile, string password, ProgressDelegate.ProgressHandler progress = null, object sender = null, bool overwrite = true)
  41. {
  42. DateTime beginTime = DateTime.Now;
  43. if (!File.Exists(srcFile)) return -11; //要加密的文件不存在
  44. if (File.Exists(dstFile) && !overwrite) return -12;//加密后的目标文件已存在
  45. string fmtPwd = AesTool.FmtPassword(password);
  46. string pwdMd5 = MD5Tool.Encrypt(MD5Tool.Encrypt(fmtPwd));
  47. string md5 = FileTool.GetMD5(srcFile);
  48. using (FileStream fsRead = new FileStream(srcFile, FileMode.Open))
  49. {
  50. using (FileStream fsWrite = new FileStream(dstFile, FileMode.Create))
  51. {
  52. try
  53. {
  54. //写入文件类型标识和版本号
  55. byte[] filetypeandversion = Encoding.Default.GetBytes(FileType + FileVersion);
  56. fsWrite.Write(filetypeandversion, 0, filetypeandversion.Length);
  57. //文件头部数据定义
  58. List<byte[]> headdata = new List<byte[]>()
  59. {
  60. Encoding.Default.GetBytes(FileType),
  61. Encoding.Default.GetBytes(md5),
  62. Encoding.Default.GetBytes(AesTool.Encrypt(fmtPwd,AesTool.DefaultPassword)),
  63. Encoding.Default.GetBytes(pwdMd5),
  64. Encoding.Default.GetBytes(DateTime.Now.ToString())
  65. };
  66. //写入头部信息个数
  67. byte[] count = BitConverter.GetBytes(headdata.Count);
  68. fsWrite.Write(count, 0, count.Length);
  69. //写入各部分长度
  70. for (int i = 0; i < headdata.Count; i++)
  71. {
  72. byte[] length = BitConverter.GetBytes(headdata[i].Length);
  73. fsWrite.Write(length, 0, length.Length);
  74. }
  75. //写入各部分数据
  76. for (int i = 0; i < headdata.Count; i++)
  77. {
  78. fsWrite.Write(headdata[i], 0, headdata[i].Length);
  79. }
  80. //写入文件源数据
  81. int readCount = 0;
  82. byte[] buffer = new byte[FileBuffer];
  83. while ((readCount = fsRead.Read(buffer, 0, buffer.Length)) > 0)
  84. {
  85. if (readCount != buffer.Length)
  86. {
  87. byte[] temp = new byte[readCount];
  88. Buffer.BlockCopy(buffer, 0, temp, 0, readCount);
  89. byte[] enbyte = AesTool.Encrypt(temp, fmtPwd);
  90. fsWrite.Write(enbyte, 0, enbyte.Length);
  91. }
  92. else
  93. {
  94. byte[] enbyte = AesTool.Encrypt(buffer, fmtPwd);
  95. fsWrite.Write(enbyte, 0, enbyte.Length);
  96. }
  97. progress?.Invoke(sender, new ProgressEventArgs(fsRead.Position, fsRead.Length));
  98. }
  99. return (int)Math.Ceiling((DateTime.Now - beginTime).TotalSeconds);//操作成功
  100. }
  101. catch (Exception e) { }
  102. }
  103. //加密失败后,删除加密的文件
  104. try { File.Delete(dstFile); } catch (Exception e) { }
  105. }
  106. return -404;//未知错误,操作失败
  107. }
  108. /// <summary>
  109. /// 文件解密
  110. /// </summary>
  111. /// <param name="srcFile">源文件</param>
  112. /// <param name="dstFile">目标文件</param>
  113. /// <param name="password">解密密码</param>
  114. /// <param name="progress">回调进度</param>
  115. /// <param name="overwrite">是否覆盖已有目标文件</param>
  116. /// <returns>
  117. /// >0:操作成功(操作共计秒数)
  118. /// -11:要解密的文件不存在
  119. /// -12:解密后的目标文件已存在
  120. /// -20:文件类型不匹配
  121. /// -30:文件头不长度不吻合
  122. /// -90:解锁密码错误
  123. /// -404:未知错误,操作失败
  124. /// </returns>
  125. public static int Decrypt(string srcFile, string dstFile, string password, ProgressDelegate.ProgressHandler progress = null, object sender = null, bool overwrite = true)
  126. {
  127. DateTime beginTime = DateTime.Now;
  128. if (!File.Exists(srcFile)) return -11;//要解密的文件不存在
  129. if (File.Exists(dstFile) && !overwrite) return -12;//解密后的目标文件已存在
  130. string fmtPwd = AesTool.FmtPassword(password);
  131. string pwdMd5 = MD5Tool.Encrypt(MD5Tool.Encrypt(fmtPwd));
  132. List<string> headdata = new List<string>();
  133. using (FileStream fsRead = new FileStream(srcFile, FileMode.Open))
  134. {
  135. try
  136. {
  137. //读取文件类型标识和版本号
  138. byte[] filetype = Encoding.Default.GetBytes(FileType);
  139. fsRead.Read(filetype, 0, filetype.Length);
  140. string filetypestr = Encoding.Default.GetString(filetype);
  141. byte[] fileversion = Encoding.Default.GetBytes(FileVersion);
  142. fsRead.Read(fileversion, 0, fileversion.Length);
  143. string fileversionstr = Encoding.Default.GetString(fileversion);
  144. if (filetypestr != FileType && fileversionstr != FileVersion) return -20;//文件类型不匹配
  145. //读取头部信息个数
  146. byte[] count = new byte[4];
  147. fsRead.Read(count, 0, count.Length);
  148. int countint = BitConverter.ToInt32(count, 0);
  149. //读取各部分长度和数据
  150. byte[] headlength = new byte[4 * countint];
  151. if (fsRead.Read(headlength, 0, headlength.Length) == headlength.Length)
  152. {
  153. for (int i = 0; i < countint; i++)
  154. {
  155. int datalong = BitConverter.ToInt32(headlength, i * 4);
  156. byte[] tempdata = new byte[datalong];
  157. fsRead.Read(tempdata, 0, datalong);
  158. headdata.Add(Encoding.Default.GetString(tempdata));
  159. }
  160. }
  161. if (headdata.Count < 5) return -30;//文件头不长度不吻合
  162. if (pwdMd5 != headdata[3]) return -90;//解锁密码错误
  163. using (FileStream fsWrite = new FileStream(dstFile, FileMode.Create))
  164. {
  165. int readCount = 0;
  166. byte[] buffer = new byte[FileBuffer + 16];
  167. while ((readCount = fsRead.Read(buffer, 0, buffer.Length)) > 0)
  168. {
  169. if (readCount != buffer.Length)
  170. {
  171. byte[] temp = new byte[readCount];
  172. Buffer.BlockCopy(buffer, 0, temp, 0, readCount);
  173. byte[] debyte = AesTool.Decrypt(temp, fmtPwd);
  174. fsWrite.Write(debyte, 0, debyte.Length);
  175. }
  176. else
  177. {
  178. byte[] debyte = AesTool.Decrypt(buffer, fmtPwd);
  179. fsWrite.Write(debyte, 0, debyte.Length);
  180. }
  181. progress?.Invoke(sender, new ProgressEventArgs(fsRead.Position, fsRead.Length));
  182. }
  183. }
  184. }
  185. catch (Exception e) { }
  186. }
  187. string md5 = FileTool.GetMD5(dstFile);
  188. if (headdata.Count > 1 && md5 == headdata[1])
  189. {
  190. return (int)Math.Ceiling((DateTime.Now - beginTime).TotalSeconds);//操作成功
  191. }
  192. else
  193. {
  194. //解密失败后,删除解密的文件
  195. try { File.Delete(dstFile); } catch (Exception e) { }
  196. }
  197. return -404;//未知错误,操作失败
  198. }
  199. }
  200. }