RSA 算法的 C语言实现通常比较复杂,但已经有许多密码算法库实现了 RSA 算法,例如OpenSSL、Libgcrypt​ 和 Botan ​等。我们可以在这些库的基础上进行配置或移植,从而快速实现密码算法。但这些库主要面向大量设备进行优化,如通用计算机和服务器。本文需要在嵌入式设备上实现密码算法,因此选择了实现开销更小的密码算法库 BearSSL。BearSSL包含RSA的两种加密方案,分别是PKCS#1 v1.5方案和RSAES-OAEP方案,PKCS#1 v1.5方案是早期方案,存在安全漏洞,RSAES-OAEP使用OAEP填充技术,安全性高。BearSSL还包含两种RSA签名方案,分别是RSASSA-PKCS1-v1_5方案和RSASSA-PSS方案,RSASSA-PKCS1-v1_5是早期方案,有安全漏洞,RSASSA-PSS是目前推荐方案,使用PSS填充技术,引入随机盐值,安全性高。另外,BearSSL还包含还包括一些分组密码加密和杂凑算法相关内容。本文仅进行测试演示,从BearSSL中提取出了容易实现的RSASSA-PKCS1-v1_5方案,虽然该方案存在漏洞,但因此实现简便,资源占用更小,但可以用于安全要求不太高的小型设备,或作为教学使用。我们删减了除RSASSA-PKCS1-v1_5方案外的大量冗余内容,使工程大幅简化,下载地址为:https://download.csdn.net/download/weixin_43261410/91277142,读者可以免费下载。

一、BearSSL 密码算法库

BearSSL是一个轻量级、高性能的SSL/TLS加密库,专为嵌入式系统和资源受限环境设计。与其他通用加密库(如OpenSSL)不同,BearSSL的核心目标是极致的精简与高效,同时不牺牲安全性。它采用模块化设计,允许开发者仅编译所需的加密算法,从而大幅减少代码体积(可小至50KB以下)和内存占用(栈内存通常低于3KB)。这种设计使其非常适合运行在微控制器(如ARM Cortex-M)、物联网设备(IoT)或实时操作系统中。此外,BearSSL严格遵循恒定时间编程原则,所有算法均避免数据依赖的分支和内存访问,有效抵御侧信道攻击(如时序攻击)。这种对安全性和资源效率的平衡,使其成为嵌入式安全通信的首选库之一。

BearSSL在技术实现上有多项创新,尤其是其分层加密算法支持和大整数运算优化。例如,它提供多种大整数实现(i15、i31、i62),分别针对不同硬件平台优化:i15适用于无硬件乘法指令的CPU(如Cortex-M0),i31利用32位CPU的64位乘法加速运算,而i62则针对64位架构(如x86-64)进一步优化模幂运算。此外,BearSSL采用纯C语言编写,无需汇编代码,确保了跨平台兼容性。其API设计也极具特色,例如通过“控制位”(ctl参数)实现恒定时间的条件操作,避免分支预测漏洞。这些设计使其在保持高度可移植性的同时,仍能实现接近硬件的性能。

BearSSL在安全性上毫不妥协,全面支持现代TLS协议(如TLS 1.2和1.3),并实现了前向保密(PFS)和抗降级攻击的机制。其密码套件默认禁用弱算法(如RC4、SHA-1),且支持证书链验证和OCSP装订(OCSP Stapling)。与其他库不同,BearSSL的证书解析器极度精简,仅处理必要的X.509字段,既减少了代码体积,又降低了潜在漏洞风险。此外,它通过了多项密码学标准的验证(如FIPS 140-2的算法测试),并提供了针对侧信道攻击的防护措施(如盲签名、恒定时间模幂运算)。这些特性使其在工业控制、医疗设备等对安全性要求严苛的场景中备受青睐。

二、仅提取i31位的PKCS1签名与验签方法

i31实现是BearSSL中平衡性能和代码大小的优化选择,使用31位无符号整数作为基本运算单元。这种设计充分利用了32位CPU的寄存器宽度,同时避免了符号位的潜在问题。在示例工程中,我们通过精心挑选的源文件实现了最小化的RSA PKCS#1功能,仅包含i31相关运算和必要的辅助函数。

签名过程遵循PKCS#1 v1.5规范,首先使用br_rsa_pkcs1_sig_pad对哈希值进行编码,添加ASN.1算法标识符和填充字节。示例中使用BR_HASH_OID_SHA256常量指定SHA-256算法,这比硬编码OID更安全可靠。填充后的消息随后通过br_rsa_i31_private函数进行实际签名运算,该函数采用CRT优化显著提升性能。

验签过程则相反,先用br_rsa_i31_public解密签名,再用br_rsa_pkcs1_sig_unpad验证填充格式并提取哈希值。值得注意的是,示例中严格检查了所有函数的返回值,这是安全编程的关键实践。验签最后一步将提取的哈希值与原始哈希比较,确保内容的完整性和真实性。

工程中的params.h文件包含了完整的RSA-1024密钥对,采用中国剩余定理格式存储。私钥包含p、q、dp、dq和iq等CRT参数,这些参数预先计算并存储,可显著提升签名速度。公钥部分则包含标准的模数n和公开指数e(通常为65537)。这种密钥表示方式与BearSSL的br_rsa_private_key和br_rsa_public_key结构体完美匹配,便于直接使用。

三、整体工程架构分析

工程采用清晰的模块化结构,通过CMake构建系统管理。顶层CMakeLists.txt明确定义了所有源文件和头文件的依赖关系,确保构建过程的可重复性。项目结构分为include和src两个主要目录,前者存放BearSSL头文件和应用特定的params.h,后者包含精选的i31实现源文件。

核心功能集中在main.c中,该文件实现了完整的签名验签工作流。签名函数sign_data初始化私钥结构并调用br_rsa_i31_pkcs1_sign;验签函数verify_signature类似地配置公钥后调用br_rsa_i31_pkcs1_vrfy。这种封装使主逻辑清晰可读,同时便于复用。密钥材料与业务逻辑分离的设计增强了安全性,方便后续密钥轮换。

构建系统仅包含实现RSA PKCS#1签名验签所需的最小源文件集,如i31_*.c基础运算和rsa_i31_*.c专门实现。这种精确的组件选择体现了BearSSL的模块化优势,最终生成的可执行文件体积显著小于包含完整库的情况。settings.c提供必要的运行时配置,而ccopy.c等辅助函数则确保安全的内存操作。

测试方面,工程使用固定的测试向量进行基础验证。main函数中硬编码的SHA-256哈希值作为输入,通过打印签名前后数据提供了简单的视觉验证手段。虽然这不能替代完整的测试套件,但对于演示和基础验证已经足够。实际项目中可扩展为自动化单元测试,覆盖更多边界情况和错误路径。

四、测试函数实现

测试实现采用了经典的测试模式 - 先执行签名,再验证签名,最后比较结果。main函数中首先打印原始哈希值建立基线,然后调用sign_data生成签名。签名失败会立即终止程序并提示错误,成功则输出128字节的签名数据,每32字节换行以便阅读。

验签阶段将签名作为输入,调用verify_signature函数。该函数不仅检查签名本身的合法性,还通过memcmp确保解出的哈希与原始哈希完全一致。这种双重验证保证了整个流程的正确性。测试输出包含明确的成功/失败指示和详细的十六进制数据,极大便利了调试过程。

测试使用的固定哈希值对应字符串"BearSSL RSA Test"的SHA-256摘要,这提供了确定性的测试基准。实际应用中,哈希值通常来自对实际消息的摘要计算。示例中签名缓冲区(signature)大小固定为128字节(1024位),与密钥长度匹配;哈希输出缓冲区(verify_hash_out)则为32字节,符合SHA-256的输出要求。

错误处理方面,代码检查了所有关键操作的返回值,包括签名和验签函数的输出。这种防御性编程风格对于安全关键代码至关重要。虽然示例中没有实现复杂的错误恢复机制,但简单的立即返回已能防止错误传播。扩展测试可添加无效签名、错误密钥等负面测试案例,进一步验证代码的健壮性。

最后,我们将参数保存在了params.h文件中,这是原工程没有的。密钥参数生成和SHA256的哈希计算可采用工程scripts目录下的两个脚本实现,注意需要在python中通过命令pip install cryptography安装库后运行。

#include <stdio.h>
#include <string.h>
#include "bearssl_rsa.h"
#include "params.h"unsigned char hash_value[] = {0x54, 0xba, 0x1f, 0xdc, 0xe5, 0xa8, 0x9e, 0x0d,0x3e, 0xee, 0x6e, 0x4c, 0x58, 0x74, 0x97, 0x83,0x3b, 0xc3, 0x8c, 0x35, 0x86, 0xff, 0x02, 0x05,0x7d, 0xd6, 0x45, 0x1f, 0xd2, 0xd6, 0xb6, 0x40
};int sign_data(unsigned char *signature) {br_rsa_private_key sk;sk.n_bitlen = 1024;sk.p = RSA_P;sk.plen = sizeof(RSA_P);sk.q = RSA_Q;sk.qlen = sizeof(RSA_P);sk.dp = RSA_DP;sk.dplen = sizeof(RSA_DP);sk.dq = RSA_DQ;sk.dqlen = sizeof(RSA_DQ);sk.iq = RSA_IQ;sk.iqlen = sizeof(RSA_IQ);uint32_t sign_result = br_rsa_i31_pkcs1_sign(BR_HASH_OID_SHA256,hash_value,sizeof(hash_value),&sk,signature);return sign_result != 0;
}int verify_signature(const unsigned char *signature, size_t sig_len, unsigned char *hash_out) {br_rsa_public_key pk;pk.n = RSA_N;pk.nlen = sizeof(RSA_N);pk.e = RSA_E;pk.elen = sizeof(RSA_E);uint32_t verify_result = br_rsa_i31_pkcs1_vrfy(signature,sig_len,BR_HASH_OID_SHA256,sizeof(hash_value),&pk,hash_out);if (!verify_result) {return 0;}return memcmp(hash_out, hash_value, sizeof(hash_value)) == 0;
}int main() {unsigned char signature[128] = {0};unsigned char verify_hash_out[32] = {0};printf("The original hash is: \n");for (int i = 0; i < 32; i++) {printf("%02x", hash_value[i]);}printf("\n");if (!sign_data(signature)) {printf("Failed sign!\n");return -1;}printf("Success sign, the signature is: \n");for (int i = 0; i < 128; i++) {printf("%02x", signature[i]);if((i+1)%32 ==0)printf("\n");}if (!verify_signature(signature, 128, verify_hash_out)) {printf("Failed verify!\n");return -1;}printf("Success verify, the hash out is: \n");for (int i = 0; i < 32; i++) {printf("%02x", verify_hash_out[i]);}printf("\n");return 0;
}

五、总结

本文详细介绍了基于BearSSL轻量级加密库实现RSA-PKCS#1数字签名与验签的全过程。BearSSL以其模块化设计和嵌入式友好特性,成为资源受限环境下安全通信的理想选择。文章重点剖析了i31位优化实现的RSA算法,该实现通过31位整数运算单元在32位CPU上达到性能与代码大小的最佳平衡。工程采用精简化架构,仅集成必要的i31运算模块,通过CMake构建系统实现高效管理。测试方案采用确定性测试向量,完整演示了从私钥签名到公钥验签的闭环流程,包含严格的返回值检查和内存比较验证。整个实现充分展现BearSSL的安全设计哲学:恒定时间算法防御旁路攻击、显式内存管理避免动态分配、最小化API降低误用风险。该方案特别适合物联网设备等嵌入式场景,为开发者提供了兼具安全性和效率的轻量级密码学实践范例,其模块化思想也可扩展至其他加密算法实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/87731.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/87731.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/87731.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

创客匠人视角:知识变现与创始人 IP 打造的破局之道

当知识付费从流量红利期进入精耕细作阶段&#xff0c;为何专业能力强的内容创作者反而难以变现&#xff1f;创客匠人通过 1500 案例陪跑发现&#xff1a;缺乏 IP 思维的知识输出如同雾中航行&#xff0c;而创始人 IP 打造正是连接知识价值与商业变现的核心桥梁。一、定位重构&…

结构分析设计软件 SCIA Engineer 25.0 x64

详情 Nemetschek SCIA Engineer是一家从事多项目编程、分析和软件设计的公司。该软件具有广泛的不同功能。该软件可用于以简单的方式设计建筑物、工业工厂和桥梁。 Nemetschek SCIA Engineer软件的特点和功能&#xff1a; BIM模型人 使用网格和故事 3D风 自由负载 互联网…

怎么处理[TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark

这个错误说明 Elasticsearch 的磁盘空间严重不足&#xff0c;已触及最高级别&#xff08;flood-stage&#xff09;的水位线。作为自我保护机制&#xff0c;Elasticsearch ​自动将受影响的索引设置为只读模式 (read-only-allow-delete)​&#xff0c;从而阻止写入操作&#xff…

pytorch学习-11卷积神经网络(高级篇)

2.线性模型 3.梯度下降算法 4.反向传播(用pytorch算梯度) 5.用pytorch实现线性回归 6.logistic回归 7.处理多维特征的输入 8.加载数据集 9.多分类问题 10.卷积神经网络(基础篇) 11.卷积神经网络&#xff08;高级篇&#xff09;_哔哩哔哩_bilibili 11.1 GoogleNet Google…

ubuntu 安装QT

在 Ubuntu 系统上安装 Qt 可以通过以下步骤完成&#xff0c;以下是详细的安装指南 &#xff1a; 1. 安装前的准备工作 在开始安装 Qt 之前&#xff0c;需要确保你的 Ubuntu 系统已经更新到最新版本&#xff0c;并且安装了一些必要的依赖。 1.1 更新系统 首先&#xff0c;打…

CppCon 2018 学习:RAPID PROTOTYPING OF GRAPHICS SHADERS IN

这段内容在讲**着色器&#xff08;Shader&#xff09;**的基础概念&#xff0c;尤其是它在现代 GPU&#xff08;图形处理单元&#xff09;中的作用。以下是逐条解释与理解&#xff1a; “Depicting depth perception in 3D models or illustrations by varying levels of darkn…

Angular v20版本正式发布

过去几年对 Angular 来说很具变革性,我们推出了像 Signals 这样的反应性功能和 Zoneless 应用的强大能力。我们希望这些功能可以帮助 Angular 社区构建下一代的 Web 应用,实现快速上市和强大的性能。 我们的旅程才刚刚开始!Angular v20 是最新的发布版本,我们花费了无数个小…

Oracle如何使用序列 Oracle序列使用教程

Oracle序列&#xff08;sequence&#xff09;是一种数据库项&#xff0c;能够生成一个整数序列。通常用于填充数字类型的主键列。 Oracle序列 Oracle序列使用教程&#xff1a; 1、创建序列&#xff1a; CREATE SEQUENCE sequence_name[START WITH start_num][INCREMENT BY incr…

深入探索 Vanna:让数据库交互更智能

深入探索 Vanna&#xff1a;让数据库交互更智能 在数字化时代&#xff0c;与数据库进行高效交互是许多开发者、数据分析师和企业面临的挑战。传统的 SQL 查询编写不仅需要对数据库结构有深入的了解&#xff0c;还需要花费大量的时间和精力来调试和优化。Vanna&#xff0c;一个…

C#上位机之网口通信与协议!

文章目录前言一、网口通信概念二、使用网口通信准备三、使用步骤前言 C#上位机之网口通信与协议&#xff01; 一、网口通信概念 定义 &#xff1a;Socket 可以理解为一个通信端点&#xff0c;它提供了应用程序与网络之间的接口&#xff0c;使得应用程序能够在网络上发送和接收…

Android Studio 创建类时如何自动添加类注释

打开IDEA或AS&#xff0c;点击菜单栏File——Settings——Editor——File and Code Templates。 点击右边Tab页的Includes&#xff0c;选择File Header&#xff0c;修改类头模版&#xff0c;如图&#xff1a; 记得选中Project&#xff0c;否则默认是整个AS都会进行设置

C++11:shared_ptr的设计哲学(原理+源码):内存安全和性能的架构权衡

0.简介 在C编程世界中&#xff0c;内存管理是一把双刃剑&#xff0c;手动管理带来了极致的内存控制能力&#xff0c;但也带来了像内存泄漏&#xff0c;野指针等问题&#xff1b;自动垃圾回收虽然安全&#xff0c;但却会带来一定的性能损耗。本文将介绍C11引入shared_ptr&#…

Mysql EXPLAIN 执行计划

EXPLAIN SELECT SQl。。。。界面filtered储引擎返回的数据在经过服务器层 WHERE 条件过滤后&#xff0c;剩余数据占总行数的百分比估计值rows * filtered/100 越接近100%效率越高rowspossible_keys 可能选择的索引key最终决定选择的行partitions问了哪些分区select_type查询…

力扣刷题记录【1】146.LRU缓存

前言&#xff1a; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关键字的值&…

西门子S7-1200 PLC主流通信方法及应用

一、通信基础 1. 网络术语与设备 - 关键设备&#xff1a;交换机、路由器、网关等。 - 物理接口&#xff1a;RS-485&#xff08;支持多点通信&#xff09;、RS-232C&#xff08;点对点串行通信&#xff09;。 2. OSI参考模型 - 核心框架&#xff1a;理解协议分层&…

MySQL实现任意级子目录的主要方案以及区别

常见的实现方案及区别 1. 邻接表&#xff08;Adjacency List&#xff09; 方案描述&#xff1a; 每条记录存储一个节点的父节点ID。 表结构大致&#xff1a; id INT PRIMARY KEY, name VARCHAR(...), parent_id INT -- 指向父节点的ID&#xff0c;根节点为NULL或0优点&…

Linux网络socket套接字(完)(5)

文章目录前言一、多进程版的Tcp网络程序捕捉SIGCHLD信号让孙子进程提供服务二、多线程版的Tcp网络程序三、线程池版的Tcp网络程序四、Tcp协议通讯流程通讯流程总览三次握手的过程数据传输的过程四次挥手的过程总结前言 结束喽&#xff0c;至少这个Tcp套接字有关内容要结束了~  …

Web3 Study Log 003

Web3 Study Log 003 2025-7-5 这几天各种各样的琐事&#xff0c;处理完了&#xff0c;真的烦&#xff0c;估计能消停一段时间了… 今天终于能够坐下来好好学习&#xff0c;今天学习了chainlink的使用&#xff0c;能够获取 ETH/USD 实时价格&#xff0c;然后写了一个简单的众…

Kotlin:2.1.20 的新特性

一、概述 The Kotlin 2.1.20 release is here! Here are the main highlights: Kotlin 2.1.20发布了&#xff0c;主要亮点如下&#xff1a; K2 compiler updates: updates to the new kapt and Lombok pluginsKotlin Multiplatform: new DSL to replace Gradle’s Application …

设计模式 | 观察者模式

观察者模式&#xff08;Observer Pattern&#xff09;是行为型设计模式中的事件通知专家&#xff0c;它定义了对象间一种一对多的依赖关系&#xff0c;当一个对象状态改变时&#xff0c;所有依赖它的对象都会自动收到通知并更新。这种模式实现了发布-订阅机制&#xff0c;是事件…