You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中SHA256withECDSA签名验证失败问题排查

问题分析与解决

首先,我一眼就看到你代码里的致命坑——你用sig.toString()打印签名的时候,完全误解了字节数组的toString()行为!

字节数组直接调用toString(),返回的根本不是签名的实际内容,而是类似[B@6d6f6e48这种对象标识字符串(类名+哈希码)。如果你的实际业务中,是把这个toString()的结果当作签名保存或者传递,然后验证时用这个字符串的字节去校验,那必然会返回false,因为你验证的根本不是原来的签名数据!

正确的签名存储/传递方式

要把字节数组形式的签名转换成可存储的字符串,得用Base64或者十六进制编码。以Android为例,用Base64处理是最方便的:

生成签名并正确编码

val sigBytes = Signature.getInstance("SHA256withECDSA").run {
    initSign(kp.private)
    // 明确指定UTF-8编码,避免不同环境下的编码差异
    update("foo".toByteArray(Charsets.UTF_8))
    sign()
}
// 把签名转成Base64字符串,这才是可以安全存储/传递的内容
val sigStr = Base64.encodeToString(sigBytes, Base64.DEFAULT)
Log.d(tag, "sig: $sigStr")

验证签名

// 把Base64字符串转回字节数组
val sigBytes = Base64.decode(sigStr, Base64.DEFAULT)
val verifier = Signature.getInstance("SHA256withECDSA")
verifier.initVerify(kp.public)
// 同样用UTF-8编码,和生成时保持一致
verifier.update("foo".toByteArray(Charsets.UTF_8))
val isValid = verifier.verify(sigBytes)
Log.d(tag, isValid.toString()) // 这下应该输出true了

其他可能的排查点

如果你的代码真的完全像你贴的那样,直接用同一个sig字节数组验证,那唯一的可能就是你的密钥对kp不是同一组!比如你在绑定点击事件的时候,每次都重新生成了新的kp,而不是复用同一个实例。你可以检查下kp的生成逻辑,确保签名和验证时用的是同一对公私钥。

另外补充个小细节:最好明确指定字符串转字节数组的编码(比如Charsets.UTF_8),虽然Android默认是UTF-8,但万一环境编码被修改,也会导致哈希值不一致,验证失败。

内容的提问来源于stack exchange,提问作者user2297550

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:05:47