我正在尝试生成" raw",未编码的ECDSA签名,以便与加密芯片一起使用。目标是在主机PC上签名,然后将其发送到芯片进行验证。但是,我遇到了一个小问题。我的理解是ECDSA签名应该是64字节(对于secp256v1)。而且,当我使用芯片生成签名时,它确实是64字节长。但是,当我使用openssl时,签名长度为71个字节。签名的开头似乎是某种前缀,但我找不到任何关于这是什么的数据。
以下是我尝试做的所有事情:
生成密钥:
openssl ecparam -genkey -name secp256r1 -noout -out privkeyv1.pem
生成"消息"签字:
echo -n "Hello World" > test.txt
我尝试了两种签名消息的方法。两者都会产生相同的意外输出。
第一种方法 - 生成测试文件的sha256哈希值,然后对其进行签名:
sha256sum test.txt | cut -f 1 -d " " > hash
使用pkutil签名
openssl pkeyutl -sign -in hash -inkey privkeyv1.pem -out test_sig_meth1
方法2:使用openssl dgst进行签名
openssl dgst -sha256 -binary -sign privkeyv1.pem -out test_sig_meth2 test.txt
问题:这是xxd -p -c 256 test_sig_meth1
的输出:
3045022000a86fb146d5f8f6c15b962640bc2d1d928f5e0f96a5924e4db2853ec8b66fb002210085431613d0a235db1adabc090cc1062a246a78941972e298423f4b3d081b48c8
xxd -p -c 256 test_sig_meth2
的输出:
30450220693732cd53d9f2ba3deae213d74cdf69a00e7325a10ddc6a4445ff2b33f95e62022100b6d2561e3afba10f95247ed05f0c59620dc0913f0d798b4148e05c4116b6384e
正如您所看到的,这两种方法都会在开头生成一些看起来像标题字节的字节(30450220
,可能更长),但我不确定它们是什么或如何删除它们。作为参考,这里是在加密芯片上生成的相同方法的签名。如果在末尾删除空字节填充,则它是64字节。 4677AD09F2AF49D7445ED5D6AC7253ADC863EC6D5DB6D3CFBF9C6D3E221D0A7BA2561942524F46B590AEE749D827FBF80A961E884E3A7D85EC75FE48ADBC0BD00000000000000000000000
问题:如何使用openssl生成64字节原始(未编码,没有标头)ECDSA签名我可以使用此方案?
答案 0 :(得分:1)
出于效率原因,大多数芯片只会输出r
和s
作为字节数组或八位字节字符串,其中每个r
和s
都是相同的八位字节的字段大小(即密钥大小)。另一种方法是将r
和s
输出为一系列数字,因为最后,r
和s
就是这样。使用ASN.1,这将成为INTEGER值的SEQUENCE。
要从这样的序列转换,您可以首先使用BER解析器进行BER解码以检索整数。然后实现一个I2OSP算法(整数到八位字节流原语),它需要以字节/八位字节为单位的值和密钥大小作为参数。数字应该是大整数形式,但这很好,因为ASN.1 BER编码整数也是大整数。基本上,如果数字太小,你必须留下零字节的填充。然后你连接数字。
我不会进入将字节数组转换为整数的OS2IP。请注意,如果以BER格式对其进行编码,那么整数应不用零字节填充。所以仍然需要一些技巧。
因此,虽然签名变更形式,但签名仍然有效;您只需在一个表单和另一个表单之间进行转换,签名仍然可以验证 - 只要您使用正确的库来完成工作,很明显。