内容:Pfx证书,同时包含了公钥信息和私钥信息。
作用:保证了数据在传输过程中的安全性。
用法:私钥请求的数据进行签名,公钥对响应的数据进行验证签名。
代码:
第一步:将请求的数据进行ascii字典序,并添加Dictionary字典集合中。注意了(SortedDictionary<(Of <(TKey, TValue>)>) 和 SortedList<(Of <(TKey, TValue>)>) 都不是按照ascii排序的)正真的ascii字典序在下面:
string[] keys = { "requestNo", "version", "transId", "agentId","cityId", "registerAddress", "regNo", "regMoney", "regAddress", "spIcp", "remarks", "cardNoCipher", "cardName", "cardBankNo"};//要请求数据变量名 Array.Sort(keys, string.CompareOrdinal); //对请求数据变量名ascii排序 Dictionary<string, string> dictReq = new Dictionary<string, string>();//实例化字典集合对象 for (int i = 0; i <14; i++) //遍历keys数组 { string formData = Request.Form[keys[i]];//获取请求数据变量名获取对应的表单内的值。 if (!String.IsNullOrEmpty(formData)) //判断取出的值是否为空 { dictReq.Add(keys[i], formData); //如果不为空,将变量名和值添加到dictReq字典集合中 } }
第二步:将请求的数据进行签名。(证书存放路径:F:/API/cer/test.pdf 私钥密码 123456 接口请求路径:
http://192.168.1.104:8010/interface) string privateKeyUrl = "F:/API/cer/test.pdf";//私钥证书路径 string privateKeyPwd = "123456"//私钥证书密码 string signData = signature(dictReq, privateKeyUrl, privateKeyPwd);//请求数据签名 /// <summary> /// 签名 /// </summary> /// <param name="dictReq">签名数据</param> /// <param name="privateKey">私钥</param> /// <param name="privateKeyPwd">私钥密码</param> /// <returns>返回post请求数据</returns> public string signature(Dictionary<string, string> dictReq, string privateKey, string privateKeyPwd) { string postData = ""; //url编码的post请求数据 string signStr = ""; //待签名数据 foreach (KeyValuePair<string, string> kvp in dictReq) //遍历键值对 { if (kvp.Value == "") continue;//如果值为空,不参与签名 if (kvp.Key != "signature") postData += kvp.Key + "=" + HttpUtility.UrlEncode(kvp.Value) + "&"; //拼接url编码的 post请求数据 if (kvp.Value != "") signStr += kvp.Key + "=" + kvp.Value + "&"; //拼接待签名数据 } string signatureData = SignData(signStr.TrimEnd('&'),privateKey,privateKeyPwd);//签名 return postData.TrimEnd('&') + "&signature=" + HttpUtility.UrlEncode(signatureData);返回post请求数据 } /// <summary> /// 将数据SHA1签名 /// </summary> /// <param name="content">待签名字符串</param> /// <param name="privateKey">私钥证书</param> /// <param name="privateKeyPwd">私钥密码</param> /// <returns>已签名base64编码数据</returns> public string SignData(string content,string privateKey,string privateKeyPwd) { X509Certificate2 cert = new X509Certificate2(privateKey,privateKeyPwd, X509KeyStorageFlags.MachineKeySet);//加载证 书实体 RSACryptoServiceProvider rsapri = (RSACryptoServiceProvider)cert.PrivateKey; //获取私钥证书 RSAPKCS1SignatureFormatter f = new RSAPKCS1SignatureFormatter(rsapri); byte[] result; f.SetHashAlgorithm("SHA1"); SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider(); result = sha.ComputeHash(System.Text.Encoding.UTF8.GetBytes(content)); return System.Convert.ToBase64String(f.CreateSignature(result)).ToString(); }
第三步:发送POST请求,获取返回结果(Post,Form)
string postUrl = "http://192.168.1.104:8010/interface";//post请求地址 string resultData = TransSubmit(signData, postUrl);//发送POST请求,获取返回结果(Post,Form) /// <summary> /// 发送POST请求,获取返回结果(Post,Form) /// </summary> /// <param name="postData">请求数据</param> /// <param name="postUrl">请求地址</param> /// <returns>响应结果</returns> public string TransSubmit(string postData,string postUrl) { Encoding code = Encoding.GetEncoding("utf-8"); byte[] bytesRequestData = code.GetBytes(postData); string str = ""; WebRequest webRequest = WebRequest.Create(postUrl); HttpWebRequest myReq = webRequest as HttpWebRequest; myReq.Method = "post"; myReq.ContentType = "application/x-www-form-urlencoded"; myReq.ContentLength = bytesRequestData.Length; Stream requestStream = myReq.GetRequestStream(); requestStream.Write(bytesRequestData, 0, bytesRequestData.Length); requestStream.Close(); HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse(); Stream myStream = HttpWResp.GetResponseStream(); StreamReader Reader = new StreamReader(myStream); str = Reader.ReadToEnd(); return str; }
第四步:对响应的数据验证签名。
string sign = GetUrlStrValue(resultData, "signature"); //截取响应结果的签名字符串 string sourceData = resultData.Substring(0, resultData.IndexOf("signature")-1); //响应的数据字符 string PublicKey = MyRsaUtil.GetPublicKey(privateKeyUrl,privateKeyPwd );//获取公钥证书 bool verifySign = MyRsaUtil.SignatureDeformatter(sourceData, sign, PublicKey);//公钥证书验证签名(为true,则验证签名成功 。为false ,则验证签名失败) if (verifySign) { Response.Write("请求内容:" + signData); Response.Write("响应内容:"+resultData); } else { Response.Write("验证签名失败"); } /// <summary> /// 截取路径字符串变量值 /// </summary> /// <param name="sourceStr">路径字符串</param> /// <param name="strof">变量名</param> /// <returns>变量值</returns> public string GetUrlStrValue(string sourceStr,string strof) { sourceStr=sourceStr.Substring(sourceStr.IndexOf(strof+"="),sourceStr.Length-sourceStr.IndexOf(strof+"=")); sourceStr = sourceStr + "&"; sourceStr = sourceStr.Substring(sourceStr.IndexOf("=") + 1, sourceStr.IndexOf("&") - sourceStr.IndexOf("=") - 1); return sourceStr; } /// <summary> /// 获取证书公钥 /// </summary> /// <param name="pfxFileName">证书路径</param> /// <param name="password">证书密码</param> /// <returns>证书公钥</returns> public string GetPublicKey(string pfxFileUrl, string password) { X509Certificate2 _certificate = GetCertificateFromPfxFile(pfxFileName, password); return _certificate.PublicKey.Key.ToXmlString(false); } /// <summary> /// 验证签名 /// </summary> /// <param name="sourceData">响应的数据</param> /// <param name="strEncryptString">签名</param> /// <param name="publicKey">公钥</param> /// <returns>true or false</returns> public bool SignatureDeformatter(string sourceData, string sign,string publicKey) { try { byte[] rgbHash = Encoding.UTF8.GetBytes(sourceData); RSACryptoServiceProvider key = new RSACryptoServiceProvider(); key.FromXmlString(publicKey); bool result = key.VerifyData(rgbHash, "SHA1", Convert.FromBase64String(strEncryptString)); return result; } catch { return false; } }