与平安对接保险随笔
本文出自Crayfish博主,转载请注明:
最近公司项目在跟平安进行“投保”、“支付”、“承保”等事项的对接,投保使用C#进行了报文读取,很快就解决了“投保”问题。进行到“支付”环节的时候处理“证书验签失败”问题,整整处理了三天。我们使用的是平安自己的支付,使用POST请求,返回支付页面,我看了平安支付文档后,就觉得文档很简陋,既然要让用户使用你们的支付,那请把文档写写好一点吧。
支付中的问题
接着,就开始了支付接口对接之旅,第一天将平安java版本的签名算法改进成Android版本的,在这之间由于Android与java读取文件流存在一定的出入,我使用了context.getAssets().open(keyStoreFileName);;来获得一个InputStream对象,来进行加载证书,接下来奇怪的是私钥获取不到,在java版本中“别名”传“1”就可以获取到,但是Android中却不行,几经周折百度,查阅到了
Enumeration enume = keyStore.aliases();
if (enume.hasMoreElements()) {keyStoreAlias = (String) enume.nextElement();
}
已这种方式进行读取“别名”,最终取到了私钥进行加密。
最后,Base64编码问题出现了,大家都知道java会使用sun.misc.BASE64Encoder,但是Android使用不了,Android有自己的android.util.Base64进行Base64编码;与java加密相同的是Android中Base64.CRLF,剩下还有DEFAULT默认、NO_PADDING去除最后的“=”、NO_WRAP去除换行符、URL_SAFE以-和_取代+和/。
获取电子保单的问题
支付在明确参数后,也顺利完成了,最后获取电子保单,我使用的是C#开发的服务,request.GetRequestStream()此流无法操作的问题,最后以巧妙的方式进行了PDF流的读取:
public static byte[] StreamToBytes(Stream stream)
{List<byte> bytes = new List<byte>();int temp = stream.ReadByte();while (temp != -1){bytes.Add((byte)temp);temp = stream.ReadByte();}return bytes.ToArray();
}
SHA1WithRSA签名算法
C#请求添加证书(以及内容签名)代码:
X509Certificate2 objx5092 = new X509Certificate2(KEYSTOREPATH, KEYSTOREPASSWORD, X509KeyStorageFlags.MachineKeySet);
//RSACryptoServiceProvider rsa = objx5092.PrivateKey as RSACryptoServiceProvider;
//byte[] bb = rsa.SignData(dataByte, new SHA1CryptoServiceProvider());
request.ClientCertificates.Add(objx5092);
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
//回调方法public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors){ // 总是接受 return true;}
java签名代码:
if(keyStoreFileName.toUpperCase().indexOf("PFX")>=0)//判断证书文件的格式
{keystoreType="PKCS12";
}
else
{keystoreType="JKS";
}
keyStore = KeyStore.getInstance(keystoreType);//获取JKS证书实例
InputStream in = context.getAssets().open(keyStoreFileName);
char[]pwdChar=keyStorePassword.toCharArray();//证书密码
keyStore.load(in, pwdChar);//加载证书到keystore中
Enumeration enume = keyStore.aliases();
if (enume.hasMoreElements()) {keyStoreAlias = (String) enume.nextElement();
}
PrivateKey privateKey=(PrivateKey)keyStore.getKey(keyStoreAlias, pwdChar);//从证书中获取私钥
Signature sign=Signature.getInstance("SHA1WithRSA");//SHA1WithRSA签名算法
sign.initSign(privateKey);//设置私钥
sign.update(data.getBytes());//设置明文
signRstByte=sign.sign();//加密
signValue=new String(Base64.encode(signRstByte,Base64.CRLF));