EncryptUtil.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. using System;
  2. using System.IO;
  3. using System.Security.Cryptography;
  4. using System.Text;
  5. using PaySharp.Core.Exceptions;
  6. namespace PaySharp.Core.Utils
  7. {
  8. /// <summary>
  9. /// 加密工具类
  10. /// </summary>
  11. public static class EncryptUtil
  12. {
  13. #region 私有字段
  14. /// <summary>
  15. /// 默认编码
  16. /// </summary>
  17. private static readonly string _defaultCharset = "UTF-8";
  18. #endregion
  19. #region MD5加密
  20. /// <summary>
  21. /// MD5加密
  22. /// </summary>
  23. /// <param name="data">数据</param>
  24. public static string MD5(string data)
  25. {
  26. return MD5(data, Encoding.UTF8);
  27. }
  28. /// <summary>
  29. /// MD5加密
  30. /// </summary>
  31. /// <param name="data">数据</param>
  32. /// <param name="encoding">编码</param>
  33. /// <returns></returns>
  34. public static string MD5(string data, Encoding encoding)
  35. {
  36. var md5 = System.Security.Cryptography.MD5.Create();
  37. var dataByte = md5.ComputeHash(encoding.GetBytes(data));
  38. return BitConverter.ToString(dataByte).Replace("-", "");
  39. }
  40. #endregion
  41. #region RSA加密
  42. /// <summary>
  43. /// RSA加密
  44. /// </summary>
  45. /// <param name="data">数据</param>
  46. /// <param name="privateKey">私钥</param>
  47. /// <param name="signType">签名类型</param>
  48. /// <returns></returns>
  49. public static string RSA(string data, string privateKey, string signType)
  50. {
  51. return RSA(data, privateKey, _defaultCharset, signType, false);
  52. }
  53. private static string RSA(string data, string privateKeyPem, string charset, string signType, bool keyFromFile)
  54. {
  55. byte[] signatureBytes = null;
  56. try
  57. {
  58. RSA rsaCsp = null;
  59. if (keyFromFile)
  60. {
  61. //文件读取
  62. rsaCsp = LoadCertificateFile(privateKeyPem, signType);
  63. }
  64. else
  65. {
  66. //字符串获取
  67. rsaCsp = LoadCertificateString(privateKeyPem, signType);
  68. }
  69. byte[] dataBytes = null;
  70. if (string.IsNullOrEmpty(charset))
  71. {
  72. dataBytes = Encoding.UTF8.GetBytes(data);
  73. }
  74. else
  75. {
  76. dataBytes = Encoding.GetEncoding(charset).GetBytes(data);
  77. }
  78. if (null == rsaCsp)
  79. {
  80. throw new GatewayException("您使用的私钥格式错误,请检查RSA私钥配置" + ",charset = " + charset);
  81. }
  82. if ("RSA2".Equals(signType))
  83. {
  84. #if NETCOREAPP3_1
  85. signatureBytes = rsaCsp.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
  86. #else
  87. signatureBytes = ((RSACryptoServiceProvider)rsaCsp).SignData(dataBytes, "SHA256");
  88. #endif
  89. }
  90. else
  91. {
  92. #if NETCOREAPP3_1
  93. signatureBytes = rsaCsp.SignData(dataBytes, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
  94. #else
  95. signatureBytes = ((RSACryptoServiceProvider)rsaCsp).SignData(dataBytes, "SHA1");
  96. #endif
  97. }
  98. }
  99. catch
  100. {
  101. throw new GatewayException("您使用的私钥格式错误,请检查RSA私钥配置" + ",charset = " + charset);
  102. }
  103. return Convert.ToBase64String(signatureBytes);
  104. }
  105. /// <summary>
  106. /// RSA2验签
  107. /// </summary>
  108. /// <param name="data">数据</param>
  109. /// <param name="sign">签名</param>
  110. /// <param name="publicKey">公钥</param>
  111. /// <param name="signType">签名类型</param>
  112. /// <returns></returns>
  113. public static bool RSAVerifyData(string data, string sign, string publicKey, string signType)
  114. {
  115. return RSAVerifyData(data, sign, publicKey, _defaultCharset, signType, false);
  116. }
  117. private static bool RSAVerifyData(string signContent, string sign, string publicKeyPem, string charset, string signType, bool keyFromFile)
  118. {
  119. try
  120. {
  121. var sPublicKeyPEM = publicKeyPem;
  122. if (keyFromFile)
  123. {
  124. sPublicKeyPEM = File.ReadAllText(publicKeyPem);
  125. }
  126. var rsa = CreateRsaProviderFromPublicKey(sPublicKeyPEM, signType);
  127. var bVerifyResultOriginal = false;
  128. if ("RSA2".Equals(signType))
  129. {
  130. #if NETCOREAPP3_1
  131. bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent),
  132. Convert.FromBase64String(sign), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
  133. #else
  134. bVerifyResultOriginal = ((RSACryptoServiceProvider)rsa).VerifyData(
  135. Encoding.GetEncoding(charset).GetBytes(signContent), "SHA256", Convert.FromBase64String(sign));
  136. #endif
  137. }
  138. else
  139. {
  140. #if NETCOREAPP3_1
  141. bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent),
  142. Convert.FromBase64String(sign), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
  143. #else
  144. bVerifyResultOriginal = ((RSACryptoServiceProvider)rsa).VerifyData(
  145. Encoding.GetEncoding(charset).GetBytes(signContent), "SHA1", Convert.FromBase64String(sign));
  146. #endif
  147. }
  148. return bVerifyResultOriginal;
  149. }
  150. catch
  151. {
  152. return false;
  153. }
  154. }
  155. private static RSA CreateRsaProviderFromPublicKey(string publicKeyString, string signType)
  156. {
  157. byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
  158. var seq = new byte[15];
  159. var x509Key = Convert.FromBase64String(publicKeyString);
  160. using var mem = new MemoryStream(x509Key);
  161. using var binr = new BinaryReader(mem);
  162. byte bt = 0;
  163. ushort twobytes = 0;
  164. twobytes = binr.ReadUInt16();
  165. if (twobytes == 0x8130)
  166. {
  167. binr.ReadByte();
  168. }
  169. else if (twobytes == 0x8230)
  170. {
  171. binr.ReadInt16();
  172. }
  173. else
  174. {
  175. return null;
  176. }
  177. seq = binr.ReadBytes(15);
  178. if (!CompareBytearrays(seq, seqOid))
  179. {
  180. return null;
  181. }
  182. twobytes = binr.ReadUInt16();
  183. if (twobytes == 0x8103)
  184. {
  185. binr.ReadByte();
  186. }
  187. else if (twobytes == 0x8203)
  188. {
  189. binr.ReadInt16();
  190. }
  191. else
  192. {
  193. return null;
  194. }
  195. bt = binr.ReadByte();
  196. if (bt != 0x00)
  197. {
  198. return null;
  199. }
  200. twobytes = binr.ReadUInt16();
  201. if (twobytes == 0x8130)
  202. {
  203. binr.ReadByte();
  204. }
  205. else if (twobytes == 0x8230)
  206. {
  207. binr.ReadInt16();
  208. }
  209. else
  210. {
  211. return null;
  212. }
  213. twobytes = binr.ReadUInt16();
  214. byte lowbyte = 0x00;
  215. byte highbyte = 0x00;
  216. if (twobytes == 0x8102)
  217. {
  218. lowbyte = binr.ReadByte();
  219. }
  220. else if (twobytes == 0x8202)
  221. {
  222. highbyte = binr.ReadByte();
  223. lowbyte = binr.ReadByte();
  224. }
  225. else
  226. {
  227. return null;
  228. }
  229. byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
  230. var modsize = BitConverter.ToInt32(modint, 0);
  231. var firstbyte = binr.PeekChar();
  232. if (firstbyte == 0x00)
  233. {
  234. binr.ReadByte();
  235. modsize -= 1;
  236. }
  237. var modulus = binr.ReadBytes(modsize);
  238. if (binr.ReadByte() != 0x02)
  239. {
  240. return null;
  241. }
  242. int expbytes = binr.ReadByte();
  243. var exponent = binr.ReadBytes(expbytes);
  244. var rsa = System.Security.Cryptography.RSA.Create();
  245. rsa.KeySize = signType == "RSA" ? 1024 : 2048;
  246. var rsaKeyInfo = new RSAParameters
  247. {
  248. Modulus = modulus,
  249. Exponent = exponent
  250. };
  251. rsa.ImportParameters(rsaKeyInfo);
  252. return rsa;
  253. }
  254. private static bool CompareBytearrays(byte[] a, byte[] b)
  255. {
  256. if (a.Length != b.Length)
  257. {
  258. return false;
  259. }
  260. var i = 0;
  261. foreach (var c in a)
  262. {
  263. if (c != b[i])
  264. {
  265. return false;
  266. }
  267. i++;
  268. }
  269. return true;
  270. }
  271. private static RSA LoadCertificateFile(string filename, string signType)
  272. {
  273. using var fs = File.OpenRead(filename);
  274. var data = new byte[fs.Length];
  275. byte[] res = null;
  276. fs.Read(data, 0, data.Length);
  277. if (data[0] != 0x30)
  278. {
  279. res = GetPem("RSA PRIVATE KEY", data);
  280. }
  281. try
  282. {
  283. return DecodeRSAPrivateKey(res, signType);
  284. }
  285. catch
  286. {
  287. return null;
  288. }
  289. }
  290. private static RSA LoadCertificateString(string strKey, string signType)
  291. {
  292. var data = Convert.FromBase64String(strKey);
  293. try
  294. {
  295. return DecodeRSAPrivateKey(data, signType);
  296. }
  297. catch
  298. {
  299. return null;
  300. }
  301. }
  302. private static RSA DecodeRSAPrivateKey(byte[] privkey, string signType)
  303. {
  304. byte[] modulus, e, d, p, q, dP, dQ, iQ;
  305. var mem = new MemoryStream(privkey);
  306. var binr = new BinaryReader(mem);
  307. try
  308. {
  309. var twobytes = binr.ReadUInt16();
  310. if (twobytes == 0x8130)
  311. {
  312. binr.ReadByte();
  313. }
  314. else if (twobytes == 0x8230)
  315. {
  316. binr.ReadInt16();
  317. }
  318. else
  319. {
  320. return null;
  321. }
  322. twobytes = binr.ReadUInt16();
  323. if (twobytes != 0x0102)
  324. {
  325. return null;
  326. }
  327. var bt = binr.ReadByte();
  328. if (bt != 0x00)
  329. {
  330. return null;
  331. }
  332. var elems = GetIntegerSize(binr);
  333. modulus = binr.ReadBytes(elems);
  334. elems = GetIntegerSize(binr);
  335. e = binr.ReadBytes(elems);
  336. elems = GetIntegerSize(binr);
  337. d = binr.ReadBytes(elems);
  338. elems = GetIntegerSize(binr);
  339. p = binr.ReadBytes(elems);
  340. elems = GetIntegerSize(binr);
  341. q = binr.ReadBytes(elems);
  342. elems = GetIntegerSize(binr);
  343. dP = binr.ReadBytes(elems);
  344. elems = GetIntegerSize(binr);
  345. dQ = binr.ReadBytes(elems);
  346. elems = GetIntegerSize(binr);
  347. iQ = binr.ReadBytes(elems);
  348. var bitLen = 1024;
  349. if ("RSA2".Equals(signType))
  350. {
  351. bitLen = 2048;
  352. }
  353. var rsa = System.Security.Cryptography.RSA.Create();
  354. rsa.KeySize = bitLen;
  355. var rsaParams = new RSAParameters
  356. {
  357. Modulus = modulus,
  358. Exponent = e,
  359. D = d,
  360. P = p,
  361. Q = q,
  362. DP = dP,
  363. DQ = dQ,
  364. InverseQ = iQ
  365. };
  366. rsa.ImportParameters(rsaParams);
  367. return rsa;
  368. }
  369. catch
  370. {
  371. return null;
  372. }
  373. finally
  374. {
  375. binr.Close();
  376. }
  377. }
  378. private static byte[] GetPem(string type, byte[] data)
  379. {
  380. var pem = Encoding.UTF8.GetString(data);
  381. var header = string.Format("-----BEGIN {0}-----\\n", type);
  382. var footer = string.Format("-----END {0}-----", type);
  383. var start = pem.IndexOf(header) + header.Length;
  384. var end = pem.IndexOf(footer, start);
  385. var base64 = pem.Substring(start, end - start);
  386. return Convert.FromBase64String(base64);
  387. }
  388. #endregion
  389. #region SHA256加密
  390. /// <summary>
  391. /// SHA256加密
  392. /// </summary>
  393. /// <param name="data">数据</param>
  394. /// <returns></returns>
  395. public static string SHA256(string data)
  396. {
  397. var byteData = Encoding.UTF8.GetBytes(data);
  398. var sha256 = new SHA256Managed();
  399. var result = sha256.ComputeHash(byteData);
  400. return BitConverter.ToString(result).Replace("-", "").ToLower();
  401. }
  402. #endregion
  403. #region HMACSHA1加密
  404. /// <summary>
  405. /// HMACSHA1加密
  406. /// </summary>
  407. /// <param name="data">数据</param>
  408. /// <param name="key">密钥</param>
  409. /// <returns></returns>
  410. public static string HMACSHA1(string data, string key)
  411. {
  412. var byteData = Encoding.UTF8.GetBytes(data);
  413. var byteKey = Encoding.UTF8.GetBytes(key);
  414. var hmacsha1 = new HMACSHA1(byteKey);
  415. var result = hmacsha1.ComputeHash(byteData);
  416. return Convert.ToBase64String(result);
  417. }
  418. #endregion
  419. #region HMACSHA256加密
  420. /// <summary>
  421. /// HMACSHA256加密
  422. /// </summary>
  423. /// <param name="data">数据</param>
  424. /// <param name="key">密钥</param>
  425. /// <returns></returns>
  426. public static string HMACSHA256(string data, string key)
  427. {
  428. var byteData = Encoding.UTF8.GetBytes(data);
  429. var byteKey = Encoding.UTF8.GetBytes(key);
  430. var hmacsha256 = new HMACSHA256(byteKey);
  431. var result = hmacsha256.ComputeHash(byteData);
  432. return BitConverter.ToString(result).Replace("-", "").ToLower();
  433. }
  434. #endregion
  435. #region AES解密
  436. /// <summary>
  437. /// AES解密
  438. /// </summary>
  439. /// <param name="data">待解密数据</param>
  440. /// <param name="key">密钥</param>
  441. /// <returns></returns>
  442. public static string AESDecrypt(string data, string key)
  443. {
  444. var keyArray = Encoding.UTF8.GetBytes(key);
  445. var toEncryptArray = Convert.FromBase64String(data);
  446. var rDel = new RijndaelManaged
  447. {
  448. Key = keyArray,
  449. Mode = CipherMode.ECB,
  450. Padding = PaddingMode.PKCS7
  451. };
  452. var cTransform = rDel.CreateDecryptor();
  453. var resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
  454. return Encoding.UTF8.GetString(resultArray);
  455. }
  456. #endregion
  457. #region from alipay signer
  458. /// <summary>
  459. /// 验证签名
  460. /// </summary>
  461. /// <param name="content">待验签的内容</param>
  462. /// <param name="sign">签名值的Base64串</param>
  463. /// <param name="publicKeyPem">支付宝公钥</param>
  464. /// <returns>true:验证成功;false:验证失败</returns>
  465. public static bool Verify(string content, string sign, string publicKeyPem)
  466. {
  467. try
  468. {
  469. using (RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider())
  470. {
  471. rsaService.PersistKeyInCsp = false;
  472. rsaService.ImportParameters(ConvertFromPemPublicKey(publicKeyPem));
  473. return rsaService.VerifyData(Encoding.UTF8.GetBytes(content),
  474. "SHA256", Convert.FromBase64String(sign));
  475. }
  476. }
  477. catch (Exception e)
  478. {
  479. string errorMessage = "验签遭遇异常,content=" + content + " sign=" + sign +
  480. " publicKey=" + publicKeyPem + " reason=" + e.Message;
  481. throw new Exception(errorMessage, e);
  482. }
  483. }
  484. /// <summary>
  485. /// SHA256WithRSA 计算签名
  486. /// </summary>
  487. /// <param name="content">数据</param>
  488. /// <param name="privateKeyPem">私钥</param>
  489. /// <returns></returns>
  490. public static string Sign(string content, string privateKeyPem)
  491. {
  492. try
  493. {
  494. using (RSACryptoServiceProvider rsaService = BuildRSAServiceProvider(Convert.FromBase64String(privateKeyPem)))
  495. {
  496. byte[] data = Encoding.UTF8.GetBytes(content);
  497. byte[] sign = rsaService.SignData(data, "SHA256");
  498. return Convert.ToBase64String(sign);
  499. }
  500. }
  501. catch (Exception e)
  502. {
  503. string errorMessage = "签名遭遇异常,content=" + content + " privateKeySize=" + privateKeyPem.Length + " reason=" + e.Message;
  504. throw new Exception(errorMessage, e);
  505. }
  506. }
  507. private static RSAParameters ConvertFromPemPublicKey(string pemPublickKey)
  508. {
  509. if (string.IsNullOrEmpty(pemPublickKey))
  510. {
  511. throw new Exception("PEM格式公钥不可为空。");
  512. }
  513. //移除干扰文本
  514. pemPublickKey = pemPublickKey.Replace("-----BEGIN PUBLIC KEY-----", "")
  515. .Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", "");
  516. byte[] keyData = Convert.FromBase64String(pemPublickKey);
  517. bool keySize1024 = (keyData.Length == 162);
  518. bool keySize2048 = (keyData.Length == 294);
  519. if (!(keySize1024 || keySize2048))
  520. {
  521. throw new Exception("公钥长度只支持1024和2048。");
  522. }
  523. byte[] pemModulus = (keySize1024 ? new byte[128] : new byte[256]);
  524. byte[] pemPublicExponent = new byte[3];
  525. Array.Copy(keyData, (keySize1024 ? 29 : 33), pemModulus, 0, (keySize1024 ? 128 : 256));
  526. Array.Copy(keyData, (keySize1024 ? 159 : 291), pemPublicExponent, 0, 3);
  527. RSAParameters para = new RSAParameters
  528. {
  529. Modulus = pemModulus,
  530. Exponent = pemPublicExponent
  531. };
  532. return para;
  533. }
  534. private static RSACryptoServiceProvider BuildRSAServiceProvider(byte[] privateKey)
  535. {
  536. byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
  537. byte bt = 0;
  538. ushort twobytes = 0;
  539. int elems = 0;
  540. //set up stream to decode the asn.1 encoded RSA private key
  541. //wrap Memory Stream with BinaryReader for easy reading
  542. using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(privateKey)))
  543. {
  544. twobytes = binaryReader.ReadUInt16();
  545. //data read as little endian order (actual data order for Sequence is 30 81)
  546. if (twobytes == 0x8130)
  547. {
  548. //advance 1 byte
  549. binaryReader.ReadByte();
  550. }
  551. else if (twobytes == 0x8230)
  552. {
  553. //advance 2 bytes
  554. binaryReader.ReadInt16();
  555. }
  556. else
  557. {
  558. return null;
  559. }
  560. twobytes = binaryReader.ReadUInt16();
  561. //version number
  562. if (twobytes != 0x0102)
  563. {
  564. return null;
  565. }
  566. bt = binaryReader.ReadByte();
  567. if (bt != 0x00)
  568. {
  569. return null;
  570. }
  571. //all private key components are Integer sequences
  572. elems = GetIntegerSize(binaryReader);
  573. MODULUS = binaryReader.ReadBytes(elems);
  574. elems = GetIntegerSize(binaryReader);
  575. E = binaryReader.ReadBytes(elems);
  576. elems = GetIntegerSize(binaryReader);
  577. D = binaryReader.ReadBytes(elems);
  578. elems = GetIntegerSize(binaryReader);
  579. P = binaryReader.ReadBytes(elems);
  580. elems = GetIntegerSize(binaryReader);
  581. Q = binaryReader.ReadBytes(elems);
  582. elems = GetIntegerSize(binaryReader);
  583. DP = binaryReader.ReadBytes(elems);
  584. elems = GetIntegerSize(binaryReader);
  585. DQ = binaryReader.ReadBytes(elems);
  586. elems = GetIntegerSize(binaryReader);
  587. IQ = binaryReader.ReadBytes(elems);
  588. //create RSACryptoServiceProvider instance and initialize with public key
  589. RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider();
  590. RSAParameters rsaParams = new RSAParameters
  591. {
  592. Modulus = MODULUS,
  593. Exponent = E,
  594. D = D,
  595. P = P,
  596. Q = Q,
  597. DP = DP,
  598. DQ = DQ,
  599. InverseQ = IQ
  600. };
  601. rsaService.ImportParameters(rsaParams);
  602. return rsaService;
  603. }
  604. }
  605. private static int GetIntegerSize(BinaryReader binaryReader)
  606. {
  607. byte bt = 0;
  608. byte lowbyte = 0x00;
  609. byte highbyte = 0x00;
  610. int count = 0;
  611. bt = binaryReader.ReadByte();
  612. //expect integer
  613. if (bt != 0x02)
  614. {
  615. return 0;
  616. }
  617. bt = binaryReader.ReadByte();
  618. if (bt == 0x81)
  619. {
  620. //data size in next byte
  621. count = binaryReader.ReadByte();
  622. }
  623. else if (bt == 0x82)
  624. {
  625. //data size in next 2 bytes
  626. highbyte = binaryReader.ReadByte();
  627. lowbyte = binaryReader.ReadByte();
  628. byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
  629. count = BitConverter.ToInt32(modint, 0);
  630. }
  631. else
  632. {
  633. //we already have the data size
  634. count = bt;
  635. }
  636. while (binaryReader.ReadByte() == 0x00)
  637. { //remove high order zeros in data
  638. count -= 1;
  639. }
  640. //last ReadByte wasn't a removed zero, so back up a byte
  641. binaryReader.BaseStream.Seek(-1, SeekOrigin.Current);
  642. return count;
  643. }
  644. #endregion
  645. }
  646. }