RSA數字簽名方案的C語言實現(帶測試)

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;是事件…