openssl 模拟签名验签(加密解密)详细分析

一、准备文件与密钥

创建示例文件

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);
相关推荐
en.en..2 小时前
ARM 汇编 B / BL 核心区别
汇编·arm开发
程序员JerrySUN3 小时前
Jetson Edge AI 实战05:Secure Boot 到底在保护什么?PKC、SBK、Fuse 与可信启动链一次讲清【视频讲解】
arm开发·人工智能·安全·计算机视觉·目标跟踪·音视频
老当益壮梁奶奶7 小时前
驱动学习(二):从零开始:驱动工程搭建与字符设备驱动框架详解(基于IMX6ULL)
c语言·arm开发·驱动开发·嵌入式硬件·学习
竣达技术9 小时前
机房运维:UPS 如何实现跨网段采集监控数据
运维·arm开发
女神下凡1 天前
嵌入式系统 vs 嵌入式文件系统
arm开发·嵌入式硬件·设计规范
女神下凡1 天前
芯参谋(55):LED 驱动 · 系统设计指南
arm开发·单片机·嵌入式硬件·硬件工程·设计规范
Awh-1 天前
ARM 裸机开发 DAY10 学习笔记
arm开发·笔记·学习
番茄灭世神1 天前
PN学堂GD32教程第14篇——Arm单片机启动流程
arm开发·单片机·嵌入式硬件
女神下凡1 天前
芯参谋(49):eMCP_软件设计规范
arm开发·嵌入式硬件·设计规范