OpenSSL ECDSA签名比预期的长

OpenSSL ECDSA签名比预期的长,openssl,cryptography,pki,Openssl,Cryptography,Pki,我正在尝试生成“原始”的、未编码的ECDSA签名,以便与加密芯片一起使用。目标是在主机pc上签名,然后将其发送到芯片进行验证。然而,我遇到了一个小问题。我的理解是ECDSA签名应该是64字节(对于secp256v1)。而且,当我使用芯片生成签名时,它的长度确实是64字节。然而,当我使用openssl时,签名的长度是71字节。签名的开头似乎是某种前缀,但我找不到任何关于这是什么的数据 以下是我尝试做每件事的方式: 生成密钥: openssl ecparam -genkey -name secp25

我正在尝试生成“原始”的、未编码的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进行签名

openssldgst-sha256-binary-signprivkeyv1.pem-out test\u sig\u meth2 test.txt
问题:这里是xxd-p-C256测试信号方法1的输出:
3045022000A86FB146D5F8F6C15B962640BC2D1D928F5E0F96A5924E4DB2853EC8B66FB00210085431613D0A235DB1ADABC90CC1062A2246A78941972E298423F4B3D081B48C8

以及xxd-p-C256测试信号方法2的输出:
30450220693732CD53D9F2BA3DEAE213D74CDF69A00E7325A10DDC6A4445FF2B33F95E6022100B6D2561E3AFB10F95247ED05F0C59620DC0913F0D798B4148E05C411B6384E

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


问题是:如何使用openssl生成64字节原始(未编码,无头)ECDSA签名,我可以使用此方案

出于效率考虑,大多数芯片将只输出
r
s
作为字节数组或八位字节字符串,其中每个
r
s
与八位字节中的字段大小(即键大小)相同。另一种方法是将
r
s
作为数字序列输出,因为最后,这就是
r
s
的含义。使用ASN.1,这将成为一个整数值序列

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

我不会进入OS2IP,它将字节数组转换为整数。请注意,如果您以BER形式对其进行编码,那么整数不应该用零字节填充。因此,仍然需要一些诡计


因此,尽管签名改变了形式,签名仍然有效;您可以简单地在一个表单和另一个表单之间进行转换,签名仍然可以验证-显然,只要您使用正确的库来执行作业。

我发现两个命令的输出都是der编码的。通过使用asn1parse-inform-der,我能够找到组成签名的整数(r和s)。请问这与C有什么关系?Stack Overflow是一个用于编程和开发问题的网站。这个问题似乎离题了,因为它与编程或开发无关。请参见帮助中心中的。也许或者是一个更好的提问的地方。我能够在test_sig_meth2中使用openssl asn1parse-inform der-in转换密钥的格式,它输出r和s值。谢谢@F41lizer可以,但不要忘记转换为八位字节字符串。这通常只是一个串联…直到一个较短的r或s值将咬你。我不知道你说的转换为八位字节字符串是什么意思。这基本上只是对字符串进行十六进制编码,还是我遗漏了什么?八位字节字符串只是一个字节数组。八位字节=字节,字符串=数组。十六进制编码是为了使这些字节具有可读性。不要将字节的表示与字节本身混淆。因此,如果你有一条256位的曲线,你将编码为32字节,如果你有一条521(不是打印错误),那么你将通过左填充大端编码的数字编码为66字节。“因此,尽管签名改变了形式,签名仍然有效;您只需在一种形式和另一种形式之间进行转换,签名仍将验证(只要您使用正确的库来执行此任务)相关,请参阅。它在ASN.1/DER(OpenSSL、Java和其他几种)和P1363格式(Crypto++和其他几种)之间进行转换。Net是一个奇怪的人;它使用XML编码格式。