.net连接java web service 公钥私钥证书验签
时间:2010-09-09 来源:交友乐
最近和银行做接口,前前后后断断续续做了3个月,终于大功告成。
在此期间,查了不少资料,发现网上关于.net如何验签的文章不多,现在把我的经验贡献给大家,希望有点用处。其中一些很容易在网上查到的内容我就不一一说明了,不懂得朋友可以自行学习。本文写的比较简单,请高手指点。
项目说明:
银行方:java的web service接口
本方:.net平台
开发工具:vs2008
一、证书
首先我们手里有两个文件,私钥和公钥。私钥一般是xx.pfx,公钥一般是xx.cer。公钥由银行提供,私钥由本方按照文档在银行网站生成。在本机导入证书。
二、连通过程
因为银行没有.net的说明文档,所以一切都靠自己摸索。
首先在vs的工程中添加web reference,输入银行提供的wsdl路径,vs自动生成接口框架类(Payment)。看了一下自动生成的类,里面是银行web service的接口。
第二步建立调用接口的代码
private CookieContainer cookies;
private static Payment pss = new Payment();
public Service()
{
//加入密钥
//pss.ClientCertificates.Add(X509Certificate.CreateFromCertFile(System.AppDomain.CurrentDomain.BaseDirectory + "App_Data\\certificate\\new.cer"));
pss.ClientCertificates.Add(new X509Certificate2(System.AppDomain.CurrentDomain.BaseDirectory + "App_Data\\certificate\\private.pfx", ""));
pss.Url = "https://pay.bank.com/Payment/services/PaymentServices";
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
//局域网内调试
if (Environment.UserDomainName.Equals("x"))
{
WebProxy myProxy = new WebProxy("129.1.0.0:8080", false);
myProxy.Credentials = new NetworkCredential("xxx", "xxx", "xxx");
pss.Proxy = myProxy;
}
cookies = new CookieContainer();
pss.CookieContainer = cookies;
pss.AllowAutoRedirect = true;
}
public static string Login()
{
try
{
return pss.login(getLogin());
}
catch (Exception e)
{
Log(e.StackTrace);
Log(e.Message);
return "";
}
}
private static String getLogin()
{
string now = DateTime.Now.ToString("yyyyMMddhhmmss");
StringBuilder sb = new StringBuilder();
sb.Append("<?xml version=\"1.0\" encoding=\"GBK\"?>");
sb.Append("<message method=\"login\" type=\"request\">");
sb.Append("<infoType>0800</infoType>");
sb.Append("<posTime>").Append(now).Append("</posTime>");
sb.Append("<posID>000001</posID>");
sb.Append("<transTime>").Append(now.Substring(8)).Append("</transTime>");
sb.Append("<transDate>").Append(now.Substring(0, 8)).Append("</transDate>");
sb.Append("<retCode></retCode>");
sb.Append("<terminalID></terminalID>");
sb.Append("<merchantID>").Append(merId).Append("</merchantID>");
sb.Append("<merchantName>xxx</merchantName>");
sb.Append("<password>xxx</password>");
sb.Append("<commentRes></commentRes>");
sb.Append("<resParam></resParam>");
sb.Append("<reserved></reserved>");
sb.Append("</message>");
Log(sb.ToString());
return sb.ToString();
}
这个时候发生了一个问题,不论如何修改都无法连接到对方的web service上,IE是可以连接上对方的web service网页的。查了很多网站,也没有得到结果,后来偶尔加入了pss.Url="https://pay.bank.com/Payment/services/PaymentServices"; ,居然连接上了。查看了一下框架类,里面明明有Url的值。这个问题一直没找到原因。
注意如果是局域网内调试,需要加入proxy。
另外根据银行的需要,你可以选择是使用公钥X509Certificate来登录,还是试用私钥X509Certificate2来登录。这里使用了私钥。
三、验签
验签的代码是网上找来的,需要注意的是对方可能是公钥加密,我们需要用私钥解密,也可能对方是私钥加密,我们需要公钥解密。我就碰到对方测试环境和生产环境做法不一样,导致花了好几天才找到问题。
/// <summary>
/// 引用证书非对称加/解密RSA-私钥验签【OriginalString:原文(有中文用utf-8编码的字节);SignatureString:签名字符;prikey_path:证书路径;CertificatePW:证书密码;SignType:签名摘要类型(1:MD5,2:SHA1)】
/// </summary>
public static bool CerRSAVerifySignatureByPrivate(byte[] OriginalString, byte[] SignatureString, string prikey_path, string CertificatePW, int SignType)
{
X509Certificate2 x509_Cer1 = new X509Certificate2(prikey_path, CertificatePW);
RSACryptoServiceProvider rsapub = (RSACryptoServiceProvider)x509_Cer1.PrivateKey;
rsapub.ImportCspBlob(rsapub.ExportCspBlob(false));
RSAPKCS1SignatureDeformatter f = new RSAPKCS1SignatureDeformatter(rsapub);
byte[] HashData;
switch (SignType)
{
case 1:
f.SetHashAlgorithm("MD5");//摘要算法MD5
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
HashData = md5.ComputeHash(OriginalString);
break;
default:
f.SetHashAlgorithm("SHA1");//摘要算法SHA1
SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
HashData = sha.ComputeHash(OriginalString);
break;
}
if (f.VerifySignature(HashData, SignatureString))
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 引用证书非对称加/解密RSA-公钥验签【OriginalString:原文(有中文用utf-8编码的字节);SignatureString:签名字符;pubkey_path:证书路径;CertificatePW:证书密码;SignType:签名摘要类型(1:MD5,2:SHA1)】
/// </summary>
public static bool CerRSAVerifySignature(byte[] OriginalString, byte[] SignatureString, string pubkey_path, string CertificatePW, int SignType)
{
X509Certificate2 x509_Cer1 = new X509Certificate2(pubkey_path, CertificatePW);
RSACryptoServiceProvider rsapub = (RSACryptoServiceProvider)x509_Cer1.PublicKey.Key;
rsapub.ImportCspBlob(rsapub.ExportCspBlob(false));
RSAPKCS1SignatureDeformatter f = new RSAPKCS1SignatureDeformatter(rsapub);
byte[] HashData;
switch (SignType)
{
case 1:
f.SetHashAlgorithm("MD5");//摘要算法MD5
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
HashData = md5.ComputeHash(OriginalString);
break;
default:
f.SetHashAlgorithm("SHA1");//摘要算法SHA1
SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
HashData = sha.ComputeHash(OriginalString);
break;
}
if (f.VerifySignature(HashData, SignatureString))
{
return true;
}
else
{
return false;
}
我是用SHA1算法,注意byte的转换
CerRsa.CerRSAVerifySignature(Encoding.UTF8.GetBytes(orgData.ToString()), Convert.FromBase64String(payment.Signature), pubkey_path, "", 2)