一、准备文件与密钥
创建示例文件
echo "hello world" > 1.txt
生成 2048 位 RSA 私钥
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
从私钥导出公钥
openssl rsa -pubout -in private_key.pem -out public_key.pem
保护私钥权限
chmod 600 private_key.pem
二、模拟签名与验签
生成签名(发送方操作)
openssl dgst -sha256 -sign private_key.pem -out 1.sig 1.txt
验证签名(接收方操作)
openssl dgst -sha256 -verify public_key.pem -signature 1.sig 1.txt
成功输出:
Verified OK
篡改测试(可选)
修改 1.txt 后再验签:
echo "hello world!" > 1.txt
openssl dgst -sha256 -verify public_key.pem -signature 1.sig 1.txt
输出:
Verification Failure
三、模拟加密与解密
使用公钥加密(发送方操作)
openssl pkeyutl -encrypt -pubin -inkey public_key.pem -in 1.txt -out 1.enc
使用私钥解密(接收方操作)
openssl pkeyutl -decrypt -inkey private_key.pem -in 1.enc -out 1.dec
查看解密结果
cat 1.dec 输出:hello world
四, 代码实现
1,基于mebelts3.4.1的实现
(1)结构体定义
mebdlts 3.4.1 安全启动中的签名头结构体定义如下:
#pragma pack(push, 1)
typedef struct {
uint32_t magic; /* +0x00: 魔数 'BBEM' */
uint32_t version; /* +0x04: 版本 0x00030401 */
uint32_t image_len; /* +0x08: 被保护数据总长 */
uint32_t flags; /* +0x0C: 标志位 */
uint8_t sha256_hash[32]; /* +0x10: 原始数据的哈希 */
uint8_t rsa_signature[256]; /* +0x30: RSA-2048 签名 */
uint8_t reserved[220]; /* 填充 */
} meb_sign_header_t;
#pragma pack(pop)
签名长度为 256 字节 (RSA-2048 输出固定长度)。哈希为 SHA-256,输出 32 字节。
2,签正文名与验签函数实现
2.1 初始化上下文(RSA-2048 + SHA-256 + PKCS#1 v2.1)
#include "mbedtls/rsa.h"
#include "mbedtls/sha256.h"
#define RSA_KEY_SIZE 2048
#define RSA_SIG_LEN (RSA_KEY_SIZE / 8) /* 256 字节 */
mbedtls_rsa_context rsa;
mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
MBEDTLS_RSA_PKCS_V21 指定使用 PKCS#1 v2.1 填充方案(PSS)。
2.2 签名函数
int meb_sign_data(const unsigned char *data, size_t data_len,
const mbedtls_rsa_context *ctx,
unsigned char *signature, size_t *sig_len)
{
unsigned char hash[32]; /* SHA-256 输出 32 字节 */
int ret;
/* 1. 计算 SHA-256 摘要 */
ret = mbedtls_sha256_ret(data, data_len, hash, 0);
if (ret != 0) return ret;
/* 2. 使用私钥签名 */
ret = mbedtls_rsa_pkcs1_sign(ctx,
NULL, /* 随机数生成函数(PSS 需要,可传 NULL 使用内部默认) */
NULL, /* 随机数上下文 */
MBEDTLS_RSA_PRIVATE,
MBEDTLS_MD_SHA256,
32, /* hashlen = SHA-256 输出长度 */
hash,
signature);
if (ret != 0) return ret;
*sig_len = RSA_SIG_LEN; /* 固定 256 字节 */
return 0;
}
2.3 验签函数
int meb_verify_signature(const unsigned char *data, size_t data_len,
const mbedtls_rsa_context *ctx,
const unsigned char *signature)
{
unsigned char hash[32];
int ret;
/* 1. 计算 SHA-256 摘要 */
ret = mbedtls_sha256_ret(data, data_len, hash, 0);
if (ret != 0) return ret;
/* 2. 使用公钥验签 */
ret = mbedtls_rsa_pkcs1_verify(ctx,
NULL,
NULL,
MBEDTLS_RSA_PUBLIC,
MBEDTLS_MD_SHA256,
32,
hash,
signature);
/* 返回 0 表示验签成功;非 0 表示失败 */
return ret;
}
五,异常场景
举一个例子,如果密钥更新了,私钥没更新,签名失败的例子
SECSEC Calculated Hash : 9e41f2a88c33b1d1... (当前数据计算出的哈希)
SECSEC RSA Verify : FAILED
SECSEC Error: Signature mismatch!
SECSEC Security Alert: Halting system.
可以在初始化后使用mbedtls_pk_check_pair显式验证密钥对的匹配性,mbedtls_pk_check_pair函数是 Mbed TLS 提供的密钥配对检查函数,用于在签名或验签操作前,主动确认公钥与私钥是否匹配,从而避免因密钥更新不同步导致的验签失败。
#include "mbedtls/pk.h"
#include "mbedtls/ctr_drbg.h"
mbedtls_pk_context pub_key;
mbedtls_pk_context prv_key;
mbedtls_ctr_drbg_context ctr_drbg;
int ret;
/* 初始化并加载密钥...(略) */
/* 检查公钥与私钥是否配对 */
ret = mbedtls_pk_check_pair(&pub_key, &prv_key,
mbedtls_ctr_drbg_random, &ctr_drbg);
if (ret != 0) {
/* 密钥不匹配,记录错误并终止签名流程 */
mbedtls_printf("Key pair mismatch! ret = -0x%04X\n", -ret);
/* 此时应阻止使用该密钥进行签名 */
return -1;
}
/* 检查通过,可以安全地执行签名 */
ret = mbedtls_pk_sign(&prv_key, MBEDTLS_MD_SHA256,
hash, 32, signature, &sig_len,
mbedtls_ctr_drbg_random, &ctr_drbg);