支付宝敏感信息解密
支付宝官方解密文档:https://docs.alipay.com/mini/introduce/aes
String response = "小程序前端提交的"; //1. 获取验签和解密所需要的参数 Map<String, String> openapiResult = JSON.parseObject(response, new TypeReference<Map<String, String>>() { }, Feature.OrderedField); String signType = StringUtil.defaultIfBlank(openapiResult.get("signType"), "RSA2"); String charset = StringUtil.defaultIfBlank(openapiResult.get("charset"), "UTF-8"); String encryptType = StringUtil.defaultIfBlank(openapiResult.get("encryptType"), "AES"); String sign = openapiResult.get("sign"); //如果密文的 boolean isDataEncrypted = !content.startsWith("{"); boolean signCheckPass = false; //2. 验签 String signContent = content; String signVeriKey = "你的小程序对应的支付宝公钥(为扩展考虑建议用appId+signType做密钥存储隔离)"; String encryptType = "你的小程序对应的加解密密钥(为扩展考虑建议用appId+encryptType做密钥存储隔离)" //如果是加密的报文则需要在密文的前后添加双引号 if (isDataEncrypted) { signContent = "\"" + signContent + "\""; } try { signCheckPass = AlipaySignature.rsaCheck(signContent, sign, signVeriKey, charset, signType); } catch (AlipayApiException e) { //验签异常, 日志 } if(!signCheckPass) { //验签不通过(异常或者报文被篡改),终止流程(不需要做解密) throw new Exception("验签失败"); } //3. 解密 String plainData = null; if (isDataEncrypted) { try { AlipayEncrypt.decryptContent(content, encryptType, decryptKey, charset); } catch (AlipayApiException e) { //加密异常, 日志 throw new Exception("解密异常"); } } else { plainData = content; }
虽然是参考代码,但个人感觉太随意了。做了一些简单的修改,编译和逻辑都没有问题了。
/** * 敏感信息解密 */ @PostMapping(value = "/decryptor", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public RestResponse decryptor(@RequestBody String encryptContent) { RestResponse restResponse = new RestResponse(); try { Map<String, String> openapiResult = JSON.parseObject(encryptContent, new TypeReference<Map<String, String>>() { }, Feature.OrderedField); String signType = StringUtils.defaultIfBlank(openapiResult.get("sign_type"), "RSA2"); String charset = StringUtils.defaultIfBlank(openapiResult.get("charset"), "UTF-8"); String encryptType = StringUtils.defaultIfBlank(openapiResult.get("encrypt_type"), "AES"); String sign = openapiResult.get("sign"); String content = openapiResult.get("response"); LOGGER.info(String.format("准备验签和解密,sign=[%s], signType=[%s], encryptType=[%s], encryptContent=[%s]", sign, signType, encryptType, encryptContent)); //如果密文的 boolean isDataEncrypted = !content.startsWith("{"); boolean signCheckPass; //2. 验签 String signContent = content; //支付宝应用公钥 String signVeriKey = ALIPAY_APPLET_PUBLIC_SECRET; //如果是加密的报文则需要在密文的前后添加双引号 if (isDataEncrypted) { signContent = "\"" + signContent + "\""; } try { signCheckPass = AlipaySignature.rsaCheck(signContent, sign, signVeriKey, charset, signType); } catch (AlipayApiException e) { //验签异常, 日志 LOGGER.error("验签异常,encryptContent=" + encryptContent, e); restResponse.setRestStatus(RestStatus.FAIL_100021); return restResponse; } if (!signCheckPass) { //验签不通过(异常或者报文被篡改),终止流程(不需要做解密) LOGGER.error("验签失败,encryptContent=" + encryptContent); restResponse.setRestStatus(RestStatus.FAIL_100021); return restResponse; } //支付宝小程序AES秘钥 String encryptKey = ALIPAY_APPLET_AES_SECRET; //3. 解密 String plainData; if (isDataEncrypted) { try { plainData = AlipayEncrypt.decryptContent(content, encryptType, encryptKey, charset); } catch (AlipayApiException e) { //解密异常, 日志 LOGGER.error("解密异常,encryptContent=" + encryptContent, e); restResponse.setRestStatus(RestStatus.FAIL_100021); return restResponse; } } else { plainData = content; } restResponse.setData(plainData); restResponse.setRestStatus(RestStatus.SUCCESS); } catch (Exception e) { LOGGER.error("验签解密异常,encryptContent=" + encryptContent, e); restResponse.setRestStatus(RestStatus.FAIL_100021); } return restResponse; }
解密报文示例。
{"response":"+A9tOP5n2uUJaQRJOxLj6+rR0yooZWC/SQhcHDJ1BbLKkEA+hUr2ah3KOzL/+RwuyO4mH5ZSeFRpOrNPyTac/w==","sign":"V9OSmt5iTWr2tqpW/p6jjTcvpdiva8WxjnC7nvqyHg5eT181/61wcKysoTgLuNfFd2XbKvULHxi9mZDIh3OAR1PDIs0aOEhzimORbf9wBofoWfGKlq2iwWKeSSnxyS0W4maF0VrS0kNySsx5ta7eBGtSlGozOOR6R7oeygNdd43jOo33pZmUA0fo6DSHZH5lblrwqL4t0UcLSFLx1kqVNi28BsRQA5OxqkUp78PsxPGdps0CI9gQcAHfCKbKYk6F1bimw+R3k7ympm2esdEfl59Yym7lpz7gtOkGuNDjY3Y/urrYwGt7Kq/EX5BcIYA4DCS4nPkyb3wPRkH1VKBE+g=="}
或者
{
"response": "hvDOnibG0DPcOFPNubK3DEfLQGL4=",
"sign": "OIwk7zfZMp5GX78Ow==",
"sign_type": "RSA2",
"encrypt_type": "AES",
"charset": "UTF-8"
}
本文来自博客园,作者:hjzqyx,转载请注明原文链接:https://www.cnblogs.com/hujunzheng/p/10184418.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端