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

如何让OpenSSL生成的EC签名可被Subtle Crypto API验证?

问题

我有一个包含由SubtleCrypto.sign()的ECDSA算法和SHA512摘要生成的EC签名的小型JSON文件。现在我想把手动生成签名的流程自动化,且必须基于nginx:alpine基础镜像。我已经安装了OpenSSL,但发现SubtleCrypto.verify()需要IEEE P1363格式的签名,而OpenSSL生成的是ASN.1格式。有没有办法让OpenSSL生成的签名能在浏览器中正常验证?

注意:我在浏览器中创建了EC密钥对,使用SubtleCrypto.sign()生成签名时验证正常。随后我将私钥以PKCS#8格式导出为PEM文件,内容如下:

-----BEGIN EC PRIVATE KEY-----
<Base64 encoded content here...>
-----END EC PRIVATE KEY-----

我使用以下命令为仅包含{}的data.json生成Base64格式的签名:

$ openssl dgst -sha512 -sign private.pem data.json | base64
MIGHAkEZ0YthoqLqCW1ll0MvPEYdhoz+p1zxQnLt0sl0rSvD8eI0BdAeQUqS1fUlNi8O39ClI6OI
JDZJqJ3OkTFkMyqzaAJCAT8koJnhqv2PUHla7EWV/qVIBb9LtPovQODl0+CsBQlkGO+TKkX3X57+
rpOZMqYv1tIOAz1m5ry0sOo0hGSe4c8X

之后我通过ASN.1解码网站获取r和s的十进制值,并参考Stack Overflow的回答转换为十六进制值:

r = 346169932049245619871744113024266741326899713498883047336224784039276978051811648336988371154157537871201508197563500632048282301939214838670217488915673960
s = 4279009059525041370739088323750483074176965727856497966083564113228214038964554024207556176396942898795827323835166902701178318351093672293528073206493204247

hex_val = 19D18B61A2A2EA096D6597432F3C461D868CFEA75CF14272EDD2C974AD2BC3F1E23405D01E414A92D5F525362F0EDFD0A523A388243649A89DCE913164332AB368013F24A099E1AAFD8F50795AEC4595FEA54805BF4BB4FA2F40E0E5D3E0AC05096418EF932A45F75F9EFEAE939932A62FD6D20E033D66E6BCB4B0EA3484649EE1CF17

得到的Base64签名为:

GdGLYaKi6gltZZdDLzxGHYaM/qdc8UJy7dLJdK0rw/HiNAXQHkFKktX1JTYvDt/QpSOjiCQ2SaidzpExZDMqs2gBPySgmeGq/Y9QeVrsRZX+pUgFv0u0+i9A4OXT4KwFCWQY75MqRfdfnv6uk5kypi/W0g4DPWbmvLSw6jSEZJ7hzxc=

但该签名在浏览器中验证失败。


解决方案

无需手动解码ASN.1格式签名,OpenSSL本身支持直接生成或转换出符合要求的IEEE P1363格式签名,具体步骤如下:

方法1:直接生成IEEE P1363格式签名

使用pkeyutl命令搭配-raw参数,可直接生成r和s拼接的P1363二进制签名,再转Base64即可:

# 生成二进制P1363格式签名,再转Base64
openssl pkeyutl -sign -in data.json -inkey private.pem -digest sha512 -raw | base64

方法2:将已有ASN.1签名转换为P1363格式

如果已经生成了ASN.1格式的签名,可通过以下步骤转换:

  1. 将Base64签名解码为二进制文件:
echo "MIGHAkEZ0YthoqLqCW1ll0MvPEYdhoz+p1zxQnLt0sl0rSvD8eI0BdAeQUqS1fUlNi8O39ClI6OIJDZJqJ3OkTFkMyqzaAJCAT8koJnhqv2PUHla7EWV/qVIBb9LtPovQODl0+CsBQlkGO+TKkX3X57+rpOZMqYv1tIOAz1m5ry0sOo0hGSe4c8X" | base64 -d > signature.asn1
  1. 用asn1parse提取r和s的偏移量与长度:
openssl asn1parse -in signature.asn1

输出会显示r和s的offset(偏移位置)和length(长度),示例如下:

0:d=0  hl=2 l= 130 cons: SEQUENCE          
    2:d=1  hl=2 l=  64 prim: INTEGER           :19D18B61A2A2EA096D6597432F3C461D868CFEA75CF14272EDD2C974AD2BC3F1E23405D01E414A92D5F525362F0EDFD0A523A388243649A89DCE913164332AB368
   68:d=1  hl=2 l=  64 prim: INTEGER           :013F24A099E1AAFD8F50795AEC4595FEA54805BF4BB4FA2F40E0E5D3E0AC05096418EF932A45F75F9EFEAE939932A62FD6D20E033D66E6BCB4B0EA3484649EE1CF17
  1. 提取r和s的二进制数据并拼接成P1363格式,再转Base64:
# 提取r(对应offset=2,length=64)
xxd -s 2 -l 64 -p signature.asn1 | xxd -r -p > r.bin
# 提取s(对应offset=68,length=64)
xxd -s 68 -l 64 -p signature.asn1 | xxd -r -p > s.bin
# 拼接r和s得到P1363格式签名,再转Base64
cat r.bin s.bin | base64

关键注意事项

  • 确保r和s的长度与使用的椭圆曲线匹配:比如secp521r1(P-521)曲线的r/s各占66字节,secp256r1(P-256)各占32字节;如果提取的r/s长度不足,需在前面补0字节保证长度符合要求。
  • 在nginx:alpine镜像中,OpenSSL是默认预装的,xxd可通过apk add xxd快速安装,无需额外复杂依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 09:35:22