BouncyCastle生成的SHA512-ECDSA密钥在jsrsasign中不匹配如何解决
问题定位与修复方案
你遇到的验签失败问题核心是密钥格式不匹配和签名编码格式不统一两个原因,具体修复逻辑如下:
核心问题说明
1. 私钥格式错误
Kotlin侧输出的privateKey是完整的PKCS#8编码的EC私钥结构的Base64值,但jsrsasign的sig.init方法传入的d参数要求的是EC私钥原始32字节大数的编码值,不是整个PKCS#8结构,直接传全量PKCS#8的Base64肯定会导致签名生成错误。
2. 公钥格式错误
Kotlin侧截取输出的公钥是标准X962格式的原始公钥(04开头+32字节x+32字节y,共65字节)的Base64值,但jsrsasign的xy参数要求传入HEX格式的x+y拼接值,直接传Base64格式的公钥无法被正确解析。
3. 签名编码格式不统一
ECDSA签名有两种通用编码格式:
- DER编码格式:BouncyCastle默认使用该格式
- P1363原始格式:r+s直接拼接的格式,是jsrsasign的默认输出格式
两边格式不匹配会直接导致验签失败。
修复后的JS代码
Kotlin侧的密钥生成逻辑无需调整,仅需要修改JS侧的密钥解析和签名初始化逻辑即可:
const message = "Testing"; // 替换为服务端生成的对应密钥 const serverPrivateKeyBase64 = "MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg6xrOGWvvTTh5EfxhDco0xqppyFrSRbFaKUKbZutlynugCgYIKoZIzj0DAQehRANCAAQ6EhELaQWv3z7tBgJXYMGspw93Ni+LvvmY3f0MSBtu84ldBZi3boz+OV3hiiyO+mBx+jCg4s2TDF+nw0Vi3lS7"; const serverPublicKeyBase64 = "BDoSEQtpBa/fPu0GAldgwaynD3c2L4u++Zjd/QxIG27ziV0FmLdujP45XeGKLI76YHH6MKDizZMMX6fDRWLeVLs="; // 签名流程 const sig = new KJUR.crypto.Signature({ alg: "SHA512withECDSA", sigval: "der" // 指定输出DER格式签名,和BouncyCastle对齐 }); // 直接解析标准PKCS8私钥,无需手动传d和curve参数 const privateKey = KEYUTIL.getKeyFromPlainPrivatePKCS8(serverPrivateKeyBase64); sig.init(privateKey); sig.updateString(message); const signature = sig.sign(); // 验签流程 const sigVerification = new KJUR.crypto.Signature({ alg: "SHA512withECDSA", sigval: "der" }); // 把服务端Base64格式的公钥转成HEX,再传给xy参数 const publicKeyHex = KJUR.lang.String.b64tohex(serverPublicKeyBase64); sigVerification.init({ xy: publicKeyHex, curve: "prime256v1" }); sigVerification.updateString(message); const isValid = sigVerification.verify(signature); if(isValid) { console.log("Signature is valid, keys are matching"); } else { throw "The signature is invalid. Please make sure the keys match." }
如果你的服务端配置为接收P1363原始格式的签名,把两处sigval: "der"改为sigval: "raw"即可。
内容的提问来源于stack exchange,提问作者bearbob
相关产品推荐
相关产品推荐

