C++ 通過CryptoPP計算Hash值

来源:https://www.cnblogs.com/LyShark/archive/2023/11/30/17865683.html
-Advertisement-
Play Games

Crypto++ (CryptoPP) 是一個用於密碼學和加密的 C++ 庫。它是一個開源項目,提供了大量的密碼學演算法和功能,包括對稱加密、非對稱加密、哈希函數、消息認證碼 (MAC)、數字簽名等。Crypto++ 的目標是提供高性能和可靠的密碼學工具,以滿足軟體開發中對安全性的需求。該庫包含了許多... ...


Crypto++ (CryptoPP) 是一個用於密碼學和加密的 C++ 庫。它是一個開源項目,提供了大量的密碼學演算法和功能,包括對稱加密、非對稱加密、哈希函數、消息認證碼 (MAC)、數字簽名等。Crypto++ 的目標是提供高性能和可靠的密碼學工具,以滿足軟體開發中對安全性的需求。

該庫包含了許多常見的密碼學演算法,如AES、DES、RSA、DSA、SHA等,使開發者能夠輕鬆地在他們的應用程式中實現安全性和加密功能。Crypto++ 是以面向對象的方式設計的,因此它的使用通常涉及使用類和對象來表示不同的密碼學概念和演算法。

Crypto++ 提供了許多特性,包括多平臺支持(Windows、Linux、macOS等)、容易使用的 API、高性能的實現、豐富的文檔和社區支持。在使用 Crypto++ 之前,你需要確保正確地配置和鏈接 Crypto++ 庫到你的項目中。

編譯Crypto庫

目前Crypto庫的最新版本為8.90,讀者可自行下載對應的庫源代碼,下載好以後使用Visual Studio工具打開源文件中的cryptest.sln文件。

打開以後選中調試菜單中的屬性頁面,此時將運行庫修改為多線程/MT模式,否則雖可以編譯通過但這個庫卻無法被正常使用,此處是一個坑。

此時選中解決方案,並直接點擊重新編譯庫,這個過程可能需要等待一段時間,更具設備的配置而不同讀者可在最底部看到輸出進度;

當編譯成功以後,讀者可以來到cryptopp890\Win32\Output\Release目錄下,該目錄下的則是編譯成功後的lib庫文件,可以將這3個文件全部保存在新建的lib文件夾內。

接著在cryptopp890文件夾下直接搜索所有的*.h頭文件,並放入到新建的include文件夾內,此時我們就有了最新版本的開發工具包了。

使用該庫也很容易,只需要包含Include與Lib庫文件即可,如下圖所示配置;

使用MD5演算法

MD5(Message Digest Algorithm 5)是一種常見的哈希函數,用於產生128位的散列值(通常以32位的十六進位數表示)。MD5廣泛用於檢查數據完整性、數字簽名、密碼存儲等領域。

以下是 MD5 演算法的基本概述:

  1. 輸入處理: MD5 接受任意長度的輸入,但輸出是固定長度的128位。輸入被劃分為512位的塊,每個塊包含16個32位的字。
  2. 填充: 如果輸入的位數不是512的倍數,就需要填充數據,使其長度滿足這個條件。填充是通過在消息的末尾添加一個'1'和零比特,然後添加一個表示原始消息長度的64位整數來完成的。
  3. 初始化: MD5 有四個32位的寄存器(A、B、C、D),初始化為特定的常數。這些寄存器將在處理每個消息塊時進行更新。
  4. 處理塊: 對於每個512位塊,MD5 執行64個操作輪次。每個輪次都使用一個非線性函數,一個常量和一個消息塊的子集。這些輪次通過迴圈結構連接起來。
  5. 輸出: MD5 的輸出是四個32位字的級聯,通常以32位的十六進位數表示。這四個字的順序是 A、B、C、D。

MD5 演算法的設計目標是產生一個唯一的(或極其難以相同)散列值,以便在密碼存儲、數字簽名和數據完整性檢查等場景中使用。然而,由於MD5存在一些安全性問題,特別是其易受碰撞攻擊的漏洞,現在不再被推薦用於安全性要求較高的場景。對於安全性要求較高的應用,推薦使用更強大和安全的哈希函數,如SHA-256或SHA-3。

如下這段代碼中涉及到一些特殊的類,這裡將分別介紹功能;

  • FileSource: 用於從文件中讀取數據。

  • StringSource: 用於從字元串或二進位數據中讀取數據。

  • HashFilter: 表示一個用於計算哈希的過濾器。它接受一個哈希函數作為參數,這裡是 md5

  • md5: 用於計算輸入數據的 MD5 哈希值。

  • HexEncoder: 用於將二進位數據編碼為十六進位表示。

  • StringSink(dst 或 digest): 用於將數據寫入字元串。在這裡,它將最終的哈希值以十六進位字元串的形式寫入到 dstdigest 中。

#include <Windows.h>
#include <iostream>

#include <md5.h>
#include <files.h>
#include <hex.h>

using namespace std;
using namespace CryptoPP;

#pragma comment(lib,"cryptlib.lib")

int main(int argc, char* argv[])
{
	// 定義MD5類
	MD5 md5;

	// 計算字元串MD5
	string src = "Hello World";
	string dst;

	StringSource(src, true, new HashFilter(md5, new HexEncoder(new StringSink(dst))));
	std::cout << "字元串hash = " << dst << std::endl;

	// 計算位元組數組MD5
	string digest;
	BYTE pData[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	DWORD dwDataSize = sizeof(pData);

	StringSource(pData, dwDataSize, true, new HashFilter(md5, new HexEncoder(new StringSink(digest))));
	std::cout << "數組長度 = " << dwDataSize << std::endl;
	std::cout << "數組hash = " << digest << std::endl;

	system("pause");
	return 0;
}

運行後則可分別輸出字元串與數組的MD5值,如下圖所示;

如果需要從文件中讀取則需要使用FileSource類,在計算MD5之前先將文件讀入記憶體在進行計算,如下所示;

#include <Windows.h>
#include <iostream>

#include <md5.h>
#include <files.h>
#include <hex.h>

using namespace std;
using namespace CryptoPP;

#pragma comment(lib,"cryptlib.lib")

// 計算文件MD5
string CalMD5ByFile(char *pszFileName)
{
	string value;
	MD5 md5;
	FileSource(pszFileName, true, new HashFilter(md5, new HexEncoder(new StringSink(value))));
	return value;
}

// 計算數據MD5
string CalMD5ByMemory(PBYTE pData, DWORD dwDataSize)
{
	string value;
	MD5 md5;
	StringSource(pData, dwDataSize, true, new HashFilter(md5, new HexEncoder(new StringSink(value))));
	return value;
}

int main(int argc, char* argv[])
{
	// 定義MD5類
	MD5 md5;

	// 計算文件的MD5
	string md51 = CalMD5ByFile("d://lyshark.exe");
	printf("md5 = %s\n", md51.c_str());

	// 計算文件記憶體的MD5
	HANDLE hFile2 = CreateFile("d://lyshark.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);

	// 取文件長度
	DWORD dwFileSize2 = GetFileSize(hFile2, NULL);
	BYTE *pData2 = new BYTE[dwFileSize2];

	// 讀文件到記憶體
	ReadFile(hFile2, pData2, dwFileSize2, NULL, NULL);

	// 計算MD5
	string md52 = CalMD5ByMemory(pData2, dwFileSize2);
	printf("md5 = %s\n", md52.c_str());

	system("pause");
	return 0;
}

如下圖所示,是計算後得到的文件的MD5值;

使用CRC32演算法

CRC32(Cyclic Redundancy Check,迴圈冗餘校驗)是一種廣泛用於數據校驗的錯誤檢測演算法。它基於多項式除法,在電腦領域中常用於檢測數據傳輸或存儲過程中的錯誤。

以下是CRC32演算法的基本概述:

  1. 多項式選擇: CRC32使用一個32位的二進位多項式,通常表示為一個32位的二進位數。這個多項式在CRC計算中充當除數。
  2. 數據處理: 要計算CRC32,首先需要將數據按位劃分成塊,每個塊的長度等於多項式的次數。通常,CRC32使用位元組為單位進行處理。
  3. 初始值: CRC32計算開始前,需要初始化一個32位的寄存器為一個特定的初始值,通常為全1或全0。
  4. 除法運算: 對於每個數據塊,將它與32位的寄存器中的值進行異或操作。然後,將寄存器中的值右移一位,再與多項式進行異或操作。這個過程重覆進行,直到所有數據塊都被處理完。
  5. 最終值: 在處理完所有數據塊後,寄存器中的值就是CRC32的最終校驗值。
  6. 校驗值附加: 通常,CRC32的結果會附加在原始數據的末尾,形成一個帶有校驗值的完整數據塊。

CRC32廣泛應用於文件傳輸、存儲系統、乙太網通信等領域,用於檢測數據傳輸中的錯誤。由於其簡單性和高效性,CRC32在實際應用中被廣泛採用。然而,需要註意的是,CRC32主要用於錯誤檢測而非安全性,不適用於對惡意操作的防範。在一些對安全性要求較高的場景中,其他更強大的校驗演算法可能更為合適。

crc32演算法的使用只需要包含<crc.h>頭文件,並將程式內的MD5類改為CRC32即可,其他的無任何差異,代碼如下所示;

#include <Windows.h>
#include <iostream>

#include <crc.h>
#include <files.h>
#include <hex.h>

using namespace std;
using namespace CryptoPP;

#pragma comment(lib,"cryptlib.lib")

// 計算文件CRC32
string CalCRCByFile(char *pszFileName)
{
	string value;
	CRC32 crc;
	FileSource(pszFileName, true, new HashFilter(crc, new HexEncoder(new StringSink(value))));
	return value;
}

// 計算數據CRC32
string CalCRCByMemory(PBYTE pData, DWORD dwDataSize)
{
	string value;
	CRC32 crc;
	StringSource(pData, dwDataSize, true, new HashFilter(crc, new HexEncoder(new StringSink(value))));
	return value;
}

int main(int argc, char* argv[])
{
	// 定義CRC32類
	CRC32 crc32;

	// 計算文件的MD5
	string crc = CalCRCByFile("d://lyshark.exe");
	printf("crc32 = %s\n", crc.c_str());

	// 計算文件記憶體的crc
	HANDLE hFile2 = CreateFile("d://lyshark.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);

	// 取文件長度
	DWORD dwFileSize2 = GetFileSize(hFile2, NULL);
	BYTE *pData2 = new BYTE[dwFileSize2];

	// 讀文件到記憶體
	ReadFile(hFile2, pData2, dwFileSize2, NULL, NULL);

	// 計算crc
	string crc2 = CalCRCByMemory(pData2, dwFileSize2);
	printf("crc32 = %s\n", crc2.c_str());

	system("pause");
	return 0;
}

程式運行後將會計算文件的CRC32值,如下圖所示;

使用SHA1演算法

SHA-1(Secure Hash Algorithm 1)是一種常見的哈希函數,用於生成160位的散列值。與MD5類似,SHA-1也被廣泛用於數字簽名、數據完整性驗證等領域。然而,由於SHA-1存在一些安全性漏洞,特別是對碰撞攻擊的脆弱性,因此在對安全性要求較高的應用中,不再推薦使用SHA-1,而是轉向使用更安全的哈希演算法,如SHA-256或SHA-3。

以下是SHA-1演算法的基本概述:

  1. 輸入處理: SHA-1同樣接受任意長度的輸入,但輸出為160位。輸入被劃分為512位的塊,每個塊包含16個32位字。
  2. 填充: 與MD5類似,如果輸入長度不是512的倍數,需要對輸入進行填充,使其滿足條件。填充的方式是在消息的末尾添加一個'1'和零比特,然後添加一個64位整數,表示原始消息長度。
  3. 初始化: SHA-1有五個32位的寄存器(A、B、C、D、E),初始化為特定的常數。這些寄存器將在處理每個消息塊時進行更新。
  4. 處理塊: SHA-1的處理方式類似於MD5,但使用了不同的非線性函數和常量。每個消息塊經過80個操作輪次,其中包括迭代、位運算和條件操作。
  5. 輸出: SHA-1的輸出是五個32位字的級聯,通常以40位的十六進位數表示。這五個字的順序是A、B、C、D、E。

由於SHA-1存在安全性問題,特別是在2017年被證明對碰撞攻擊不再是安全的,因此已經不再被推薦用於安全性要求較高的應用。取而代之的是,SHA-256和SHA-3等更安全的哈希演算法,它們提供更長的輸出長度和更強的抗碰撞能力。

與MD5的計算方法一致,SHA系列計算方式只需引入<sha.h>系列頭文件,並使用SHA1 sha1;類進行計算即可,如下代碼所示;

#include <Windows.h>
#include <iostream>

#include <sha.h>
#include <files.h>
#include <hex.h>

using namespace std;
using namespace CryptoPP;

#pragma comment(lib,"cryptlib.lib")

// 計算文件SHA1
string CalSHA1ByFile(char *pszFileName)
{
	string value;
	SHA1 sha1;
	FileSource(pszFileName, true, new HashFilter(sha1, new HexEncoder(new StringSink(value))));
	return value;
}

// 計算數據SHA1
string CalSHA1ByMemory(PBYTE pData, DWORD dwDataSize)
{
	string value;
	SHA1 sha1;
	StringSource(pData, dwDataSize, true, new HashFilter(sha1, new HexEncoder(new StringSink(value))));
	return value;
}

int main(int argc, char* argv[])
{
	// 定義SHA類
	SHA1 sha1;

	// 計算文件的sha1
	string sha11 = CalSHA1ByFile("d://lyshark.exe");
	printf("sha1 = %s\n", sha11.c_str());

	// 計算文件記憶體的sha1
	HANDLE hFile2 = CreateFile("d://lyshark.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);

	// 取文件長度
	DWORD dwFileSize2 = GetFileSize(hFile2, NULL);
	BYTE *pData2 = new BYTE[dwFileSize2];

	// 讀文件到記憶體
	ReadFile(hFile2, pData2, dwFileSize2, NULL, NULL);

	// 計算sha1
	string sha12 = CalSHA1ByMemory(pData2, dwFileSize2);
	printf("sha1 = %s\n", sha12.c_str());

	system("pause");
	return 0;
}

sha1計算結果如下圖所示;

使用SHA256演算法

SHA-256(Secure Hash Algorithm 256-bit)是SHA-2(Secure Hash Algorithm 2)家族中的一種哈希函數,用於生成256位的散列值。SHA-256是目前廣泛應用於各種安全領域的強大哈希演算法,包括數字簽名、證書簽名、數據完整性驗證等。SHA-256提供了更高的安全性,相對於之前的SHA-1和MD5來說更為強大。

以下是SHA-256演算法的基本概述:

  1. 輸入處理: SHA-256同樣接受任意長度的輸入,但輸出為256位。輸入被劃分為512位的塊,每個塊包含16個32位字。
  2. 填充: 與SHA-1和MD5相似,如果輸入長度不是512的倍數,需要對輸入進行填充,以滿足條件。填充的方式包括添加一個'1'和零比特,然後添加一個64位整數,表示原始消息長度。
  3. 初始化: SHA-256有八個32位的寄存器(A、B、C、D、E、F、G、H),初始化為特定的常數。這些寄存器將在處理每個消息塊時進行更新。
  4. 處理塊: SHA-256的處理方式包括64個操作輪次,每個輪次使用一個非線性函數、常量和消息塊的子集。這些輪次通過迴圈結構連接起來。
  5. 輸出: SHA-256的輸出是八個32位字的級聯,通常以64位的十六進位數表示。這八個字的順序是A、B、C、D、E、F、G、H。

SHA-256相對於SHA-1和MD5提供了更高的抗碰撞能力和更強的安全性,使其成為當前廣泛使用的哈希演算法之一。然而,隨著計算能力的增強,一些專家逐漸傾向於使用更長的哈希演算法,如SHA-3,以適應未來更高的安全性需求。

代碼調用上與sha1保持一致,Sha256同樣只需要少量的更改,只要掌握了這個規律,那麼則可以完成其他演算法的調用,代碼如下所示;

#include <Windows.h>
#include <iostream>

#include <sha.h>
#include <files.h>
#include <hex.h>

using namespace std;
using namespace CryptoPP;

#pragma comment(lib,"cryptlib.lib")

// 計算文件SHA1
string CalSHA1ByFile(char *pszFileName)
{
	string value;
	SHA256 sha256;
	FileSource(pszFileName, true, new HashFilter(sha256, new HexEncoder(new StringSink(value))));
	return value;
}

// 計算數據SHA1
string CalSHA1ByMemory(PBYTE pData, DWORD dwDataSize)
{
	string value;
	SHA256 sha256;
	StringSource(pData, dwDataSize, true, new HashFilter(sha256, new HexEncoder(new StringSink(value))));
	return value;
}

int main(int argc, char* argv[])
{
	// 定義SHA類
	SHA256 sha256;

	// 計算文件的sha256
	string sha11 = CalSHA1ByFile("d://lyshark.exe");
	printf("sha256 = %s\n", sha11.c_str());

	// 計算文件記憶體的sha256
	HANDLE hFile2 = CreateFile("d://lyshark.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);

	// 取文件長度
	DWORD dwFileSize2 = GetFileSize(hFile2, NULL);
	BYTE *pData2 = new BYTE[dwFileSize2];

	// 讀文件到記憶體
	ReadFile(hFile2, pData2, dwFileSize2, NULL, NULL);

	// 計算sha256
	string sha12 = CalSHA1ByMemory(pData2, dwFileSize2);
	printf("sha256 = %s\n", sha12.c_str());

	system("pause");
	return 0;
}

運行後則可輸出文件的sha256值,如下圖所示;

文章出處:https://www.cnblogs.com/LyShark/p/17865683.html
本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • public class RandomNickName { public enum Gender{ MAN, WOMAN, UNKNOWN, ; } public static void main(String[] args) { String nickName = nickName(Gender. ...
  • 1 簡介 任務是需要資源(CPU 時間、記憶體、存儲、網路帶寬等)在指定時間內完成的一段計算工作。 通過智能地將資源分配給任務以滿足任務級和系統級目標的系統稱為任務調度程式。 任務調度程式: 及時決定和分配資源給任務的過程稱為任務調度。 當我們在 Facebook 發表評論時。我們不會讓評論發佈者等待 ...
  • 本文從源碼層面主要分析了線程池的創建、運行過程,通過上述的分析,可以看出當線程池中的線程數量超過核心線程數後,會先將任務放入等待隊列,隊列放滿後當最大線程數大於核心線程數時,才會創建新的線程執行。 ...
  • 大家好,夜鶯項目發佈 v6.4.0 版本,新增全局巨集變數功能,本文為大家簡要介紹一下相關更新內容。 全局巨集變數功能 像 SMTP 的配置中密碼類型的信息,之前都是以明文的方式在頁面展示,夜鶯支持全局巨集變數之後,可以在變數管理配置一個 smtp_password 的密碼類型的變數,在 SMTP 配置頁 ...
  • Crypto++ (CryptoPP) 是一個用於密碼學和加密的 C++ 庫。它是一個開源項目,提供了大量的密碼學演算法和功能,包括對稱加密、非對稱加密、哈希函數、消息認證碼 (MAC)、數字簽名等。Crypto++ 的目標是提供高性能和可靠的密碼學工具,以滿足軟體開發中對安全性的需求。高級加密標準(... ...
  • 作者查閱了Sentinel官網、51CTO、CSDN、碼農家園、博客園等很多技術文章都沒有很準確的springmvc集成Sentinel的示例,因此整理了本文,主要介紹SpringMvc集成Sentinel ...
  • ArrayList是Java中的一個動態數組類,可以根據實際需要自動調整數組的大小。ArrayList是基於數組實現的,它內部維護的是一個Object數組,預設初始化容量為10,當添加的元素個數超過了當前容量時,會自動擴容。ArrayList也被廣泛用於Java中的集合框架,例如Java中的List... ...
  • 統計學有時候會被誤解,好像必須有大量的樣本數據,才能使統計結果有意義。這會讓我們覺得統計學離我們的日常生活很遙遠。 其實,如果數據的準確度高的話,少量的樣本數據同樣能反映出真實的情況。比如,很多國家選舉時不斷做的民意調查,一般做到有效樣本1600多份就夠了,不管你是幾千萬人的小國家,還是數億人的大國 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...