Signer.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. using System;
  2. using System.Text;
  3. using System.Security.Cryptography;
  4. using System.IO;
  5. using System.Collections.Generic;
  6. namespace Alipay.EasySDK.Kernel.Util
  7. {
  8. /// <summary>
  9. /// SHA256WithRSA签名器
  10. /// </summary>
  11. public class Signer
  12. {
  13. /// <summary>
  14. /// 计算签名
  15. /// </summary>
  16. /// <param name="content">待签名的内容</param>
  17. /// <param name="privateKeyPem">私钥</param>
  18. /// <returns>签名值的Base64串</returns>
  19. public static string Sign(string content, string privateKeyPem)
  20. {
  21. try
  22. {
  23. using (RSACryptoServiceProvider rsaService = BuildRSAServiceProvider(Convert.FromBase64String(privateKeyPem)))
  24. {
  25. byte[] data = AlipayConstants.DEFAULT_CHARSET.GetBytes(content);
  26. byte[] sign = rsaService.SignData(data, "SHA256");
  27. return Convert.ToBase64String(sign);
  28. }
  29. }
  30. catch (Exception e)
  31. {
  32. string errorMessage = "签名遭遇异常,content=" + content + " privateKeySize=" + privateKeyPem.Length + " reason=" + e.Message;
  33. Console.WriteLine(errorMessage);
  34. throw new Exception(errorMessage, e);
  35. }
  36. }
  37. /// <summary>
  38. /// 验证签名
  39. /// </summary>
  40. /// <param name="content">待验签的内容</param>
  41. /// <param name="sign">签名值的Base64串</param>
  42. /// <param name="publicKeyPem">支付宝公钥</param>
  43. /// <returns>true:验证成功;false:验证失败</returns>
  44. public static bool Verify(string content, string sign, string publicKeyPem)
  45. {
  46. try
  47. {
  48. using (RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider())
  49. {
  50. rsaService.PersistKeyInCsp = false;
  51. rsaService.ImportParameters(ConvertFromPemPublicKey(publicKeyPem));
  52. return rsaService.VerifyData(AlipayConstants.DEFAULT_CHARSET.GetBytes(content),
  53. "SHA256", Convert.FromBase64String(sign));
  54. }
  55. }
  56. catch (Exception e)
  57. {
  58. string errorMessage = "验签遭遇异常,content=" + content + " sign=" + sign +
  59. " publicKey=" + publicKeyPem + " reason=" + e.Message;
  60. Console.WriteLine(errorMessage);
  61. throw new Exception(errorMessage, e);
  62. }
  63. }
  64. /// <summary>
  65. /// 对参数集合进行验签
  66. /// </summary>
  67. /// <param name="parameters">参数集合</param>
  68. /// <param name="publicKeyPem">支付宝公钥</param>
  69. /// <returns>true:验证成功;false:验证失败</returns>
  70. public static bool VerifyParams(Dictionary<string, string> parameters, string publicKeyPem)
  71. {
  72. string sign = parameters[AlipayConstants.SIGN_FIELD];
  73. parameters.Remove(AlipayConstants.SIGN_FIELD);
  74. parameters.Remove(AlipayConstants.SIGN_TYPE_FIELD);
  75. string content = GetSignContent(parameters);
  76. return Verify(content, sign, publicKeyPem);
  77. }
  78. private static string GetSignContent(IDictionary<string, string> parameters)
  79. {
  80. // 把字典按Key的字母顺序排序
  81. IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters, StringComparer.Ordinal);
  82. IEnumerator<KeyValuePair<string, string>> iterator = sortedParams.GetEnumerator();
  83. // 把所有参数名和参数值串在一起
  84. StringBuilder query = new StringBuilder("");
  85. while (iterator.MoveNext())
  86. {
  87. string key = iterator.Current.Key;
  88. string value = iterator.Current.Value;
  89. query.Append(key).Append("=").Append(value).Append("&");
  90. }
  91. string content = query.ToString().Substring(0, query.Length - 1);
  92. return content;
  93. }
  94. private static RSAParameters ConvertFromPemPublicKey(string pemPublickKey)
  95. {
  96. if (string.IsNullOrEmpty(pemPublickKey))
  97. {
  98. throw new Exception("PEM格式公钥不可为空。");
  99. }
  100. //移除干扰文本
  101. pemPublickKey = pemPublickKey.Replace("-----BEGIN PUBLIC KEY-----", "")
  102. .Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", "");
  103. byte[] keyData = Convert.FromBase64String(pemPublickKey);
  104. bool keySize1024 = (keyData.Length == 162);
  105. bool keySize2048 = (keyData.Length == 294);
  106. if (!(keySize1024 || keySize2048))
  107. {
  108. throw new Exception("公钥长度只支持1024和2048。");
  109. }
  110. byte[] pemModulus = (keySize1024 ? new byte[128] : new byte[256]);
  111. byte[] pemPublicExponent = new byte[3];
  112. Array.Copy(keyData, (keySize1024 ? 29 : 33), pemModulus, 0, (keySize1024 ? 128 : 256));
  113. Array.Copy(keyData, (keySize1024 ? 159 : 291), pemPublicExponent, 0, 3);
  114. RSAParameters para = new RSAParameters
  115. {
  116. Modulus = pemModulus,
  117. Exponent = pemPublicExponent
  118. };
  119. return para;
  120. }
  121. private static RSACryptoServiceProvider BuildRSAServiceProvider(byte[] privateKey)
  122. {
  123. byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
  124. byte bt = 0;
  125. ushort twobytes = 0;
  126. int elems = 0;
  127. //set up stream to decode the asn.1 encoded RSA private key
  128. //wrap Memory Stream with BinaryReader for easy reading
  129. using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(privateKey)))
  130. {
  131. twobytes = binaryReader.ReadUInt16();
  132. //data read as little endian order (actual data order for Sequence is 30 81)
  133. if (twobytes == 0x8130)
  134. {
  135. //advance 1 byte
  136. binaryReader.ReadByte();
  137. }
  138. else if (twobytes == 0x8230)
  139. {
  140. //advance 2 bytes
  141. binaryReader.ReadInt16();
  142. }
  143. else
  144. {
  145. return null;
  146. }
  147. twobytes = binaryReader.ReadUInt16();
  148. //version number
  149. if (twobytes != 0x0102)
  150. {
  151. return null;
  152. }
  153. bt = binaryReader.ReadByte();
  154. if (bt != 0x00)
  155. {
  156. return null;
  157. }
  158. //all private key components are Integer sequences
  159. elems = GetIntegerSize(binaryReader);
  160. MODULUS = binaryReader.ReadBytes(elems);
  161. elems = GetIntegerSize(binaryReader);
  162. E = binaryReader.ReadBytes(elems);
  163. elems = GetIntegerSize(binaryReader);
  164. D = binaryReader.ReadBytes(elems);
  165. elems = GetIntegerSize(binaryReader);
  166. P = binaryReader.ReadBytes(elems);
  167. elems = GetIntegerSize(binaryReader);
  168. Q = binaryReader.ReadBytes(elems);
  169. elems = GetIntegerSize(binaryReader);
  170. DP = binaryReader.ReadBytes(elems);
  171. elems = GetIntegerSize(binaryReader);
  172. DQ = binaryReader.ReadBytes(elems);
  173. elems = GetIntegerSize(binaryReader);
  174. IQ = binaryReader.ReadBytes(elems);
  175. //create RSACryptoServiceProvider instance and initialize with public key
  176. RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider();
  177. RSAParameters rsaParams = new RSAParameters
  178. {
  179. Modulus = MODULUS,
  180. Exponent = E,
  181. D = D,
  182. P = P,
  183. Q = Q,
  184. DP = DP,
  185. DQ = DQ,
  186. InverseQ = IQ
  187. };
  188. rsaService.ImportParameters(rsaParams);
  189. return rsaService;
  190. }
  191. }
  192. private static int GetIntegerSize(BinaryReader binaryReader)
  193. {
  194. byte bt = 0;
  195. byte lowbyte = 0x00;
  196. byte highbyte = 0x00;
  197. int count = 0;
  198. bt = binaryReader.ReadByte();
  199. //expect integer
  200. if (bt != 0x02)
  201. {
  202. return 0;
  203. }
  204. bt = binaryReader.ReadByte();
  205. if (bt == 0x81)
  206. {
  207. //data size in next byte
  208. count = binaryReader.ReadByte();
  209. }
  210. else if (bt == 0x82)
  211. {
  212. //data size in next 2 bytes
  213. highbyte = binaryReader.ReadByte();
  214. lowbyte = binaryReader.ReadByte();
  215. byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
  216. count = BitConverter.ToInt32(modint, 0);
  217. }
  218. else
  219. {
  220. //we already have the data size
  221. count = bt;
  222. }
  223. while (binaryReader.ReadByte() == 0x00)
  224. { //remove high order zeros in data
  225. count -= 1;
  226. }
  227. //last ReadByte wasn't a removed zero, so back up a byte
  228. binaryReader.BaseStream.Seek(-1, SeekOrigin.Current);
  229. return count;
  230. }
  231. }
  232. }