RSAEncryptor.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. using System;
  2. using System.Text;
  3. using System.Security.Cryptography;
  4. using System.IO;
  5. namespace PaySharp.Alipay.Util.Asymmetric
  6. {
  7. /// <summary>
  8. /// RSA算法加密器
  9. /// 签名部分采用SHA1算法进行摘要计算
  10. /// </summary>
  11. public class RSAEncryptor : BaseAsymmetricEncryptor
  12. {
  13. /// <summary>
  14. /// RSA算法签名采用SHA1摘要算法
  15. /// </summary>
  16. /// <returns>摘要算法名称</returns>
  17. protected virtual string GetShaType()
  18. {
  19. return "SHA1";
  20. }
  21. protected override string GetAsymmetricType()
  22. {
  23. return "RSA";
  24. }
  25. protected override string DoDecrypt(string cipherTextBase64, string charset, string privateKey)
  26. {
  27. using (RSACryptoServiceProvider rsaService = BuildRSAServiceProvider(Convert.FromBase64String(privateKey)))
  28. {
  29. byte[] data = Convert.FromBase64String(cipherTextBase64);
  30. //解密块最大长度
  31. int maxBlockSize = rsaService.KeySize / 8;
  32. //如果密文长度小于等于单个解密块最大长度,直接单次调用解密接口完成解密
  33. if (data.Length <= maxBlockSize)
  34. {
  35. byte[] cipherbytes = rsaService.Decrypt(data, false);
  36. return Encoding.GetEncoding(charset).GetString(cipherbytes);
  37. }
  38. //如果密文长度大于单个解密块最大长度,在内存中循环调用解密接口完成解密
  39. using (MemoryStream plainStream = new MemoryStream())
  40. {
  41. using (MemoryStream cipherStream = new MemoryStream(data))
  42. {
  43. Byte[] buffer = new Byte[maxBlockSize];
  44. int readSize = cipherStream.Read(buffer, 0, maxBlockSize);
  45. while (readSize > 0)
  46. {
  47. Byte[] cipherBlock = new Byte[readSize];
  48. Array.Copy(buffer, 0, cipherBlock, 0, readSize);
  49. Byte[] plainBlock = rsaService.Decrypt(cipherBlock, false);
  50. plainStream.Write(plainBlock, 0, plainBlock.Length);
  51. readSize = cipherStream.Read(buffer, 0, maxBlockSize);
  52. }
  53. }
  54. return Encoding.GetEncoding(charset).GetString(plainStream.ToArray());
  55. }
  56. }
  57. }
  58. protected override string DoEncrypt(string plainText, string charset, string publicKey)
  59. {
  60. using (RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider())
  61. {
  62. rsaService.PersistKeyInCsp = false;
  63. rsaService.ImportParameters(ConvertFromPemPublicKey(publicKey));
  64. byte[] data = Encoding.GetEncoding(charset).GetBytes(plainText);
  65. //加密块最大长度
  66. int maxBlockSize = rsaService.KeySize / 8 - 11;
  67. //如果明文长度小于等于单个加密块最大长度,直接单次调用加密接口完成加密
  68. if (data.Length <= maxBlockSize)
  69. {
  70. byte[] cipherbytes = rsaService.Encrypt(data, false);
  71. return Convert.ToBase64String(cipherbytes);
  72. }
  73. //如果明文长度大于单个加密块最大长度,在内存中循环调用加密接口完成加密
  74. using (MemoryStream cipherStream = new MemoryStream())
  75. {
  76. using (MemoryStream plainStream = new MemoryStream(data))
  77. {
  78. Byte[] buffer = new Byte[maxBlockSize];
  79. int readSize = plainStream.Read(buffer, 0, maxBlockSize);
  80. while (readSize > 0)
  81. {
  82. Byte[] plainBlock = new Byte[readSize];
  83. Array.Copy(buffer, 0, plainBlock, 0, readSize);
  84. Byte[] cipherBlock = rsaService.Encrypt(plainBlock, false);
  85. cipherStream.Write(cipherBlock, 0, cipherBlock.Length);
  86. readSize = plainStream.Read(buffer, 0, maxBlockSize);
  87. }
  88. }
  89. return Convert.ToBase64String(cipherStream.ToArray(), Base64FormattingOptions.None);
  90. }
  91. }
  92. }
  93. protected override string DoSign(string content, string charset, string privateKey)
  94. {
  95. using (RSACryptoServiceProvider rsaService = BuildRSAServiceProvider(Convert.FromBase64String(privateKey)))
  96. {
  97. byte[] data = Encoding.GetEncoding(charset).GetBytes(content);
  98. byte[] sign = rsaService.SignData(data, GetShaType());
  99. return Convert.ToBase64String(sign);
  100. }
  101. }
  102. protected override bool DoVerify(string content, string charset, string publicKey, string sign)
  103. {
  104. using (RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider())
  105. {
  106. rsaService.PersistKeyInCsp = false;
  107. rsaService.ImportParameters(ConvertFromPemPublicKey(publicKey));
  108. return rsaService.VerifyData(Encoding.GetEncoding(charset).GetBytes(content),
  109. GetShaType(), Convert.FromBase64String(sign));
  110. }
  111. }
  112. private RSAParameters ConvertFromPemPublicKey(string pemPublickKey)
  113. {
  114. if (string.IsNullOrEmpty(pemPublickKey))
  115. {
  116. throw new Exception("PEM格式公钥不可为空。");
  117. }
  118. //移除干扰文本
  119. pemPublickKey = pemPublickKey.Replace("-----BEGIN PUBLIC KEY-----", "")
  120. .Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", "");
  121. byte[] keyData = Convert.FromBase64String(pemPublickKey);
  122. bool keySize1024 = (keyData.Length == 162);
  123. bool keySize2048 = (keyData.Length == 294);
  124. if (!(keySize1024 || keySize2048))
  125. {
  126. throw new Exception("公钥长度只支持1024和2048。");
  127. }
  128. byte[] pemModulus = (keySize1024 ? new byte[128] : new byte[256]);
  129. byte[] pemPublicExponent = new byte[3];
  130. Array.Copy(keyData, (keySize1024 ? 29 : 33), pemModulus, 0, (keySize1024 ? 128 : 256));
  131. Array.Copy(keyData, (keySize1024 ? 159 : 291), pemPublicExponent, 0, 3);
  132. RSAParameters para = new RSAParameters();
  133. para.Modulus = pemModulus;
  134. para.Exponent = pemPublicExponent;
  135. return para;
  136. }
  137. private static RSACryptoServiceProvider BuildRSAServiceProvider(byte[] privateKey)
  138. {
  139. byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
  140. byte bt = 0;
  141. ushort twobytes = 0;
  142. int elems = 0;
  143. //set up stream to decode the asn.1 encoded RSA private key
  144. //wrap Memory Stream with BinaryReader for easy reading
  145. using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(privateKey)))
  146. {
  147. twobytes = binaryReader.ReadUInt16();
  148. //data read as little endian order (actual data order for Sequence is 30 81)
  149. if (twobytes == 0x8130)
  150. {
  151. //advance 1 byte
  152. binaryReader.ReadByte();
  153. }
  154. else if (twobytes == 0x8230)
  155. {
  156. //advance 2 bytes
  157. binaryReader.ReadInt16();
  158. }
  159. else
  160. {
  161. return null;
  162. }
  163. twobytes = binaryReader.ReadUInt16();
  164. //version number
  165. if (twobytes != 0x0102)
  166. {
  167. return null;
  168. }
  169. bt = binaryReader.ReadByte();
  170. if (bt != 0x00)
  171. {
  172. return null;
  173. }
  174. //all private key components are Integer sequences
  175. elems = GetIntegerSize(binaryReader);
  176. MODULUS = binaryReader.ReadBytes(elems);
  177. elems = GetIntegerSize(binaryReader);
  178. E = binaryReader.ReadBytes(elems);
  179. elems = GetIntegerSize(binaryReader);
  180. D = binaryReader.ReadBytes(elems);
  181. elems = GetIntegerSize(binaryReader);
  182. P = binaryReader.ReadBytes(elems);
  183. elems = GetIntegerSize(binaryReader);
  184. Q = binaryReader.ReadBytes(elems);
  185. elems = GetIntegerSize(binaryReader);
  186. DP = binaryReader.ReadBytes(elems);
  187. elems = GetIntegerSize(binaryReader);
  188. DQ = binaryReader.ReadBytes(elems);
  189. elems = GetIntegerSize(binaryReader);
  190. IQ = binaryReader.ReadBytes(elems);
  191. //create RSACryptoServiceProvider instance and initialize with public key
  192. RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider();
  193. RSAParameters rsaParams = new RSAParameters
  194. {
  195. Modulus = MODULUS,
  196. Exponent = E,
  197. D = D,
  198. P = P,
  199. Q = Q,
  200. DP = DP,
  201. DQ = DQ,
  202. InverseQ = IQ
  203. };
  204. rsaService.ImportParameters(rsaParams);
  205. return rsaService;
  206. }
  207. }
  208. private static int GetIntegerSize(BinaryReader binaryReader)
  209. {
  210. byte bt = 0;
  211. byte lowbyte = 0x00;
  212. byte highbyte = 0x00;
  213. int count = 0;
  214. bt = binaryReader.ReadByte();
  215. //expect integer
  216. if (bt != 0x02)
  217. {
  218. return 0;
  219. }
  220. bt = binaryReader.ReadByte();
  221. if (bt == 0x81)
  222. {
  223. //data size in next byte
  224. count = binaryReader.ReadByte();
  225. }
  226. else if (bt == 0x82)
  227. {
  228. //data size in next 2 bytes
  229. highbyte = binaryReader.ReadByte();
  230. lowbyte = binaryReader.ReadByte();
  231. byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
  232. count = BitConverter.ToInt32(modint, 0);
  233. }
  234. else
  235. {
  236. //we already have the data size
  237. count = bt;
  238. }
  239. while (binaryReader.ReadByte() == 0x00)
  240. { //remove high order zeros in data
  241. count -= 1;
  242. }
  243. //last ReadByte wasn't a removed zero, so back up a byte
  244. binaryReader.BaseStream.Seek(-1, SeekOrigin.Current);
  245. return count;
  246. }
  247. }
  248. }