移植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
相关产品推荐
相关产品推荐

