微信退款通知信息解密

摘要:
在最近的开发需求中,有一个需求,就是需要把微信退款通知记录在数据库中,原本以为是一个简单的需求,但是微信文档的坑,是你不能理解的。在微信退款通知返回的字段中有一个加密信息字段req_info。

在最近的开发需求中,有一个需求,就是需要把微信退款通知记录在数据库中,原本以为是一个简单的需求,但是微信文档的坑,是你不能理解的。

在微信退款通知返回的字段中有一个加密信息字段req_info。这个加密字段需要三个解密步骤才能最终获取到信息。由此可见,这个字段是多么的重要。以下是微信官方文档给出的解密步骤:

解密步骤如下:

(1)对加密串A做base64解码,得到加密串B

(2)对商户key做md5,得到32位小写key* ( key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 )

(3)用key*对加密串B做AES-256-ECB解密(PKCS7Padding)

第一步,第二步都好理解,但是第三步说的真是太简单了。被坑了一天,现在把代码留下。

1.通过微信退款通知先获取到req_info这个字段

public static Map<String, String> xmlToMap(HttpServletRequest request) throws Exception {
Map<String, String> map = new HashMap<String, String>();
SAXReader reader = new SAXReader();
InputStream ins = request.getInputStream();
Document doc = reader.read(ins);
Element root = doc.getRootElement();
List<Element> list = root.elements();
for (Element e : list) {
map.put(e.getName(), e.getText());
}
ins.close();
return map;
}

这里使用DOM4j 首先把返回来的xml转换成map。从中获取req_info。

2.就是对req_info这个字段信息进行解密。

1. 对加密信息进行base64位解码。

byte[] b = org.bouncycastle.util.encoders.Base64.decode(req_info);

2.对商户API秘钥做MD5加密,得到小写的32位key

String key* =getMD5("your API key").toLowerCase().getBytes();

3.用刚才得到的key对加密串B做AES-256-ECB解密(PKCS7Padding)

public static String decryptData(byte[] b) throws Exception {
Cipher cipher = null;
cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
SecretKeySpec key = new SecretKeySpec(key*.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(b));
}

解密过后,就会返还xml,需要对xml进一步解析。

在整个解密过程中需要注意以下几点:

1. java 目前只支持PKCS5Padding,所以需要额外添加依赖。

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk16</artifactId>
<version>1.45</version>
</dependency>

2.如果报这个错Illegal key size or default parameters 就需要替换你JAVA_HOME/jre/lib/security 下面的两个jar包 local_policy.jar和US_export_policy.jar。

3.在解密类中需要添加一个静态代码块来提供支持,静态代码块如下:

static {
try {
Security.addProvider(new BouncyCastleProvider());
} catch (Exception e) {
e.printStackTrace();
}
}

以下 附上完整代码:

public class CipherTextUtil {

    private static final String serectKey = "your API Serect key";
/**
* 密钥算法
*/
private static final String ALGORITHM = "AES";
/**
* 加解密算法/工作模式/填充方式
*/
private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS7Padding";
/**
* 生成key
*/
private static SecretKeySpec key = new SecretKeySpec(MD5Util.MD5Encode(serectKey).toLowerCase().getBytes(), ALGORITHM);
static {
try {
Security.addProvider(new BouncyCastleProvider());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* AES解密
*/
public static String decryptData(byte[] b) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM_MODE_PADDING);
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(b));
}
public static void main(String[] args) throws Exception {
String A = "cms0dmeMS39cUWRUz19yJiPifeLRXoZjXhOnIhQlrz4SxDa2kmPVxHkMv2BeE+H+xr8euGyAO9sBNmS9ffugL7Xj47b9K6bwI8BLrP6/SwL3nTcrm44oimbJ4axAQLoaNuheqWYFS7pRBXAbByjjsBLzdMh+thCJjhFvyCK61fRMaUlkn6eZsc7fs609KgELGqSBdDlNsbXpTurgqdLdW07jPlsJZyXshg1gJ3b+n2wMC/pEZwPA/w7E0bAt0xzTIsYKmtLEwJlWg6Vf1KiocDfU0oVnhd5JPozxx4Cve67kUuGqDpdoStTBMXywHoAytklE610DvVKT59gkK9MqFU97SXV714wko6ZRKQAW0Utpx9DUko4jV3Hdwspr1JYUAg/GnINom25YbWQqKp28VKkJveXGeif5GEeUxeAmr4mYGvf9vD+bvBP2sH06koiOTJVVuIhvWmAdmFnNdk2hJkJdKvEtxxaNP7/eha5jDKNgjvCGV/hJNasl8U3qZX1qR0RtvcgoORt3nNvUOjQESNeS+tXlZtcpdZqDR4g7kQl5grAs+BOF6rk0qJ0PagxWF+arDSReLYBN5ihBkvai56s5Cv9iXFpVNkMwTBqYC4OpqzIN1EecA5fpi9pk7nVB3v5HLwp3oBYhbNiPNXkGTkuw634wBQtDLmeG3mXAYTX4xWdsYrkg4RY/rqFKsgeeBzGs7a7+PgbcE8B/t4/jVX3qVwbBkacqhG1l/W0zfZA8vHOJzVJhWEjXzn1iccQLiA6OASfnvRYoPnBoCX1qIjo0e55oCvRDau7hVTSvBx0hcpIjXmlcMcpJgiRXrPZFXgWh9myRkYtkCRleX49NELBOnK+sRHuJlfnpYYs9d1TurWzhXuu6wMow/wGQtyGC3XtQv0QTTg1KKDPRiqYq0QXMJ28+jL216Eg8qGrxmzXGYJ9Nf3oLh2TOZZvdhBbj+EM8T9+c/h3bAEe2L1wYtEJrqAMiSwZ6qW4dElQHBwL7sWha63gIB37vJ0SbyjWkqWWLUwwOMkDgvJ9r5I58O4OgzBtinC9k9yl90wO/dm0yuDTwF9agYlsPFP8XXClVdnvGQd+HUPk9YKB+WkyUww==";
byte[] b = Base64.decode(A);
String B = AESUtil.decryptData(b);
System.out.println(B);
}
}

完结,撒花撒花。。。。。

免责声明:文章转载自《微信退款通知信息解密》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Git 本地保存账号密码的删除或修改【转载】Iptables详解下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

企业微信会话存档消息解密(Java RSA PKCS1解密)

https://www.cnblogs.com/eleclsc/p/12082000.html 转:https://www.cnblogs.com/zengsf/p/10136886.html 在线rsa加解密工具:http://tool.chacuo.net/cryptrsaprikey 在linux环境中生成公私钥: openssl然后生成私钥: ge...

JAVA8的java.util.function包 @FunctionalInterface

1函数式接口java.util.functionhttps://www.cnblogs.com/CobwebSong/p/9593313.html2JAVA8的java.util.function包https://www.cnblogs.com/linzhanfly/p/9686941.html 3 Java HashMap computeIfAbse...

xml中“ &amp;lt; &amp;gt; ”转义为“ &amp;amp;lt; &amp;amp;gt; ”问题处理

曾经也碰到过类似问题,解决方法是在发送或者解析报文前执行上面的方法将内容转义一下,现在我用dom4j组装如下的报文(报文体中内容传输时加密处理),大致介绍一下上面方法的使用,具体看代码。 importjava.io.StringReader; importjava.io.StringWriter; importjava.math.BigDecima...

shell脚本中if的“-e,-d,-f”

文件表达式-e filename 如果 filename存在,则为真-d filename 如果 filename为目录,则为真-f filename 如果 filename为常规文件,则为真-L filename 如果 filename为符号链接,则为真-r filename 如果 filename可读,则为真-w filename 如果 filenam...

权限认证机制

一、Form表单认证 之前的项目以MVC为主,采用的是from表单认证,Forms认证示意图如下: HTTP是一个无状态的协议,WEB服务器在处理所有传入HTTP请求时,根本就不知道某个请求是否是一个用户的第一次请求与后续请求,或者是另一个用户的请求。 WEB服务器每次在处理请求时,都会按照用户所访问的资源所对应的处理代码,从头到尾执行一遍,然后输出响应...

scala 学习笔记(07) 一等公民的函数

在scala中一切皆对象,一切皆函数,函数跟Int,String、Class等其它类型是处于同等的地位,换句话说,使用函数跟使用普通的类型一样,没什么区别,因此: 1、函数可以赋值给变量,可以当参数传递 def helloWorld(msg: String): Unit = { println("Hello," + msg) }...