开发说明 ===================== APP+ 采用了 HTTP 协议提供各类接口,并且所有接口都是统一请求地址,方便商户简单、快速接入。本 API 包含 2 类接口,页面浏览器类和系统调用类。 - 页面浏览器类:需要从前端页面以 Form 表单的形式发起请求,浏览器会自动跳转至汇付的相关页面(一般是快捷收银台或签约页面),用户在该页面完成相关业务操作后再回跳到商户指定页面,页面方式返回的是标准的表单格式。 - 系统调用类:直接从服务端发起 HTTP 请求,API 会同步返回请求结果,返回的数据格式都是规范 JSON 格式。 参数规范 ----------------- - 参数为可选项时,JSON 格式中可以不包含该参数,或该参数内容为空; - 所有参数值不应该包含与 JSON 格式冲突的特殊字符,如括号,逗号,双引号,冒号等; - 金额单位为元,精确到分,如:1200.00,359.14; - 日期为定长 8 的字符串,格式为 YYYYMMDD,如 20140802; 订单规范 ----------------- - 每个接口通过商户客户号、订单号、订单日期来标识订单的唯一性; - 由于网络的不稳定性等原因,相同订单的交易应答返回给商户订单系统时,有可能会出现以下两种情况: 1.同一订单请求多次,先支付完成的订单返回参数后通知到商户; 2.同一笔订单收到多次支付结果; 处理原则:商户以订单的成功状态为终态,商户收到订单支付成功的应答后,如果再次收到订单支付失败的应答,不做处理即可。 API 调用规范 ----------------- .. image:: _static/images/cfca_eg_request.png 举例说明:假设接口参数为:version=10,cmd_id=101,mer_cust_id=6666000000011499,user_name=张三,bg_ret_url=http://mertest.chinapnr.com/npay 第一步:将接口参数转换成 JSON 格式字符串。 {"version":"10","cmd_id":"101","mer_cust_id":"6666000000011499","user_name":"张三","bg_ret_url":"http://mertest.chinapnr.com/npay"} 第二步:将第一步的 JSON 字符串进行 BASE64 转码后,使用 pfx 证书和密码进行加密,生成 check_value。 java .. code:: java String base64RequestParams = Base64.encodeBase64String(params.getBytes(Charset.forName("utf-8"))); SignResult signResult = CFCASignature.signature(pfxFile, pfxFilePwd,base64RequestParams, "utf-8"); String check_value = signResult.getSign(); .. 第三步:组装请求参数 version、cmd_id、mer_cust_id 和 check_value,以 post 方式请求接口。 java .. code:: java String postStr = "cmd_id=101&version=10&mer_cust_id=6666000000011499&check_value=第二步生成的加签串"; HttpRequest httpRequest = HttpRequest.post("http://mertest.chinapnr.com/npay/merchantRequest").charset("UTF-8"); HttpResponse httpResponse = httpRequest.contentType("application/x-www-form-urlencoded").body(postStr).send(); .. 注意:组装请求参数时 version、cmd_id 和 mer_cust_id 必须和第一步的接口参数中的 version、cmd_id 和 mer_cust_id 值保持一致。 **API 应答接收规范** .. image:: _static/images/cfca_eg_response.png 举例说明(以交易状态查询接口返回的数据为例): 第一步:从应答报文中取得 check_value 假设返回数据如下: .. code:: json {"check_value":"B170E66B00D344F8CEA68C3A84F0ED2207805147793F806CBD3D3E166B57F511ABEB7D5D7A725ECEFDC640FDC2F7102CD8D470CB0BE18A3B4ADE870689D7FCBD4CA55DD5C2E1D6BFC3F30514B0813D8E680708B44A1C1637780CA0D998EF22C10B7E4B8954F304F226BB50F091A60C939F7C4DB513261FC47667757550C7911E"} .. 第二步:解签 check_value,并取得返回参数 将第一步取得的 check_value,使用 cer 证书文件和汇付的商户号(100001)进行解签,得到内容为 BASE64 转码后的内容,例如: VerifyResult{code='000', message='验签成功', content=[101, 121, 74, 106, 97, 71, 86, 106, 97, 49, 90, 104, 98, 72, 86, 108, 73, 106, 111, 57]}。 在对 content 进行 BASE64 解码后,得到返回参数的 JSON 格式字符串,例如: .. code:: json {"extension":"extension","trans_stat":"","cmd_id":"301","div_detail":"","resp_code":"301000","mer_priv":"mer_priv","trans_amt":"","trans_type":"01","order_date":"20160801","order_id":"600001","mer_cust_id":"6666000000024878","resp_desc":"查询成功"} .. **API 特点** - 为保证接口的安全性,每笔交易都通过 CFCA 进行签名,篡改签名将导致验签失败,交易无法正常进行; - 商户可以动态地将每笔交易的返回地址指向不同的交易网站,适合于多网站和多应用的商户; - 商户在接口中可以自定义域,本平台返回时,会将该域原样返回,供商户实现特定的功能; - 本平台通过后台方式向商户发送交易结果,通过分析商户的返回页面,可以准确地知道商户是否收到交易应答结果,从而对发送失败的交易采取自动重发; 加解签简介 ------------------------------------------------------------ 本 API 对商户与汇付之间请求数据采用的是 CFCA 证书加解签方式。测试时开发人员可以在开发者站点申请下发测试用的证书。生产环境的证书是在正式商户开通后,由汇付中台人员下发的。下发证书后,商户联系人邮箱会收到如下图的邮件通知。 .. image:: _static/images/cfca_mail.png 证书下载操作指引 ~~~~~~~~~~~~~~~~~~ **安装证书控件** 非IE浏览器下,点击邮件中的申请链接,登录安全证书下载控台。首次登录需要安装证书控件,系统提示如下图。点击【确定】,下载保存证书控件到本地,并安装。 .. image:: _static/images/cfca_browser_alert.png - 安装过程中如果弹出如下的提示框,一定要选择允许。 .. image:: _static/images/cfca_browser_bottom.png - 安装完成后,重起浏览器。 .. image:: _static/images/cfca_finish.png IE 浏览器下,进入邮件中的申请链接地址,输入联系人手机号,获取验证码(下载测试证书时,验证码随便输入,不做校验)。 .. image:: _static/images/cfca_login.png - 点击【下载证书】,系统会自动下载安装。 .. image:: _static/images/cfca_download1.png - 安装成功后提示。 .. image:: _static/images/cfca_success.png **导出加签证书** - 点击浏览器菜单栏“工具”菜单,单击“Internet选项”。 .. image:: _static/images/cfca_export.png - 在弹出的对话框中点击【内容】选项卡,单击【证书】按钮。 .. image:: _static/images/cfca_export_alert.png - 选中之前安装的证书,点击【导出】。 .. image:: _static/images/cfca_export_select.png - 选择导出私钥,点击【下一步】。 .. image:: _static/images/cfca_export_private_key.png - 选择“个人信息交换”,下属二级选项可根据实际需要勾选,建议全选。点击【下一步】。 .. image:: _static/images/cfca_export_private_key2.png - 输入并确认密码,点击【下一步】。 注意:请记下这里输入的密码,调用加签方法时需要用到这个密码 .. image:: _static/images/cfca_success.png - 指定文件名和存放路径。点击【浏览】可更改存放路径,选择完成后点击【下一步】。 .. image:: _static/images/cfca_export_save.png - 点击【完成】,获得 pfx 文件。 .. image:: _static/images/cfca_export_finish.png **下载解签证书** .. image:: _static/images/cfca_download2.png - 点击【用户指南 cer 文件】,系统会自动下载解签证书。 CFCA_ACS_TEST_OCA31.cer 为测试环境用的解签证书,CFCA_ACS_OCA31.cer 为生产环境用的解签证书。 JAVA 代码示例 ~~~~~~~~~~~~~~~~~~ `相关 jar 包下载 <_static/lib/jar.zip>`_ **加签示例** java .. code:: java private static String sign(String valueObj) { // 加签用 pfx 文件,请换成商户自己导出的证书 String pfxFile = "/app/etc/product/888888-汇付测试商户.pfx"; // 加签用密码,导出 pfx 证书时的密码 String pfxFilePwd = "888888"; // 进行 base64 转换 String base64RequestParams = Base64.encodeBase64String(valueObj.getBytes(Charset.forName("utf-8"))); // 加签 SignResult signResult = CFCASignature.signature(pfxFile, pfxFilePwd,base64RequestParams, "utf-8"); if ("000".equals(signResult.getCode())) { return signResult.getSign(); } else { return "加签失败"; } } .. **验签示例** java .. code:: java public static String parseResult(String responseJson) throws Exception { JSONObject jsonObject = JSON.parseObject(responseJson); String sign = jsonObject.getString("check_value"); // 解签用的证书,请换成商户自己下载的证书 String cerFile = "/app/etc/product/CFCA_ACS_OCA31.cer"; VerifyResult verifyResult = CFCASignature.verifyMerSign("100001", sign, "utf-8", cerFile); if ("000".equals(verifyResult.getCode())) { String content = new String(verifyResult.getContent(), Charset.forName("utf-8")); String decrptyContent = new String(Base64.decodeBase64(content), Charset.forName("utf-8")); return decrptyContent; } else { return "验签失败"; } } .. PHP 代码示例( Linux 版) ~~~~~~~~~~~~~~~~~~~~~~ `相关组件下载 <_static/lib/cfcaphp.zip>`_ 解压后,参考 cfcaphp/v3.4.0.1/文档/PHP版服务器端工具包(Linux版)软件使用手册.pdf **Demo 运行** 1.安装的 PHP 环境(版本 v5.6、版本 v7.0 和 版本 v7.1) 2.安装运行环境(glibc 库需要在 v2.17 以上) 3.修改 PHP 的配置文件 php.ini 修改 php.ini,使 php 允许加载扩展,并将当前扩展添加到其扩展列表中 把 libSADKExtension.so 需要放到对应的 php 环境的扩展文件夹内 例如:/usr/lib/php/20160303/libSADKExtension.so enable_dl = On extension=libSADKExtension.so 重启 php-fpm 服务 /etc/init.d/php-fpm restart 4.通过命令行终端运行 Demo 文件 cfcaphp/v3.4.0.1/ 程序 /Demo/huifuSADKExtension.php 为例子 +------------------------+-------------------------+ |Msg PKCS7-attached Sign | 为使用 pfx 证书加签 | +------------------------+-------------------------+ |PKCS7-attached-Verify | 为验证汇付的签名 | +------------------------+-------------------------+ |cfca_verifyCertificate | 为验证证书链合法性 | +------------------------+-------------------------+ |cfca_getCertificateInfo | 为获取证书信息(非必要)| +------------------------+-------------------------+ php .. code:: php getMessage(); cfca_uninitialize(); } ?> .. PHP 代码示例( Windows 版) ~~~~~~~~~~~~~~~~~~~~~~~~~ `DEMO 下载 <_static/lib/phpwindows.zip>`_ Demo 运行环境要求:WinServer2008 64bit、 WinServer2012 64bit 1、配置 php.ini php -i|findstr ini,找到 php.ini 所在路径 将重命名后的 php.ini 文件内的“; extension_dir = "ext"”行,修改为 “extension_dir = "./ext"”。然后,在 php.ini 文件末尾,添加以下两行内容: [COM_DOT_NET] extension=php_com_dotnet.dll 2、注册 com 组件 64 位下执行 regsvr32 CryptoKit.Standard.x64.dll 32 位下执行 regsvr32 CryptoKit.Standard.x86.dll 3、在 Demo_PHP 目录下执行(TestData 需要与之目录同级) php huifuSADKExtension.php cfca_signData_PKCS7Attached 为使用 pfx 证书加签 cfca_verifyDataSignature_PKCS7Attached 为验证汇付的签名 cfca_verifyCertificate 为验证证书链合法性 cfca_getCertificateInfo 为获取证书信息(非必要) php .. code:: php SignData_PKCS7Attached($strSignAlg, $strSignSourceData, $strPfxFilePath, $strPfxPassword, $strHashAlg); echo "strMsgPKCS7AttachedSignature:".$strMsgPKCS7AttachedSignature."\n\n"; //汇付返回的签名,需要base64 decode一次 $huifuSignature="TUlJSzl3WUpLb1pJaHZjTkFRY0NvSUlLNkRDQ0N1UUNBUUV4RHpBTkJnbGdoa2dCWlFNRUFnRUZBRENDQk9jR0NTcUdTSWIzRFFFSEFhQ0NCTmdFZ2dUVVpYbEtlbVZZVGpCYVZ6RktXa05KTmtsc1VrNVJla0YzVFVSRmQwbHBkMmxpTTBwcldsaEtTbHBEU1RaSmEwWlZUbFJSZWs1VVozaE5SRmt5VFdwTk1FNUVRVFZPYW1kM1NXbDNhVmxYTVRCSmFtOXBUWHBOZFUxRVJXbE1RMHBwWkZoT2VsWkliSGRhVTBrMlNXcEJlRWxwZDJsa1NFcG9ZbTVPYUZrelVuQmlNalZGV1ZoU2JFbHFiMmxOYWtGNFQwUkJNVTFVYTNoT1JFMDBUV3BWZUUxVVRXbE1RMG93WVZoU2MxcFRTVFpKZFZNMGFYVmhNWFFyWVhob0syRldjMDloWTJsbGJWcHJUMWRHY2s5WFVIVkRTWE5KYmxwc1kyNU9jR0l5TkdsUGFVbDRUR3BCZFUxRFNYTkpiVTVvWTIxU1QySjVTVFpKYWxreVRtcFpNazVxUVhkTlZFRjRUVlJqTUU1VVdUSk5SRmswU1dsM2FWbFhiSGxqUjNob1ltMVdRMlJZVG5waFZ6VnNZek5OYVU5dWMybFpNMHBzWkRCc2RXSnJSbXBaTVZaMVlWaFJhVTlwVEd4b2IxaHdaelpxYTNaS2NtOXljVVZwVEVOS2QySkhSblZhVmtwc1lsZEdlV0Y1U1RaSmRWZHJhQ3RoZW5GRFNYTkpia0p6V1ZjMWJGVklTblpVYlRocFQybE1jRzlpYm01dE5qZHVka3BpYkdvM1pFUlJWRUY0VFdwVk1FOUVaelJQUkdjMFNXbDNhVmxYVG1waU0xWjFaRVZWYVU5cFNUVlBWR3MxVDFSck5VOVVhMmxNUTBwM1lrZEdkVnBXVW5CWk1uUnNaRVUxZGtscWIybFJWbEV5VG1wWk1rNXFXV2xNUTBwM1lrZEdkVnBXVG14amJscHdXVEpXUW1KWVVXbFBhVWw1VGxNMGQwMURTWE5KYlU1NVdsaGtUMko1U1RaSmEwNUNUbXBaTWs1cVdUSlBRMGx6U1c1U2FHRXlWbEJhYlZwRldWaFNiRWxxYjJsTmFrRjRUMFJGZVUxNlFXbE1RMHA1V2xoT2JHTnVXbXhWYlZab1l6STVkVWxxYjJrMllVdEZOa3MyYVRVMVEwYzFOVk40U1dsM2FXTkhlR2hpYlZaSFdsZFZhVTlwU1hwTlJFRjFUVVJCYVV4RFNtcGpiVll6VWtkV2QyUkZOWFpKYW05cFVUQkdTbE5VUVhoSmFYZHBXVE5LYkdSNVNUWkpkV0ZwWjJWWFIzTlBVemR0VTBselNXNUNjMWxYTld4Vk1rWnpXbFpDZVdGWFRteEphbTlwVFdwQmQwMUROSGROUTBselNXNUNjMWxYTld4V1IyeHFZVEpXTUZRelZqQlNSMFl3V2xOSk5rbHFTWGROVkdkM1RsUkpNa2xwZDJsYWJYaHdXakpvTUZSdVZuUkphbTlwVVRGdmVrMVVRbGhKYVhkcFdUTktiR1F3Um1wWk1WWjFZVmhSYVU5cFRHdDJTbkp2Y25GSWJHcGFXR3QyV1RCcFRFTktlbHBYWkhSYVZ6VXdTV3B2YVRWWmVWZzFUSEZ6VEZNemEzVkpjbTEwWW1OcFRFTktkMkpIUm5WYVZVWnVXbGMxTUZGWE1UQkphbTlwVGxSQmRVMUVRV2xNUTBwM1lrZEdkVnBWVG5aaWJrNHhZbGRXVldWWVFteEphbTlwVFVSRmFVeERTbmxhVnpGb1kyMXplRWxxYjJsTlJFVnBURU5LZW1GSGJIZGpSMngxV2pGT2QxbFhUbXhXU0d4M1dsTkpOa2xxUlhoSmFYZHBZMjFXZEZsWVNuSk5hVWsyU1dwSmVrMUVSWGhQVkVVMVQwUlpkMDlVVlRCTmVrbDRUV2xLT1V4RFNtcGlWMUpLV2tOSk5rbHRVblpSV0ZZd1lVYzVlV0ZZY0doa1IyeDJZbXhTVGxGNVNYTkpiVTVvWWtkNGFWbFhUbkpXV0VwelNXcHZhV0ZJVWpCalJHOTJUSHBGTTAxcE5IcE5VelI0VDBNMGVrNXFielJOUkdkNFRIcEpkbU50T1hOaVIwcG9XVEp6ZG1SSE1XcEphWGRwWkVoS2FGcEhWbFZsV0VKc1NXcHZhVTFFUldsTVEwb3dZVmN4YkdNelVtaGlXRUZwVDJsSmVFNVVUWGRPZW1ONVRrUkZNVTVxWXpGSmJqQTlvSUlFVERDQ0JFZ3dnZ013b0FNQ0FRSUNCVUFDbVRrME1BMEdDU3FHU0liM0RRRUJDd1VBTUYweEN6QUpCZ05WQkFZVEFrTk9NVEF3TGdZRFZRUUtFeWREYUdsdVlTQkdhVzVoYm1OcFlXd2dRMlZ5ZEdsbWFXTmhkR2x2YmlCQmRYUm9iM0pwZEhreEhEQWFCZ05WQkFNVEUwTkdRMEVnUVVOVElGUkZVMVFnVDBOQk16RXdIaGNOTVRnd01UQTVNREl3TlRNMldoY05Nak13TVRBNU1ESXdOVE0yV2pCeE1Rc3dDUVlEVlFRR0V3SkRUakVWTUJNR0ExVUVDaE1NUTBaRFFTQlVSVk5VSUVOQk1SRXdEd1lEVlFRTEV3aE1iMk5oYkNCU1FURVpNQmNHQTFVRUN4TVFUM0puWVc1cGVtRjBhVzl1WVd3dE1URWRNQnNHQTFVRUF4UVVNRFV4UURnNE9EZzRPRUJPTVRFeE1UTXdRREV3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRE0rdVhlQ0ZuYlNjdkNMbTZUc1Uyc01CT2F2MmM0SWV5YmFjTnRZNkk2Y0owRXQ4U3lGS1NRSHUyTkVRSXFrQlJEbmdubkx2dlMyaFRmdkVkTFhqa012dHZxbXI4UVRzdzNUSGRYUC9sc3FPbmg0SHcrTDNoVlgrZzFaeDlZaGQvOXhGRGIraE94T1k0ajlaTTVaRkVWMCtiMXhzcDJGeDQ0bTNvQ2dPL2x4VTNBOUVWQ0JlcUdQajF0MjRyNVN6a3pGQ2FUc203c2V0UEI0c1FqSnZlcjlwNHMzcFZMbXFSV1N5V2FhbnQzOHg1di95Q043SDhBK0wzd3U1bElWcUlaOGFrd1F1bVNMeGkyRWtMOE9TRWhLWTN2b2xwdWFlbHZSTXBRUDBtbmx0YzBidXZKZ2gxeGxIUEpSRVk5a2ZhZkZHMGx1VENXNkF3NTNtdUUrVjEzQWdNQkFBR2pnZm93Z2Zjd1B3WUlLd1lCQlFVSEFRRUVNekF4TUM4R0NDc0dBUVVGQnpBQmhpTm9kSFJ3T2k4dmIyTnpjSFJsYzNRdVkyWmpZUzVqYjIwdVkyNDZPREF2YjJOemNEQWZCZ05WSFNNRUdEQVdnQlNhUGJTdVpWajd6bG9GZUNhZ2JTc0VocnJHN0RBTUJnTlZIUk1CQWY4RUFqQUFNRGNHQTFVZEh3UXdNQzR3TEtBcW9DaUdKbWgwZEhBNkx5OHlNVEF1TnpRdU5ESXVNeTlQUTBFek1TOVNVMEV2WTNKc01qa3VZM0pzTUE0R0ExVWREd0VCL3dRRUF3SUd3REFkQmdOVkhRNEVGZ1FVNVN3eVBrU0p3eHA1V2plNnRyRlFmMFB0ZFZzd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3SUdDQ3NHQVFVRkJ3TUVNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUNnb2hXMlYxZTNXQW1GSTlRbGVpZmVNZ1VqcHg3cWRUZWNOdGV6SzdrbDVFM2ladjl6T001NTV1WmN0R0VqVm5rMWtBMGlEMDlaV005eEo5ZFNnUlEvVUliTU5YQmxJdWJJTFlrcG14cWlOVmVObXZmYXlCMmJUemtEOEM2Q2RjOXladXNoMmJmNkdBS2hZTk8zNkpRdGdRdG51aEtiVUNpSXg4aG5DZFZwQjRXT0Vwa0J5R2JadVVqcFpTYS81V1NXUFpZanBPdWU5Sm44Qjc0Z1FRam5ORURRZ1FEaFN6b0NyQjVLcWV1K2dlZWx2MTVCN05kSnFBTC9vZWZCZjNZK3pHR3VGa0pZNWg0cW4vcVkxMTFUdWJmTXAvM1YyUDZJRmd2b3ZubWNGcmQxeCtxMWROM3Q2cUJUUmEybjJXM25BRitCWDkvd0lYRFZFd0NTM29LR01ZSUJrVENDQVkwQ0FRRXdaakJkTVFzd0NRWURWUVFHRXdKRFRqRXdNQzRHQTFVRUNoTW5RMmhwYm1FZ1JtbHVZVzVqYVdGc0lFTmxjblJwWm1sallYUnBiMjRnUVhWMGFHOXlhWFI1TVJ3d0dnWURWUVFERXhORFJrTkJJRUZEVXlCVVJWTlVJRTlEUVRNeEFnVkFBcGs1TkRBTkJnbGdoa2dCWlFNRUFnRUZBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NBUUNhRXNpVFlVL2t6T2ZZNnZlMU1oQjVXMlB5a1M3aGtxejMzS05rMWtHTE5qb0dCVGFiZzQvVks4aktMbnFEMVJNbFNVNjd0THFiNkE0UVcrcFRXdWdEYllmUUQ4eUszR1BGUEZXODBKb0NkaXBtK1MxMjFxZFozWU5mT0h5NTM1WXlqV0tvTmpiYUJxTGxYdkIxZG1ldHE0RmlzbGlIWDJpdFJDS2VlcnZtWHFtQXBwb2N6czBWU1pySi9vOEpGTkhxMFJoaTU5VGh0dDJDYml5bTRReUVSWU9hekVydWNSeVdNZlVIclAzd0xRZUVVdkVQTGJjS1V2M2VDR29UVmQvaVZPVUtVLzZHOGkwRWQyR21udnRaRERSWjdjaWRhNmZ4dldyeUpzQWt2TXpEYWd3OUZlYjBmVTA1QUFoaWtJbENUMk5icUZoUHFIV0JKYjlWeGhWMA=="; $huifuSignature = base64_decode($huifuSignature); //验签 $strBase64CertContent = ""; $strBase64CertContent = $CryptoAgentServerObj->VerifyDataSignature_PKCS7Attached($strSignAlg, $huifuSignature); echo "strMsgP7AttachedSignCertContent:".$strBase64CertContent."\n\n"; //获取原文 $strMsgP7AttachedSource = ""; $strMsgP7AttachedSource = $CryptoAgentServerObj->GetSignSourceData($strMsgPKCS7AttachedSignature); echo "strMsgP7AttachedSource:".$strMsgP7AttachedSource."\n\n"; //校验证书链,防止伪造证书 $nCertVerifyFlag = 4; $strTrustedCACertFilePath = "../TestData/RSA/CFCA_ACS_TEST_CA.cer|../TestData/RSA/CFCA_ACS_TEST_OCA31.cer"; $strCRLFilePath = ""; $bCertVerifyResult = false; $bCertVerifyResult = $CryptoAgentServerObj->VerifyCertificate($strBase64CertContent, $nCertVerifyFlag, $strTrustedCACertFilePath, $strCRLFilePath); echo "bCertVerifyResult:".$bCertVerifyResult."\n\n"; if($bCertVerifyResult==1){ echo "pass"; } //获取证书公钥,输出证书信息 // $strBase64CertContent = ""; // $strBase64CertContent = $CryptoAgentServerObj->GetPublicCertFromPFX($strSignAlg, $strPfxFilePath, $strPfxPassword); // echo "strBase64CertContent:".$strBase64CertContent."\n\n"; // $strInfoType = "CertType"; // $strCertType = ""; // $strSubjectDN = ""; // $strSubjectCN = ""; // $strIssuerDN = ""; // $strSerialNumber = ""; // $strValidFrom = ""; // $strValidTo = ""; // $strCertType = $CryptoAgentServerObj->GetCertificateInfo($strBase64CertContent, $strInfoType); // echo "strCertType:".$strCertType."\n"; // $strSubjectDN = $CryptoAgentServerObj->GetCertificateInfo($strBase64CertContent, "SubjectDN"); // echo "strSubjectDN:".$strSubjectDN."\n"; // $strSubjectCN = $CryptoAgentServerObj->GetCertificateInfo($strBase64CertContent, "SubjectCN"); // echo "strSubjectCN:".$strSubjectCN."\n"; // $strIssuerDN = $CryptoAgentServerObj->GetCertificateInfo($strBase64CertContent, "IssuerDN"); // echo "strIssuerDN:".$strIssuerDN."\n"; // $strSerialNumber = $CryptoAgentServerObj->GetCertificateInfo($strBase64CertContent, "SerialNumber"); // echo "strSerialNumber:".$strSerialNumber."\n"; // $strValidFrom = $CryptoAgentServerObj->GetCertificateInfo($strBase64CertContent, "ValidFrom"); // echo "strValidFrom:".$strValidFrom."\n"; // $strValidTo = $CryptoAgentServerObj->GetCertificateInfo($strBase64CertContent, "ValidTo"); // echo "strValidTo:".$strValidTo."\n"; } catch(Exception $e) { echo "Message:".$e->getMessage(); $strErrorMsg=$CryptoAgentServerObj->GetLastErrorDesc(); echo "\n".$strErrorMsg; } ?> .. C# 代码示例 ~~~~~~~~~~~~~~~~~~~~~~~~~ `DEMO 下载 <_static/lib/c_windows.rar>`_ Demo 运行环境要求:WinServer2008、 WinServer2012 SignData_PKCS7Attached 为使用pfx证书加签 VerifyDataSignature_PKCS7Attached 为验证汇付的签名 VerifyCertificate 为验证证书链合法性 GetCertificateInfo 为获取证书信息(非必要) 替换证书和cer文件(TestData文件为测试DEMO证书) pfx为私钥文件请妥善保管不要泄露给他人 cer文件为颁发者公钥,用来验证汇付公钥 c# .. code:: c# using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace app_plus { class Sign { //动态库调用,非COM方式,指定dll位置或使用相对目录 [DllImport("C:\\SADK.Standard.x64.dll")] public static extern int Initialize(); [DllImport("C:\\SADK.Standard.x64.dll")] public static extern int SignData_PKCS7Attached(string strAlgorithm, byte[] pbySourceData, int nSourceSize, string strPFXFilePath, string strPFXPassword, string strHashAlg, ref IntPtr ppstrBase64PKCS7Signature); [DllImport("C:\\SADK.Standard.x64.dll")] public static extern int VerifyDataSignature_PKCS7Attached(string strAlgorithm, string strBase64PKCS7AttachedSignature, ref IntPtr pptrBase64SignCertContent, ref IntPtr pptrSourceData, ref int pnSourceDataSize); [DllImport("C:\\SADK.Standard.x64.dll")] public static extern int Uninitialize(); [DllImport("C:\\SADK.Standard.x64.dll")] public static extern void FreeMemory(IntPtr ptrBuf); static public string sign(string plain_text) { int nResult = Initialize(); if (nResult != 0) return null; string strAlgorithm = "RSA"; byte[] sourceData = null; //string strPFXFilePath = "C:/888888-汇付测试商户.pfx"; //string strPFXPassword = "888888"; string strPFXFilePath = "C:/888888-NEW.pfx"; string strPFXPassword = "123456"; string strHashAlg = "SHA-256"; IntPtr ppstrBase64PKCS7Signature = IntPtr.Zero; string strBase64PKCS7Signature = ""; string sign_text = null; sourceData = System.Text.Encoding.UTF8.GetBytes(plain_text); string base64_str = System.Convert.ToBase64String(sourceData); sourceData = System.Text.Encoding.UTF8.GetBytes(base64_str); nResult = SignData_PKCS7Attached(strAlgorithm, sourceData, sourceData.Length, strPFXFilePath, strPFXPassword, strHashAlg, ref ppstrBase64PKCS7Signature); if (nResult == 0) { strBase64PKCS7Signature = InptrToUTF8String(ppstrBase64PKCS7Signature); byte[] bSignText = System.Text.Encoding.UTF8.GetBytes(strBase64PKCS7Signature); sign_text = System.Convert.ToBase64String(bSignText); FreeMemory(ppstrBase64PKCS7Signature); } nResult = Uninitialize(); return sign_text; } static public string unsign(string sign_text) { int nResult = Initialize(); if (nResult != 0) return null; string strAlgorithm = "RSA"; string strBase64PKCS1Signature = System.Text.ASCIIEncoding.Default.GetString(Convert.FromBase64String(sign_text)); IntPtr ptrBase64SignCertContent = IntPtr.Zero; string strBase64SignCertContent = ""; IntPtr ptrSourceData = IntPtr.Zero; string strSourceData = ""; string plain_text = null; int nSourceDataSize = 0; nResult = VerifyDataSignature_PKCS7Attached(strAlgorithm, strBase64PKCS1Signature, ref ptrBase64SignCertContent, ref ptrSourceData, ref nSourceDataSize); if (nResult == 0) { byte[] bData = new byte[nSourceDataSize]; Marshal.Copy(ptrSourceData, bData, 0, nSourceDataSize); strSourceData = Encoding.UTF8.GetString(bData); byte[] bPlainText = System.Convert.FromBase64String(strSourceData); plain_text = System.Text.Encoding.UTF8.GetString(bPlainText); strBase64SignCertContent = InptrToUTF8String(ptrBase64SignCertContent); FreeMemory(ptrBase64SignCertContent); FreeMemory(ptrSourceData); } nResult = Uninitialize(); return plain_text; } static private string InptrToUTF8String(IntPtr ptrData) { string strData = ""; byte[] byteData = null; int i = 0, nSize = 0; while (true) { if (Marshal.ReadByte(ptrData, i) == '\0') { nSize = i; break; } i++; } if (0 != nSize) { byteData = new byte[nSize]; Marshal.Copy(ptrData, byteData, 0, nSize); strData = Encoding.UTF8.GetString(byteData); } for (int index = 0; index < strData.Length; index++) { char cr = strData[index]; if ((cr >= 'A' && cr <= 'Z') || (cr >= 'a' && cr <= 'z') || (cr >= '0' && cr <= '9') || (cr == '+') || (cr == '/')) { continue; } else if (cr == '=') { if (index < strData.Length-1 && strData[index+1] == '=') { strData = strData.Substring(0, index + 2); break; } else { strData = strData.Substring(0, index + 1); break; } } else { strData = strData.Substring(0, index); break; } } return strData; } } } .. 更新记录 ----------------- **2018.10.23 v3.0.6** - 新增 无卡收款绑卡短信接口_ - 新增 无卡收款绑卡接口_ - 新增 无卡收款短信发送接口_ - 新增 无卡收款接口_ - 新增 批量生成代发回执单接口_ - 商户文件上传接口_ 去除更新模式 **2018.09.28 v3.0.5** - 新增 企业开户申请接口_ **2018.09.11 v3.0.3.1** - 新增 商户基本信息查询接口_,用户绑卡查询接口_ **2018.09.06 v3.0.3** - 新增 商户文件上传接口_,商户文件下载接口_ **2018.09.04 v3.0.2** - 消费金融类代扣签约接口_ 返回参数添加绑卡 ID - 前台快捷绑卡代开户接口_ 返回参数添加绑卡 ID - 快捷绑卡代开户接口_ 返回参数添加绑卡 ID - APP支付接口_ 请求参数订单超时时间改为定长 14 位 - 取现绑卡代开户接口_ 返回参数增加绑卡 ID - 纯通道代扣签约接口_ 请求参数产品订单号改为非必填 - 新增 直接代扣支付接口_ - 个人开户省份地区可选,企业开户部分字段长度变更 **2018.08.16 v3.0.1** - 新增 银行限额列表查询接口_ - 快捷支付接口_ 新增上送设备信息 - 快捷支付统合版支付接口_ 新增上送设备信息 **2018.08.13 v1.1.8** - 银行卡解绑接口_ 短信验证码日期、短信验证码订单号和短信验证码修改为非必传 **2018.07.19 v1.1.7** - 扫码支付接口_ 新增银联二维码正扫 - APP支付接口_ 新增银联二维码正扫 - APP支付接口_ 支付新增小程序支付 **2018.04.02 v1.1.4** - 新增 重新绑卡查询_ - 代发接口_ 收款人手机号统一改为非必填 **2018.02.02 v1.1.3** - 新增 生利宝理财开通接口_、 生利宝理财关闭接口_、 申购接口_、 赎回接口_、 交易明细查询接口_ 和 收益查询接口_ - 扫码支付接口_、 反扫接口_、 APP支付接口_ 和 交易状态查询接口_ 返回参数添加外部订单流水号 **2018.01.24 v1.1.1** - 扫码支付接口_、 反扫接口_、 APP支付接口_ 和 交易状态查询接口_ 返回参数添加银行返回信息 **2017.12.27 v1.1.0** - 快捷支付接口_ 和 快捷支付统合版短信发送接口_ 请求参数银行代码、省份和地区修改为可选 - 扫码支付接口_ 、 反扫接口_ 、 快捷支付WEB版接口_ 、 快捷支付APP版接口_ 和 APP支付接口_ 增加二级商户号字段 .. _扫码支付接口: wxAliPay.html#id2 .. _反扫接口: wxAliPay.html#id9 .. _快捷支付WEB版接口: quickPay.html#id42 .. _快捷支付APP版接口: quickPay.html#id49 .. _APP支付接口: wxAliPay.html#app .. _消费金融类代扣签约接口: withholdPay.html#id32 .. _前台快捷绑卡代开户接口: quickPay.html#id23 .. _快捷绑卡代开户接口: quickPay.html#id17 .. _取现绑卡代开户接口: cash.html#id8 .. _纯通道代扣签约接口: withholdPay.html#id38 .. _银行限额列表查询接口: query.html#id57 .. _快捷支付接口: quickPay.html#id35 .. _快捷支付统合版支付接口: quickPay.html#id62 .. _银行卡解绑接口: quickPay.html#id74 .. _代发接口: substitutePay.html#id2 .. _生利宝理财开通接口: financial.html#id2 .. _生利宝理财关闭接口: financial.html#id9 .. _申购接口: financial.html#id15 .. _赎回接口: financial.html#id21 .. _交易明细查询接口: financial.html#id27 .. _交易状态查询接口: query.html#id2 .. _收益查询接口: financial.html#id33 .. _快捷支付统合版短信发送接口: appsiteapi_trans.html#id56 .. _重新绑卡查询: query.html#id31 .. _交易明细查询接口: financial.html#id27 .. _直接代扣支付接口: appsiteapi_trans.html#id57 .. _商户基本信息查询接口: query.html#id75 .. _用户绑卡查询接口: query.html#id81 .. _商户文件上传接口: query.html#id63 .. _商户文件下载接口: query.html#id69 .. _批量生成代发回执单接口: query.html#id44 .. _企业开户申请接口: user.html#id14 .. _无卡收款绑卡短信接口: user.html#id57 .. _无卡收款绑卡接口: user.html#id63 .. _无卡收款短信发送接口: quickPay.html#id80 .. _无卡收款接口: quickPay.html#id86