当前位置: 首页 > 知识库问答 >
问题:

验证使用OpenSSL和BearSSL创建的签名

韦望
2023-03-14

我正在尝试验证使用BearSSL在嵌入式设备上使用OpenSSL创建的ECDSA签名。

首先,我使用OpenSSL创建了一个私钥并提取了公钥:

$ openssl ecparam -name secp256r1 -genkey -noout -out private.pem
$ openssl ec -in private.pem -pubout -out public.pem

然后我提取了原始公钥:

$ openssl ec -noout -text -inform PEM -in public.pem -pubin
read EC key
Public-Key: (256 bit)
pub:
    04:28:4b:54:a4:d4:92:6c:82:2d:da:8a:e1:be:4b:
    49:61:5d:91:2b:2d:f5:f2:66:f8:9b:d1:be:cb:fb:
    db:fc:4f:68:cf:52:68:55:36:53:0f:8e:8d:69:3f:
    40:3a:06:62:ad:5b:5a:66:e6:1d:31:c6:13:08:f3:
    4f:94:7b:59:7a

我有一个text.txt,它只包含hello world,并使用以下命令对此进行签名:

$ cat text.txt
hello world
$ openssl dgst -sha256 -sign private.pem text.txt > signature

现在,它包含ASN1格式的签名,长度如预期的那样为72个字节:

$ hexdump signature
0000000 4530 2002 ac54 51af 8ac0 cee8 dc74 4120
0000010 105c b65d a085 06c5 8e9f 1527 12f5 8e50
0000020 9d19 9b30 2102 a900 d2a5 343e 3a10 0bdd
0000030 e0a8 82f8 de2a 4f2d 51bf a775 bc42 2d2e
0000040 19c0 874f d85e 004b

现在到嵌入部分。我首先包括数据、签名和公钥:

uint8_t text[] = "hello world\n";
size_t textlen = 12;

uint8_t signature[] = {
  0x45, 0x30, 0x20, 0x02, 0xac, 0x54, 0x51, 0xaf, 0x8a, 0xc0, 0xce, 0xe8, 0xdc, 0x74, 0x41, 0x20,
  0x10, 0x5c, 0xb6, 0x5d, 0xa0, 0x85, 0x06, 0xc5, 0x8e, 0x9f, 0x15, 0x27, 0x12, 0xf5, 0x8e, 0x50,
  0x9d, 0x19, 0x9b, 0x30, 0x21, 0x02, 0xa9, 0x00, 0xd2, 0xa5, 0x34, 0x3e, 0x3a, 0x10, 0x0b, 0xdd,
  0xe0, 0xa8, 0x82, 0xf8, 0xde, 0x2a, 0x4f, 0x2d, 0x51, 0xbf, 0xa7, 0x75, 0xbc, 0x42, 0x2d, 0x2e,
  0x19, 0xc0, 0x87, 0x4f, 0xd8, 0x5e, 0x00, 0x4b };

static const uint8_t public_bytes[] = {
  0x04, 0x28, 0x4b, 0x54, 0xa4, 0xd4, 0x92, 0x6c, 0x82, 0x2d, 0xda, 0x8a, 0xe1, 0xbe, 0x4b,
  0x49, 0x61, 0x5d, 0x91, 0x2b, 0x2d, 0xf5, 0xf2, 0x66, 0xf8, 0x9b, 0xd1, 0xbe, 0xcb, 0xfb,
  0xdb, 0xfc, 0x4f, 0x68, 0xcf, 0x52, 0x68, 0x55, 0x36, 0x53, 0x0f, 0x8e, 0x8d, 0x69, 0x3f,
  0x40, 0x3a, 0x06, 0x62, 0xad, 0x5b, 0x5a, 0x66, 0xe6, 0x1d, 0x31, 0xc6, 0x13, 0x08, 0xf3,
  0x4f, 0x94, 0x7b, 0x59, 0x7a };

static const br_ec_public_key public_key = {
  .curve = BR_EC_secp256r1,
  .q = (void *)public_bytes,
  .qlen = sizeof(public_bytes)
};

此外,出于偏执,我比较了text.txt和我的字符串的md5和,然后再进行进一步的快速检查:

$ md5sum text.txt
6f5902ac237024bdd0c176cb93063dc4  text.txt
uint8_t sum[br_md5_SIZE];
br_md5_context md5ctx;
br_md5_init(&md5ctx);
br_md5_update(&md5ctx, text, textlen);
br_md5_out(&md5ctx, sum); // sum is the same as md5sum command output

我之前告诉OpenSSL使用< code>sha256来散列使用ECDSA的签名过程的有效负载,所以我现在在BearSSL中做同样的事情,并尝试使用< code>secp256r1来验证签名:

br_sha256_context sha256ctx;
br_sha256_init(&sha256ctx);
br_sha256_update(&sha256ctx, text, textlen);
br_sha256_out(&sha256ctx, hash);

uint32_t result = br_ecdsa_i15_vrfy_asn1(&br_ec_prime_i15, hash, sizeof(hash), &public_key, signature, sizeof(signature));

我的期望将是验证工作,因为我给它相同的哈希,哈希函数,曲线,相应的公钥和签名。然而,这是行不通的。我可能遗漏了一些显而易见的东西,但却无法解决。

共有1个答案

锺离刚洁
2023-03-14

签名文件内容显示为

$ hexdump signature
0000000 4530 2002 ac54 51af 8ac0 cee8 dc74 4120
...

显示为16位值。

C程序中的签名定义为8位值的数组

uint8_t signature[] = {
  0x45, 0x30, 0x20, 0x02, 0xac, 0x54, 0x51, 0xaf, 0x8a, 0xc0, 0xce, 0xe8, 0xdc, 0x74, 0x41, 0x20,
...
};

根据字节顺序,这可能正确,也可能不正确。< code>4530对应的是< code>45、< code>30还是< code>30、< code>45?

对于小端字节顺序,十六进制转储

4530 2002 ...

将对应于(*)

uint8_t signature[] = {
  0x30, 0x45, 0x02, 0x20, ...
};

我建议将十六进制转储显示为8位值,例如通过使用

od -t x1 signature

如果需要,在C代码中修复数组初始化。

根据dave_thompson_085的评论,正确的字节顺序是0x30、0x45,因此建议的修复(*)就是解决方案。

256位组上的ECDSA签名肯定从构造的第一个标记=序列(始终为0x30)开始,然后是主体长度,通常为68到70(0x44到0x46)

 类似资料:
  • 我尝试制作一个Perl-Script来验证SMIME消息"手动"。我真的试了很多,但没有用。 大多数情况下,验证会放置“签名长于密钥”或只是给出错误的返回。 如果我在控制台用OpenSSL做这件事,它就像一个魅力。 它生成并验证msg.txt 我把它改短了。 现在我尝试用非常简单的Perl来展示它。我简化了MIME处理,只使用msg.txt中的内联值。 我跳过了剩下的。它相当于msg.txt中的签

  • 我想验证C中的签名,这是我在Java中签名的随机签名。 以下是我用于签名的Java代码: 现在我想用C验证签名,我需要C代码等于以下Java代码: 到目前为止,我所尝试的: 此方法返回0,但我确信随机是用正确的键签名的,并且该方法需要返回1...我想我的验证用的C代码有问题。也许你们中的一个知道如何做对。 --解决--

  • 我正在为嵌入式Linux设备添加HTTPS支持。我尝试通过以下步骤生成自签名证书: 这是可行的,但我得到一些错误,例如,谷歌Chrome:

  • 我正在编写一些代码,试图对一些数据进行签名。在将openssl生成的私钥转换为Java密钥库之后,我将Java签名类与SHA256withRSA一起使用。我试图确认openssl中Java类返回的签名,但由于某些原因,我无法让openssl进行验证。我最终需要在iOS Swift 3中实现这个签名验证,但在找到库之前,我想尝试根据openssl标准检查Java签名。 例如,我从我们的登录服务器得到

  • 我想创建一个签名并使用openssl验证它。我想有我的签名的十六进制输出。 这是我的密码 我得到这个错误: 如果我在创建签名的过程中删除了-hex,它就可以工作了。

  • 我正在尝试使用加密来验证open-ssl签名,这是open-ssl部分: 现在在我的C代码中: 但是我总是收到验证失败的消息