Android 使用支付接口,需要进行的加密逻辑:MD5、HMAC-SHA256以及RSA
目录
- 前言
- MD5
- HMAC-SHA256
- RSA
- 其他
前言
不使用加密:支付系统如同「裸奔」,面临数据泄露、资金被盗、法律追责等风险。
正确使用加密:构建「端到端安全防线」,确保交易合法可信,同时满足国际合规要求。
支付系统作为金融基础设施,加密不是可选项,而是业务存续的必要条件。任何加密方案的疏漏都可能导致系统性风险、。
在对接第三方支付的时候,最麻烦的问题是什么???没错,就是加密,每个第三方的,可能都还不一样,导致我们开发时间变长,这里我们就来梳理一下最常见的三种加密方式。
一、md5
MD5 是一种哈希函数,用于生成数据的唯一指纹(哈希值)。其特点是:
- ✅ 快速计算:适合大数据量校验
- ❌ 已被破解:易发生哈希碰撞(不同数据生成相同哈希)
- ❌ 无密钥依赖:无法验证数据来源真实性
/** * 生成签名 * @param map * @return */ public static String getSignToken(Map map) { String result = ""; try { List infoIds = new ArrayList(map.entrySet()); // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序) Collections.sort(infoIds, new Comparator() { public int compare(Map.Entry o1, Map.Entry o2) { return (o1.getKey()).toString().compareTo(o2.getKey()); } }); // 构造签名键值对的格式 StringBuilder sb = new StringBuilder(); for (Map.Entry item : infoIds) { if (item.getKey() != null || item.getKey() != "") { String key = item.getKey(); String val = item.getValue(); if (!(val == "" || val == null)) { sb.append(key + "=" + val + "&"); } } } //密钥 result = sb.toString()+"key=xxxx"; System.out.println(result); Log.d("getPayUrl", "payUrlBean getSignToken1: "+result); //进行MD5加密 result = md5(result); // result = getMD5Value(result); } catch (Exception e) { return null; } return result; }
加密流程:
- 拿到所有参数的Map
- 然后根据Map的key进行 ASCII 码从小到大排序(字典序)
- 排序后,将map的key和value,使用=作为键值对,然后多个字段之间使用&连接在一起。
- 拼接上密钥。map.toString+=key=xxxxx
- 然后进行md5加密,然后将数据返回出去。
- 最后,返回出去加密的值,放到sign键值对里面。
1.1、发送方职责
-
生成 MD5 哈希值
- 对原始数据计算 MD5 哈希值(如文件、消息等)。
-
发送数据包
- 将 原始数据 + MD5 哈希值 一起发送给接收方。
// Java示例:发送方生成MD5 public class Md5Sender { public static String generateMd5(String data) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] hashBytes = md.digest(data.getBytes()); return bytesToHex(hashBytes); // 转换为十六进制字符串 } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } }
1.2、接收方职责
-
重新计算 MD5 哈希值
- 对接收到的原始数据重新计算 MD5。
-
验证哈希一致性
- 对比接收到的哈希值与本地计算的哈希值是否一致。
// Java示例:接收方验证MD5 public class Md5Receiver { public static boolean verify(String data, String receivedHash) { String calculatedHash = Md5Sender.generateMd5(data); return calculatedHash.equals(receivedHash); } }
二、HMAC-SHA256
HMAC-SHA256 是一种对称加密的签名方案,其核心特征是:
✅ 发送方和接收方必须共享同一个密钥
✅ 密钥用于生成和验证消息的哈希值
✅ 密钥的保密性直接决定系统安全性
/** * 生成API请求签名(HMAC-SHA256算法) * @param kvMap 按ASCII顺序排序的参数键值对 * @param apiKey 商户API密钥 * @return 全大写的签名字符串 */ public static String generateSign(SortedMap kvMap, String apiKey) { // 阶段1:构建基础签名字符串 StringBuilder sb = new StringBuilder(); boolean isFirst = true; for (String key : kvMap.keySet()) { String value = kvMap.get(key); // 过滤规则: // 1. 空值参数不参与签名 // 2. 签名参数本身(sign)不参与签名 // 3. 严格区分参数名大小写 if (value != null && !value.trim().isEmpty() && !"sign".equals(key)) { if (!isFirst) { sb.append("&"); // 参数分隔符 } sb.append(key).append("=").append(value); isFirst = false; } } String stringA = sb.toString(); System.out.println("[DEBUG] 基础参数字符串: " + stringA); // 阶段2:拼接API密钥 String stringSignTemp = stringA + "&key=" + apiKey; // 标准格式结尾 System.out.println("[DEBUG] 待加密字符串: " + stringSignTemp); // 阶段3:HMAC-SHA256加密 String encodedString = encode(stringSignTemp, apiKey); System.out.println("[DEBUG] 原始签名: " + encodedString); // 最终处理:统一转为大写 return encodedString.toUpperCase(); } /** * HMAC-SHA256加密实现 * @param stringSignTemp 待加密字符串 * @param apiKey 加密密钥 * @return 十六进制格式的哈希值 */ private static String encode(String stringSignTemp, String apiKey) { String encodedString = null; try { // 1. 转换API密钥为加密规范 SecretKeySpec sks = new SecretKeySpec( apiKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256" ); // 2. 初始化MAC加密器 Mac mac = Mac.getInstance("HmacSHA256"); mac.init(sks); // 3. 执行加密并转换字节数组为十六进制 byte[] encodedBytes = mac.doFinal( stringSignTemp.getBytes(StandardCharsets.UTF_8) ); encodedString = byte2hex(encodedBytes); } catch (InvalidKeyException | NoSuchAlgorithmException e) { System.err.println("加密失败: " + e.getMessage()); } return encodedString; } /** 字节数组转十六进制字符串 */ private static String byte2hex(byte[] bytes) { StringBuilder hexString = new StringBuilder(); for (byte b : bytes) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } return hexString.toString(); }
2.1 代码执行流程解析
阶段 操作 技术要点 1 参数过滤与排序 过滤空值参数和sign字段,按SortedMap的ASCII顺序拼接键值对 2 构建待加密字符串 固定格式拼接API密钥(&key=xxx),确保密钥参与签名 3 HMAC-SHA256加密 使用API密钥作为HMAC密钥,确保签名与密钥强关联 4 十六进制编码 将二进制哈希值转换为可读字符串 5 统一大写输出 消除大小写差异,符合多数API接口规范 2.2 通信双方职责
发送方(客户端)
操作 密钥用途 生成 HMAC 签名 使用共享密钥对原始消息计算哈希值,生成签名(HMAC-SHA256(key, message)) 发送数据包 将原始消息 + HMAC 签名一起发送(如:{data: "...", sign: "xxxx"}) 接收方(服务端)
操作 密钥用途 重新计算 HMAC 使用相同密钥对收到的消息计算哈希值(HMAC-SHA256(key, received_message)) 验证签名 比较接收到的签名与自己计算的哈希值是否一致 处理结果 一致 → 数据可信;不一致 → 数据可能被篡改或密钥错误 2.3 MAC-SHA256 vs MD5 对比
特性 HMAC-SHA256 MD5 算法类型 带密钥的哈希消息认证码 普通哈希函数 输出长度 256位(32字节) 128位(16字节) 安全性 抗碰撞性强,目前无已知漏洞 已被证实存在碰撞漏洞 密钥依赖 必须使用密钥生成签名 无需密钥,仅依赖输入数据 适用场景 API签名、金融交易等安全要求高的领域 简单校验、非敏感场景(已不建议使用) 计算性能 较慢(设计目的为安全性优先) 较快 标准化 FIPS 198-1/NIST标准 RFC 1321(已过时) 三、RSA
需要公钥和私钥。
(图片来源网络,侵删)在非对称加密体系中,公钥和私钥的使用场景有明确的区分:
-
公钥(Public Key):可公开分享,用于加密数据或验证签名。
(图片来源网络,侵删) -
私钥(Private Key):必须严格保密,用于解密数据或生成签名。
3.1 下面,我们看看签名
/** * 签名 直接调用 * @param map * @return */ public static String signature(Map map){ String asciiSort = getAsciiSort(map); Log.d(TAG, "signature: "+asciiSort); return signater(privateKey, asciiSort); } public static String getAsciiSort(Map map) { List infoIds = new ArrayList(map.entrySet()); // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序) Collections.sort(infoIds, new Comparator() { public int compare(Map.Entry o1, Map.Entry o2) { return ((String) o1.getKey()).compareToIgnoreCase((String) o2.getKey()); } }); StringBuilder sb = new StringBuilder(); for (Map.Entry infoId : infoIds) { System.out.println("key -->"+infoId.getKey()+",value--->"+infoId.getValue());; sb.append(infoId.getValue()); } return sb.toString(); } public static String publicKey="xxxxx"; public static String privateKey="xxxx"; /** * 签名 * * @param privateKey * 私钥 * @param plain_text * 明文 * @return */ public static String signater(String privateKey, String plain_text) { byte[] signed = null; try { Signature Sign = Signature.getInstance("SHA256WithRSA"); PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( Base64.decode(privateKey.getBytes(), Base64.NO_WRAP)); KeyFactory keyf = KeyFactory.getInstance("RSA"); PrivateKey priKey = keyf.generatePrivate(priPKCS8); Sign.initSign(priKey); Sign.update(plain_text.getBytes("UTF-8")); signed = Sign.sign(); System.out.println("SHA256withRSA签名后-----》" + Base64.encodeToString(signed, Base64.NO_WRAP)); } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { e.printStackTrace(); } catch (InvalidKeySpecException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return Base64.encodeToString(signed, Base64.NO_WRAP); }
逻辑流程:
- 首先,我们会准备好支付的一些参数,存进Map里面
- 然后signature方法,这个方法里面调用了getAsciiSort方法,这个方法主要是将传入参数按照字段名的 ASCII 码从小到大排序(字典序)然后再进行拼接。
- 然后使用自己的私钥对数据进行加密(生成签名),然后作为参数,发送给接收方。
- 接收方收到以后,使用公钥对签名解密,如果不成功,那么就不处理,如果成功,用自己的私钥解密数据。
3.2、发送方(加密方)
职责与操作
-
获取接收方公钥
- 通过可信渠道(如数字证书、HTTPS握手)获取对方公钥。
-
加密数据
- 使用接收方的公钥加密敏感数据,确保只有接收方可解密。
-
生成签名(可选)
- 如需身份验证,使用自己的私钥对数据生成签名。
所需材料
材料 用途 接收方的公钥 加密数据,确保只有接收方能解密 发送方的私钥(可选) 生成数字签名,证明数据来源(需配合签名算法如SHA256withRSA) 3.3、接收方(解密方)
职责与操作
-
解密数据
- 使用自己的私钥解密收到的加密数据。
-
验证签名(可选)
- 使用发送方的公钥验证签名,确认数据完整性和来源真实性。
-
管理密钥
- 确保私钥安全存储(如HSM硬件模块),定期轮换密钥。
所需材料
材料 用途 接收方的私钥 解密发送方用公钥加密的数据 发送方的公钥(可选) 验证发送方签名(需发送方同时提供签名) 3.4 与 HMAC-SHA256 的关键对比
特性 SHA256withRSA HMAC-SHA256 算法类型 非对称加密(公钥/私钥) 对称加密(共享密钥) 密钥管理 公钥可公开分发,私钥严格保密 双方必须共享同一密钥 性能 较慢(RSA 加密计算复杂) 较快(适合高并发场景) 安全性 依赖 RSA 密钥长度(建议 2048 位以上) 依赖密钥保密性和哈希强度 典型应用 数字证书、SSL/TLS、支付网关 API 签名、JWT 令牌、内部服务通信 抗量子计算 弱(RSA 易被量子计算破解) 中(需升级到 HMAC-SHA3 等抗量子算法) 四、其他
不过,有些公司不用加密,而是使用一个特定key、mid。。。
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。