OpenSSL ECDSA 签名比预期长

f41*_*zer 6 openssl cryptography pki

我正在尝试生成用于加密芯片的“原始”、未编码的 ECDSA 签名。目标是在主机 pc 上签署某些内容,然后将其发送到芯片进行验证。但是,我遇到了一个小问题。我的理解是 ECDSA 签名应该是 64 个字节(对于 secp256v1)。而且,当我使用芯片生成签名时,它的长度确实是 64 个字节。但是,当我使用 openssl 时,签名的长度为 71 个字节。签名的开头似乎是某种前缀,但我找不到关于它是什么的任何数据。

这是我尝试做所有事情的方式:

生成密钥:

openssl ecparam -genkey -name secp256r1 -noout -out privkeyv1.pem
Run Code Online (Sandbox Code Playgroud)

生成要签名的“消息”:

echo -n "Hello World" > test.txt
Run Code Online (Sandbox Code Playgroud)

我尝试了两种签署消息的方法。两者都会导致相同的意外输出。

第一种方法 - 生成测试文件的 sha256 哈希值,然后对其进行签名:

sha256sum test.txt | cut -f 1 -d " " > hash
Run Code Online (Sandbox Code Playgroud)

使用 pkutil 签名

openssl pkeyutl -sign -in hash -inkey privkeyv1.pem -out test_sig_meth1
Run Code Online (Sandbox Code Playgroud)

方法二:使用 openssl dgst 签名

openssl dgst -sha256 -binary -sign privkeyv1.pem -out test_sig_meth2 test.txt 问题:这是输出xxd -p -c 256 test_sig_meth13045022000a86fb146d5f8f6c15b962640bc2d1d928f5e0f96a5924e4db2853ec8b66fb002210085431613d0a235db1adabc090cc1062a246a78941972e298423f4b3d081b48c8

和输出xxd -p -c 256 test_sig_meth230450220693732cd53d9f2ba3deae213d74cdf69a00e7325a10ddc6a4445ff2b33f95e62022100b6d2561e3afba10f95247ed05f0c59620dc0913f0d798b4148e05c4116b6384e

如您所见,这两种方法在开头都会生成一些看起来像头字节的字节(30450220可能更长),但我不确定它们的用途或如何删除它们。作为参考,这里是加密芯片上生成的相同方法的签名。如果删除末尾的空字节填充,则为 64 字节。 4677AD09F2AF49D7445ED5D6AC7253ADC863EC6D5DB6D3CFBF9C6D3E221D0A7BA2561942524F46B590AEE749D827FBF80A961E884E3A7D85EC75FE48ADBC0BD00000000000000000000000

问题:我如何使用 openssl 生成一个 64 字节的原始(未编码,没有标头)ECDSA 签名,我可以在这个方案中使用?

Maa*_*wes 2

出于效率原因,大多数芯片只会将 和r作为s字节数组或八位字节字符串输出,其中每个rs与八位字节中的字段大小(即密钥大小)相同。另一种方法是将rands作为数字序列输出,因为最终,这就是rands的内容。使用 ASN.1,这将成为 INTEGER 值的序列。

要从这样的序列进行转换,您可以首先使用 BER 解析器进行 BER 解码以检索整数。然后实现 I2OSP 算法(整数到八位字节流原语),该算法需要值和密钥大小(以字节/八位字节为单位)作为参数。该数字应该是大整数形式,但这很好,因为 ASN.1 BER 编码的整数也是大整数。基本上,如果数字太小,则必须将填充保留零字节。然后连接数字。

我不会讨论将字节数组转换为整数的 OS2IP。请注意,如果您以 BER 形式对其进行编码,那么整数不应该零字节填充。所以仍然需要一些技巧。

因此,虽然签名的形式发生了变化,但签名仍然有效;您可以简单地在一种形式和另一种形式之间进行转换,并且签名仍然可以验证 - 显然,只要您使用正确的库来完成这项工作。