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

在ethers中验证Android KeyStore生成的签名失败问题排查

问题分析与解决建议

你遇到的核心问题大概率是椭圆曲线不匹配、消息哈希算法不一致,或者签名参数处理有误,以下是具体排查点和解决步骤:


1. 椭圆曲线不匹配(最可能的原因)

你从Android KeyStore生成的密钥对是基于P256(secp256r1)曲线,但ethers.js默认使用的是以太坊生态的secp256k1曲线。直接用ethers的默认方法验证P256签名,必然会得到错误的公钥。

解决办法:

在ethers中明确指定使用secp256r1曲线处理签名和公钥:

const { recoverPublicKey } = require("@ethersproject/signing-key");
const { secp256r1 } = require("@ethersproject/curve");

// 传入消息哈希、签名对象,指定secp256r1曲线
const recoveredPubKey = recoverPublicKey(
  messageHash, // 注意:这里必须是SHA-256哈希,不是原始消息
  { r: "0x...", s: "0x...", v: 0 }, // 签名的r、s、recovery id(0或1)
  secp256r1
);

2. 消息哈希算法不一致

Android KeyStore中使用SHA256withECDSA签名时,会先对原始消息计算SHA-256哈希,再对哈希值签名。但ethers的verifyMessage或recoverPublicKey默认会对原始消息计算Keccak256哈希,这会导致哈希值不匹配,进而恢复出错误的公钥。

解决办法:

  • 如果你在Android端签名的是原始消息,那么在ethers中需要先手动计算消息的SHA-256哈希,再传入恢复方法:
const { sha256 } = require("@ethersproject/sha256");
const message = "your original message";
const messageHash = sha256(Buffer.from(message)); // 计算SHA-256哈希
  • 确保Android端的签名算法和ethers端的哈希算法一致,不要混用SHA-256和Keccak256。

3. DER签名的r/s提取是否正确

DER签名的标准结构是:0x30 <总长度> 0x02 <r的长度> <r值> 0x02 <s的长度> <s值>,提取r和s时需要注意:

  • P256的r和s都是256位(32字节),如果DER中的r/s前面带有0x00前缀(用于避免最高位为1时被解析为负数),必须去掉该前缀;
  • 如果r/s的长度不足32字节,需要在前面补0x00补全到32字节,而不是后面。

举个例子:如果DER中r的字节是0x02 21 00 1a 2b ...(共21字节),则去掉开头的0x00,得到32字节的r;如果r是0x02 20 1a 2b ...(20字节),则在前面补12个0x00到32字节。


4. Recovery ID(v值)的验证

P256曲线的recovery id是0或1,对应公钥的两个可能存在的点。你可以尝试分别传入v=0和v=1,看哪个能恢复出与你提取的公钥一致的值。


验证步骤示例

  1. 确认你的公钥格式是0x04 + 32字节x坐标 + 32字节y坐标(你当前的提取方式是正确的);
  2. 用SHA-256计算原始消息的哈希;
  3. 正确提取32字节的r和s;
  4. 用secp256r1曲线,分别尝试v=0和v=1恢复公钥,与你的公钥对比。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 08:15:31