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

移植ECC ECDSA验证库至mbedTLS时签名验证失败问题排查

ECDSA签名验证在mbedTLS中返回-20450(无效签名)的解决方案

问题背景

将自定义ECC ECDSA验证库移植到mbedTLS时,遇到签名验证失败问题:

  • 测试用的secp256r1密钥对、数据SHA256哈希、私钥签名均由PyCryptodome生成,Python脚本内及自定义库验证均正常
  • Windows+GCC环境下,mbedTLS代码使用未压缩公钥调用mbedtls_ecdsa_read_signature,返回错误码**-20450(无效签名)**

问题根源

mbedTLS的mbedtls_ecdsa_read_signature接口默认要求签名为DER编码格式,但PyCryptodome默认生成的是P1363格式(即r和s字段直接拼接的二进制数据),格式不匹配导致验证失败。此外,公钥的加载方式也需与生成时的格式(压缩/未压缩)对应。

解决方案

1. 调整Python签名生成脚本(支持DER/P1363双格式)

修改PyCryptodome代码,同时生成两种格式的签名,方便适配mbedTLS的不同接口:

from Crypto.PublicKey import ECC
from Crypto.Signature import DSS
from Crypto.Hash import SHA256
import binascii

# 生成/加载secp256r1密钥对
private_key = ECC.generate(curve='P-256')
public_key = private_key.public_key()

# 待签名数据
data = b"test_ecdsa_signature"
hash_obj = SHA256.new(data)

# 生成P1363格式签名(r+s拼接)
signer = DSS.new(private_key, 'fips-186-3')
signature_p1363 = signer.sign(hash_obj)

# 生成DER格式签名
signature_der = private_key.sign(hash_obj, 'der')

# 输出结果
print(f"未压缩公钥: {binascii.hexlify(public_key.export_key(format='raw')).decode()}")
print(f"SHA256哈希: {binascii.hexlify(hash_obj.digest()).decode()}")
print(f"P1363签名: {binascii.hexlify(signature_p1363).decode()}")
print(f"DER签名: {binascii.hexlify(signature_der).decode()}")

2. mbedTLS验证代码(适配不同签名/公钥格式)

情况1:验证DER格式签名(使用mbedtls_ecdsa_read_signature)

#include "mbedtls/ecdsa.h"
#include "mbedtls/sha256.h"
#include <stdio.h>
#include <string.h>

#define SECP256R1_PUB_KEY_UNCOMPRESSED_HEX "你的未压缩公钥十六进制字符串"
#define DER_SIGNATURE_HEX "你的DER格式签名十六进制字符串"
#define DATA "test_ecdsa_signature"

int main() {
    mbedtls_ecdsa_context ecdsa;
    mbedtls_sha256_context sha256;
    unsigned char pub_key_raw[65];
    unsigned char sig_der[72];
    unsigned char hash[32];
    int ret;

    // 初始化上下文
    mbedtls_ecdsa_init(&ecdsa);
    mbedtls_sha256_init(&sha256);

    // 十六进制转二进制:公钥、签名
    ret = mbedtls_hex_to_bin(SECP256R1_PUB_KEY_UNCOMPRESSED_HEX, strlen(SECP256R1_PUB_KEY_UNCOMPRESSED_HEX), pub_key_raw, sizeof(pub_key_raw));
    if(ret != 0) { printf("公钥转码失败: %d\n", ret); goto exit; }

    ret = mbedtls_hex_to_bin(DER_SIGNATURE_HEX, strlen(DER_SIGNATURE_HEX), sig_der, sizeof(sig_der));
    if(ret != 0) { printf("签名转码失败: %d\n", ret); goto exit; }

    // 计算数据SHA256哈希
    mbedtls_sha256_starts_ret(&sha256, 0);
    mbedtls_sha256_update_ret(&sha256, (unsigned char*)DATA, strlen(DATA));
    mbedtls_sha256_finish_ret(&sha256, hash);

    // 加载未压缩公钥
    ret = mbedtls_ecdsa_from_public(&ecdsa, pub_key_raw, sizeof(pub_key_raw));
    if(ret != 0) { printf("加载公钥失败: %d\n", ret); goto exit; }

    // 验证DER格式签名
    ret = mbedtls_ecdsa_read_signature(&ecdsa, hash, sizeof(hash), sig_der, sizeof(sig_der));
    if(ret == 0) {
        printf("DER签名验证通过\n");
    } else {
        printf("DER签名验证失败: %d\n", ret);
    }

exit:
    mbedtls_ecdsa_free(&ecdsa);
    mbedtls_sha256_free(&sha256);
    return ret;
}

情况2:验证P1363格式签名(手动拆分r/s后调用mbedtls_ecdsa_verify)

如果需要直接验证P1363格式的签名,需手动拆分r和s字段,再调用底层验证接口:

#include "mbedtls/ecdsa.h"
#include "mbedtls/sha256.h"
#include <stdio.h>
#include <string.h>

#define SECP256R1_PUB_KEY_UNCOMPRESSED_HEX "你的未压缩公钥十六进制字符串"
#define P1363_SIGNATURE_HEX "你的P1363格式签名十六进制字符串"
#define DATA "test_ecdsa_signature"

int main() {
    mbedtls_ecdsa_context ecdsa;
    mbedtls_sha256_context sha256;
    unsigned char pub_key_raw[65];
    unsigned char sig_p1363[64];
    unsigned char hash[32];
    mbedtls_mpi r, s;
    int ret;

    // 初始化上下文
    mbedtls_ecdsa_init(&ecdsa);
    mbedtls_sha256_init(&sha256);
    mbedtls_mpi_init(&r);
    mbedtls_mpi_init(&s);

    // 十六进制转二进制:公钥、P1363签名
    ret = mbedtls_hex_to_bin(SECP256R1_PUB_KEY_UNCOMPRESSED_HEX, strlen(SECP256R1_PUB_KEY_UNCOMPRESSED_HEX), pub_key_raw, sizeof(pub_key_raw));
    if(ret != 0) { printf("公钥转码失败: %d\n", ret); goto exit; }

    ret = mbedtls_hex_to_bin(P1363_SIGNATURE_HEX, strlen(P1363_SIGNATURE_HEX), sig_p1363, sizeof(sig_p1363));
    if(ret != 0) { printf("签名转码失败: %d\n", ret); goto exit; }

    // 计算数据SHA256哈希
    mbedtls_sha256_starts_ret(&sha256, 0);
    mbedtls_sha256_update_ret(&sha256, (unsigned char*)DATA, strlen(DATA));
    mbedtls_sha256_finish_ret(&sha256, hash);

    // 加载未压缩公钥
    ret = mbedtls_ecdsa_from_public(&ecdsa, pub_key_raw, sizeof(pub_key_raw));
    if(ret != 0) { printf("加载公钥失败: %d\n", ret); goto exit; }

    // 拆分P1363签名为r和s(各32字节)
    ret = mbedtls_mpi_read_binary(&r, sig_p1363, 32);
    if(ret != 0) { printf("读取r值失败: %d\n", ret); goto exit; }
    ret = mbedtls_mpi_read_binary(&s, sig_p1363 + 32, 32);
    if(ret != 0) { printf("读取s值失败: %d\n", ret); goto exit; }

    // 验证签名
    ret = mbedtls_ecdsa_verify(&ecdsa, hash, sizeof(hash), &r, &s);
    if(ret == 0) {
        printf("P1363签名验证通过\n");
    } else {
        printf("P1363签名验证失败: %d\n", ret);
    }

exit:
    mbedtls_mpi_free(&r);
    mbedtls_mpi_free(&s);
    mbedtls_ecdsa_free(&ecdsa);
    mbedtls_sha256_free(&sha256);
    return ret;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 00:43:12