Unity C#端验证本地Android IAP市场响应签名的技术咨询
嘿,你的理解大体是对的,但有个关键细节得澄清下——服务端并不是直接用私钥“加密”哈希值,而是用私钥对数据的哈希值做签名操作(这是非对称加密的特定应用,和普通的加密解密逻辑方向不同)。我们客户端要做的也不是“解密签名”,而是用公钥验证这个签名是否真的来自持有对应私钥的服务端,同时确保返回的数据没有被篡改。
下面我会把完整的验证逻辑、Unity C#端的实现步骤和关键注意事项整理清楚,帮你搞定这个问题:
签名验证的核心逻辑梳理
先把整个流程拆解明白,避免混淆:
- 服务端生成要返回给你的响应数据(比如订单详情、支付结果)
- 服务端用指定的哈希算法(比如SHA-256)计算这份数据的哈希值
- 服务端用自己的私钥对这个哈希值执行签名操作,生成签名串(通常会用Base64编码后返回给你)
- 你在Unity端拿到三个关键内容:原始响应数据、Base64编码的签名串、服务端提供的公钥
- 你用和服务端完全相同的哈希算法,计算拿到的原始响应数据的哈希值
- 用公钥验证:签名串是否能匹配你计算出的哈希值——如果匹配,说明数据没被篡改,且确实是服务端发出的
Unity C#端实现步骤(附代码示例)
假设你从Android端拿到的内容是:
- 原始响应字符串
rawResponse(比如JSON格式的订单数据) - Base64编码的签名串
signatureBase64 - 服务端提供的PEM格式公钥(开头带
-----BEGIN PUBLIC KEY-----的字符串)
步骤1:把PEM格式公钥转成DER格式
Unity的RSA加密类需要DER格式的公钥,所以先清理并转换PEM格式:
private static byte[] ConvertPemToDer(string pemPublicKey) { // 移除PEM的头尾标记和多余换行符 var cleanedPublicKey = pemPublicKey .Replace("-----BEGIN PUBLIC KEY-----", "") .Replace("-----END PUBLIC KEY-----", "") .Replace("\n", "") .Replace("\r", ""); // Base64解码得到DER格式的字节数组 return Convert.FromBase64String(cleanedPublicKey); }
步骤2:初始化RSA对象并导入公钥
private static RSACryptoServiceProvider GetRsaProvider(byte[] derPublicKey) { var rsa = new RSACryptoServiceProvider(); // 导入DER格式的公钥 rsa.ImportSubjectPublicKeyInfo(derPublicKey, out _); return rsa; }
步骤3:计算原始数据的哈希值
注意要和服务端用的哈希算法完全一致,这里以SHA-256为例:
private static byte[] ComputeDataHash(string rawData) { using (var sha256 = SHA256.Create()) { // 编码格式要和服务端一致,通常用UTF-8 var dataBytes = Encoding.UTF8.GetBytes(rawData); return sha256.ComputeHash(dataBytes); } }
步骤4:执行签名验证
public static bool VerifySignature(string rawResponse, string signatureBase64, string pemPublicKey) { try { var derPublicKey = ConvertPemToDer(pemPublicKey); using (var rsa = GetRsaProvider(derPublicKey)) { var signatureBytes = Convert.FromBase64String(signatureBase64); var dataHash = ComputeDataHash(rawResponse); // 这里的签名算法要和服务端完全匹配,比如SHA256withRSA return rsa.VerifyHash(dataHash, CryptoConfig.MapNameToOID("SHA256"), signatureBytes); } } catch (Exception ex) { Debug.LogError($"签名验证失败:{ex.Message}"); return false; } }
关键注意事项(踩坑必看)
- 算法完全一致:哈希算法(SHA-1/SHA-256等)、签名算法(SHA256withRSA等)必须和服务端用的一模一样,否则验证100%失败
- 编码一致:计算哈希时的字符串编码(UTF-8/GBK等)要和服务端保持一致
- 公钥正确性:务必确认你用的是对应环境(测试/生产)的公钥,不能混用
- 数据完整性:你计算哈希的原始数据必须和服务端签名时用的原始数据完全一致——比如Android端返回时有没有偷偷修改过响应字符串的格式(加空格、换行)?这点一定要和Android端的同事确认
如果还是验证失败,可以从这几个方向排查:
- 打印你计算的哈希值,和服务端计算的哈希值对比,看是否一致
- 检查签名串的Base64解码是否正确
- 用在线工具把PEM转成DER,对比你代码转换后的字节数组是否一致
内容的提问来源于stack exchange,提问作者High
相关产品推荐
相关产品推荐

