在服务商平台的API接口中,有部分接口在传参时,需要对参数中的敏感信息进行RSA加密(如:小微商户申请入驻、小微商户修改结算信息等)。在这些接口的参数加密说明中,是这样注明的:

加密方法详见敏感信息加密方法说明(该md文件中的变量PUBLIC_KEY_FILENAME是表示平台证书,即为证书及其序列号获取方法说明PDF文档中1.1.5小节中的”加密后的证书内容encrypt_certificate.ciphertext"解密后的明文。)

因此,我们在对敏感信息加密前,需要先获得ciphertext,然后对ciphertext进行解密,解密出来的明文就是加密敏感信息所需的加密公钥了,将该公钥保存为文件就是公钥证书啦(该公钥证书有效期为5年,不过微信支付要求“中控服务器需要定时查询商户的平台证书列表,查询间隔应小于 12 小时,并及时下载新的平台证书。下载证书时,需与本地证书序列表对比,如果发现有新增证书序列号,那就是需要新换的证书。老证书需要在被弃用前及时清理掉”)

关于获取公钥的具体说明可以参阅腾讯官方提供的pdf文档  《证书及其序列号获取方法说明 》 中的1.1.3.3 以外的章节。



1.1.2. 接口地址

请求 Url

https://api.mch.weixin.qq.com/v3/certificates

请求方式

GET

1.1.3. 接口调用规则

  • 非必填字段的值如果为空,请求报文里面不能传递该参数,否则会报错
  • 微信支付侧有可能在不破坏协议兼容性的前提下,增加请求参数或者应答对象中的字段。商户应当兼容未来可能加入的新字段。
  • 认证方式:HTTPS 认证,SHA256 with RSA 签名
  • 字符集默认使用 UTF-8,请勿使用其它字符集
  • 商户与微信之间的交互(特别是支付通知回调),都需要验证签名
  • 处理返回时先判断 HTTP 状态码,再判断返回数据中的错误码,才能确定交易状态
  • 返回和提交数据的签名,商户号,时间戳,随机串等在 HTTP 头中传递
  • HTTP 请求头设置规则如下:

请求头

必填

说明

Accept

应答的格式。目前仅支持:application/json

Accept-Language

应答的区域语言。目前支持:en,zh-CN,zh-HK,zh-TW,不传则默认是:zh-CN 。详细请参考设置错误描述语言章节

Authorization

含有服务器用于验证商户身份的凭证。详细信息请参考签名生成方法章节

Content-Type

请求数据(Body)的格式。当请求包含请求数据时必填。目前仅支持:application/json

User-Agent

发起请求的客户端软件的标识信息

1.1.3.1. Authorization 的构造方式

微信支付要求请求通过 HTTP Authorization 头来传递签名。Authorization 由认证类型和签名信息两个部分组成。

Authorization: 认证类型 签名信息

具体组成为:

认证类型:目前为 WECHATPAY2-SHA256-RSA2048

签名信息:

商户号 mchid
请求随机串 nonce_str
签名值 signature(详见 1.1.3.2 计算签名值方法)
时间戳 timestamp
商户证书序列号 serial_no(详见 1.1.3.4 获取商户证书序列号方法)

Authorization 头的示例如下:(注意,示例因为排版可能存在换行,实际数据应在一行,mchid 前有一个空格)

Authorization: WECHATPAY2-SHA256-RSA2048 mchid="10000100",nonce_str="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg",signature="hDV4aXhMvfZ31NABElvWHWuxYiR7lB1sjzcpldpWul/62o75d90l5oznquE+uVORPESfzBpCdtU6IiL+1Cdy3rG01sKXrWfFnjr4jm/imFxbq8BbVpE+HbrRXkR/jrc6gqSVuIjJfXSMK1yL5G35WgUWzWdAKiV3ELQk/sSYrhnOiulve/xM2bJvYFQDl/dvMazxW930JLm0lv1tEMuHuqcx5WN+1fq3VJ+J9UvwVTjQT8eXmHAzaYxXHEoDyN2T5/AVzZTuzcCt1cFk5Sj/tNUvDMklxy+eF7hOUCFzo98Z42OsdpC3GV02mYOApeNwVB7I5fCB//jerFqf9/VjA==",timestamp="1507709632",serial_no="345D5C1DB746787546E06E6DAD9E5BE987CEDFCF"

1.1.3.2. 计算签名值方法

构造待签名串

在运用具体的签名算法前,商户需要先构造待签名串。

第一步,获取 HTTP 请求的方法(GET,POST,PUT 等)

GET

第二步,获取请求的 URL,并去除域名的部分,如果链接带参数,参数值必须进行 URLencode。示例请求的 URL 为

/v3/certificates

第三步,生成一个请求随机串,算法可开发者自定义(可调用系统随机数生成函数转化成字符串),建议长度不少于 10 位。

kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg

第四步,获取发起请求时的系统当前时间戳,即格林威治时间 1970 年 01 月 01 日 00 时 00 分 00 秒(北京时间 1970 年 01 月 01 日 08 时 00 分 00 秒)起至现在的总秒数,作为请求时间戳。时间戳必须是最新的,如果时间戳比微信支付服务器时间晚 300 秒,微信支付服务器会不认这个请求并报错,请商户保持自身系统的时间准确。

1507709906

第五步,获取提交数据。注:当请求方法为 GET 时,请求报文为空。

 

第六步,按照如下方法,组成待签名串。待签名串共有五行,每行包括一个参数,行尾以\n 结束,包括最后一行。请注意,\n 为换行符(ASCII 编码值为 0x0A)。

HTTP 请求方法\n
URL\n
请求时间戳\n
请求随机串\n
请求报文\n

按照以上规则,请求报文的待签名串为:

GET
/v3/certificates
1507709906
kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg

请注意,当请求方法为 GET 时请求报文为空,最后一行仅为一个换行符。

因此可以定义签名串变量

String signContent=“GET\n/v3/certificates\n1507709906\nkYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg\n\n”

计算签名值

1) 如上方法,得到签名串变量 signContent

2) 获取商户证书私钥。请参照博文微信支付服务商API 证书(权威CA颁发)是做什么用的?

超级管理员登录商户平台,在“账户中心”->“API 安全”->”API 证书(权威 CA 颁发)”中申请 API 商户证书,申请过程中会获取到私钥证书文件(申请流程详见 1.1.3.3“申请 API 商户证书“),打开私钥文件获取私钥字符(定义变量 string sKey)

3) 设置 APIv3 密钥

4) 很多编程语言支持签名函数,建议商户优先调用该类函数,使用商户证书私钥(sKey)对待签名串(signContent)进行 SHA256 with RSA 签名,并对签名结果进行 Base64 编码得到签名值。(如 java 语言提供了 PKCS8EncodedKeySpec、KeyFactory、Base64、PrivateKey 和 Signature 等类)

。。。。。。

1.1.4. 请求参数

请求示例:

curl -v -X GET "https://api.mch.weixin.qq.com/v3/certificates" WECHATPAY2-SHA256-RSA2048 -H 'Authorization:mchid="10000100",nonce_str="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg",signature="hDV4aXhMvfZ31NABElvWHWuxYiR7lB1sjzcpldpWul/62o75d90l5oznquE+uVORPESfzBpCdtU6IiL+1Cdy3rG01sKXrWfFnjr4jm/imFxbq8BbVpE+HbrRXkR/jrc6gqSVuIjJfXSMK1yL5G35WgUWzWdAKiV3ELQk/sSYrhnOiulve/xM2bJvYFQDl/dvMazxW930JLm0lv1tEMuHuqcx5WN+1fq3VJ+J9UvwVTjQT8eXmHAzaYxXHEoDyN2T5/AVzZTuzcCt1cFk5Sj/tNUvDMklxy+eOF7hOUCFzo98Z42OsdpC3GV02mYOApeNwVB7I5fCB//jerFqf9/VjA==",timestamp="1507709632",serial_no="345D5C1DB746787546E06E6DAD9E5BE987CEDFCF"' -H 'Accept-Language:' -d -H 'Content-Type:application/json' -H 'Accept:application/json' -H 'User-Agent: curl/7.54.0'

1.1.5. 返回结果

异常返回:

名称

变量名

必填

类型

示例值

描述

返回状态码

code

string(32)

INVALID_REQUEST

错误码,枚举值见错误码列表

返回信息

message

string(256)

参数格式校验错误

返回信息,如非空,为错误原因

正常返回:

名称

变量名

必填

类型

示例值

描述

加密的平台证书序列号 serial_no string(40)

5157F09EFDC096DE1

5EBE81A47057A7232F1B8E1

证书的序列号
证书启用时间 effective_time string(32) 2018-06-08T10:34:56+08:00 启用证书的时间,时间格式为?RFC3339。每个平台证书的启用时间是固定的。
证书弃用时间 expire_time string(32) 2018-06-08T10:34:56+08:00 弃用证书的时间,时间格式为?RFC3339。更换平台证书前,会提前24 小时修改老证书的弃用时间,接口返回新老两个平台证书。更换完成后,接口会返回最新的平台证书。
加密证书的算法

encrypt_certificat

e.algorithm

string(32) AEAD_AES_256_GCM 加密证书的算法,密钥为APIv3 KEY, 需要登录商户平台设置
加密证书的随机串

encrypt_certificat

e.nonce

string(12) 61f9c719728a 加密证书的随机串
关联数据

encrypt_certificat

e.associated_data

string(32) certificate 固定值: certificate
加密后的证书内容

encrypt_certificat

e.ciphertext

string(344)

Y1IPF0kyPUySt2tRe+aJ7TK6c

w08pqiXPr1g/agxl16AYarlrcsdq

1P8gcJc4iVkQfYouooRJdF4Eo…..

使用 APIv3 KEY 和上述参数,可以解密出平台证书的明文。证书明文为PEM 格式。(注意:更换证书时会出现 PEM格式中的证书失效时间与接口返回的证书弃用时间不一致的情况)

举例如下:

{"data":[{"serial_no":"5157F09EFDC096DE15EBE81A47057A7232F1B8E1","effective_time ":"2018-06-08T10:34:56+08:00","expire_time ":"2018-12-08T10:34:56+08:00","encrypt_certificate":{"algorithm":"AEAD_AES_256_GCM","nonce":"61f9c719728a","associated_data":"certificate","ciphertext":"sRvt… "}},{"serial_no":"50062CE505775F070CAB06E697F1BBD1AD4F4D87", //这个证书序列号在小微商户申请入驻接口调用时需要用到"effective_time ":"2018-12-07T10:34:56+08:00","expire_time ":"2020-12-07T10:34:56+08:00","encrypt_certificate":{"algorithm":"AEAD_AES_256_GCM","nonce":"35f9c719727b","associated_data":"certificate","ciphertext":"aBvt… "}}]
}

“加密后的证书内容”的解密算法:

下面详细描述对通知数据进行解密的流程

  1. 从微信支付商户平台上获取商户的 APIv3密钥,记为“key”。
  2. 针对“algorithm”中描述的算法(目前为“AEAD_AES_256_GCM”),取得对应的参数“nonce”和“associated_data”。
  3. 使用“key”、“nonce”和“associated_data”,对数据密文“ciphertext”进行解密,得到平台证书的原文。
  4. 将原文写入文件,使用该文件对敏感字段进行加密。

注: “AEAD_AES_256_GCM”算法的接口细节,请参考 rfc5116。微信支付使用的密钥“key”长度为 32 个字节,随机串“nonce”长度 12 个字节,“associated_data”长度小于 16 个字节并可能为空。

很多编程语言支持 “AEAD_AES_256_GCM”算法,如 java 语言中的 Cipher、SecretKey、GCMParameterSpec、Base64 等类。



官方说明pdf文档看完了,现在可以来捋一下步骤了:

  1. 通过证书私钥字符对报文进行SHA256 with RSA签名
  2. 将签名与商户号、请求随机串、时间戳、商户证书序列号一起,构建Authorization 头
  3. 往接口地址 https://api.mch.weixin.qq.com/v3/certificates 发送GET请求,请求时HTTP头需要包括Accept、Content-Type、User-Agent、Authorization等
  4. 对返回值中的“encrypt_certificate.ciphertext”进行 “AEAD_AES_256_GCM”算法解密
  5. 保存解密所得的明文为敏感信息加密公钥证书

简单点,直接上nodejs代码。

var https = require("https");
var crypto = require('crypto');app.get('/wpayGenMgPkey',function(req,res){     //1、通过证书私钥通过证书私钥字符对报文进行SHA256 with RSA签名var pcert = '-----BEGIN PRIVATE KEY-----\n这里对应新的API 证书(权威CA颁发)中的私钥文件字符串\n-----END PRIVATE KEY-----';var now = parseInt(Date.now() / 1000);var rdm = parseInt(Math.random() * Math.pow(2, 64));var plainText = 'GET\n/v3/certificates\n' + now + '\n' + rdm + '\n\n';var data = new Buffer(plainText,'utf8');var sign = crypto.createSign("RSA-SHA256");sign.update(data);var signStr = sign.sign(pcert, 'base64');var mch_id = "这里对应服务商商户号";//2、将签名与商户号、请求随机串、时间戳、商户证书序列号一起,构建Authorization 头var Auth = 'WECHATPAY2-SHA256-RSA2048 mchid="' + mch_id + '",nonce_str="' + rdm + '",signature="' + signStr + '",timestamp="' + now + '",serial_no="这里对应新的API 证书(权威CA颁发)中的证书序列号"';//3、往接口地址 https://api.mch.weixin.qq.com/v3/certificates 发送GET请求,请求时HTTP头需要包括Accept、Content-Type、User-Agent、Authorization等var opts = {method:'GET',hostname:'api.mch.weixin.qq.com',port:'443',pfx:fs.readFileSync('./cert/这里对应新的API 证书(权威CA颁发)中p12证书文件.pfx'), //直接将.p12改后缀名为.pfx即可,此配置可以不填写passphrase:mch_id,path:"/v3/certificates",host:'api.mch.weixin.qq.com'      }var body = '';var rq = https.request(opts,function(rs){rs.on('data',function(data){body += data;})rs.on('end', function(){var cJson = JSON.parse(body);if(cJson.data){//4、对返回值中的“encrypt_certificate.ciphertext”进行 “AEAD_AES_256_GCM”算法解密var nJson = cJson.data[cJson.data.length - 1];var keys = '这里对应APIv3密钥串';//编码设置var clearEncoding = 'binary';//加密方式var algorithm = 'aes-256-gcm';//向量var iv =  nJson.encrypt_certificate.nonce;//加密类型 base64/hex...var cipherEncoding = 'hex';//var cipherEncoding = 'base64';var cipherChunks = [];           var cdata = nJson.encrypt_certificate.ciphertext;cdata = new Buffer(cdata,'base64').toString('binary');var decipher = crypto.createDecipheriv(algorithm, new Buffer(keys, clearEncoding), new Buffer(iv, clearEncoding));decipher.setAutoPadding(true);      decipher.setAAD(new Buffer(nJson.encrypt_certificate.associated_data, clearEncoding))var data = new Buffer(cdata,clearEncoding);             var rtn = decipher.update(data, clearEncoding, "utf-8").toString("utf8");//这里加上这一句反倒会报错,不加的话解密出来的内容后面有一部分乱码,需要剔除//rtn += decipher.final("utf-8");                rtn = rtn.split('-----END CERTIFICATE-----')[0] + '-----END CERTIFICATE-----';rtn = rtn.replace(/\n/g,'\\n')//5、保存解密所得的明文为敏感信息加密公钥证书(这里请自己保存)res.send(rtn);        }else{res.send(body);}})});//注意:header必须通过setHeader函数写入,不能直接在opts中写rq.setHeader("Authorization",Auth);rq.setHeader("Accept","application/json");rq.setHeader("Accept-Language",'zh-CN');rq.setHeader("Content-Type","application/json");rq.setHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2763.0 Safari/537.36");//请求内容为空rq.write('');rq.on('error',function(err){if(fn){fn("<return_msg>" + err.message + "</return_msg>")}});  rq.end();
});

nodejs 如何通过API 证书(权威CA颁发)下载敏感信息加密公钥证书?相关推荐

  1. 微信支付服务商API 证书(权威CA颁发)是做什么用的?

    微信支付服务商平台于2018年7月份悄然在[账户中心]的[API安全]中增加了一个"API 证书(权威CA颁发)"版块,由于和原来的"API证书"版块命名相似, ...

  2. Java实现自签名证书,CA颁发证书

    产生证书库,并创建CA    X500Name 就是你的个人信息了,查查JAVA API 就行了 import java.io.File; import java.io.FileInputStream ...

  3. php 微信 ca证书出错,升级CA颁发的证书后微信退款、红包等无法使用

    前几天申请了新的微信支付商户号,按照流程申请了权威CA颁发的API证书,使用原来一直能正常使用(发红包.退款)的代码,发现新申请的微信支付无法运行退款接口,错误提示:certificate not m ...

  4. 数字证书、CA、CA证书,傻傻分不清楚?这一篇看懂!

    电子合同得到越来越多人的关注,而电子合同的安全性,更是人们关注的焦点.在电子合同领域,我们经常会听到这么3个词:数字证书.CA.CA证书,而且经常傻傻分不清楚它们到底是什么东西. 那么,今天小编就给大 ...

  5. 密码学专题 证书和CA指令 申请证书|建立CA|CA操作|使用证书|验证证书

    Req指令介绍 功能概述和指令格式 req指令一般来说应该是提供给证书申请用户的工具,用来生成证书请求以便交给CA验证和签发证书.但是,OpenSSL的req指令的功能远比这样的要求强大得多,它不仅可 ...

  6. 数字证书、CA、CA证书、SSL证书、CA锁 简单介绍

    1.数字证书是什么? 数字证书不是数字身份证,而是身份认证机构盖在数字身份证上的一个章或印(或者说加在数字身份证上的一个签名).其作用类似于现实生活中司机的驾驶执照或日常生活中的身份证. 2.CA是什 ...

  7. SSL数字证书之CA根证书、CA中间证书和SSL证书

    [前言] 说一下大背景吧,我们的一个后台服务需要部署在一个没法上外网的环境,但是我们的后台服务需要访问七牛云进行对象存储,于是乎,需要一个代理来完成这个访问,我门采用nginx七层来做这个代理,因为七 ...

  8. PHP开发微信支付小微商户V3版本 图片上传、生成签名、平台证书获取、平台证书编号、敏感信息加密

    吐槽一下,看微信支付小微商户的开发文档头都大了,什么是平台证书.什么是商户API证书...... 好了废话不多说下面明确几个名词: 商户API证书:是由权威CA颁发,用于有关微信支付等操作API接口使 ...

  9. java ssl证书_Java安全教程–创建SSL连接和证书的分步指南

    java ssl证书 在有关应用JEE安全性的系列文章中,我们为您提供了另一个有关如何在Java EE应用程序中创建SSL连接和创建证书的详细教程. 如我们之前的文章中所述, 安全套接字层(SSL)/ ...

最新文章

  1. 51CTO推荐博客、博客之星名单【2014年】
  2. JavaScript数组去重算法实例
  3. 2.11 while循环的嵌套以及应用(难)
  4. java swt.jar_Eclipse中的swt需要的jar包
  5. 【机器学习】集成学习之梯度提升树GBDT
  6. WPF 实现 DataGrid/ListView 分页控件
  7. 2017年Spring发布了30个新的Android库,值得您关注
  8. Pandas重复数据的查看和去重
  9. 源码大招:不服来战!撸这些完整项目,你不牛逼都难!
  10. linux 运行.net 5,.NET 5 将于2020年问世
  11. 2021沭阳中学高考成绩查询,沭阳建陵中学2020高考喜报!
  12. 面向对象的编程-类和实例
  13. c语言加密字母向右移两位,C语言二进制除法用左右移位来表示
  14. 编程基本功:如果可能,不用if,尽量使用switch
  15. 红旗Linux 网卡bond,Linux双网卡绑定一个IP的实现
  16. el-table点击单元格自动聚焦可编辑,且失去焦点即修改成功的实现方法
  17. 张帅帅学Java之注释
  18. Excel两行交换及两列交换,快速互换相邻表格数据的方法
  19. 求急!!谁会写接口测试,拜托了各位大佬,跪求!!我感激不尽,好好报答他
  20. Android自定义WebView实现Youtube网络视频播放控件

热门文章

  1. 哪些道理是你踏入社会才明白的?
  2. 在CD系统采用半导体激光器
  3. 读麦田反思BBS社区的文章有感
  4. HDU 5371 Hotaru's problem(Manacher算法+贪心)
  5. python创建变量revenue、并赋值为98765_Python序列与文件编程练习
  6. WCF全面解析(上下册)
  7. AnyDesk远程连接
  8. c语言编程 测试姓名缘分,姓名配对两人爱情结果 爱情测试游戏
  9. 风险平价组合(risk parity)理论与实践
  10. websocket是否需要处理粘包半包问题分析