介紹如何在 C++ 語言中使用 Crypto++ 加密函式庫,實作 MD5、SHA-1、SHA-2、SHA-3 與 BLAKE2 等雜湊演算法。
在使用 Crypto++ 函式庫之前,請先確認系統上有安裝好該函式庫,Ubuntu Linux 可以參考 Ubuntu Linux 安裝、使用 Crypto++ 加密函式庫教學。
計算雜湊值
以下是一個使用 Crypto++ 實作雜湊演算法的範例程式,可自由抽換不同的雜湊演算法,包含 SHA-1、SHA-2、SHA-3、BLAKE2 與 MD5 等:
#include <iostream>
#include <cstdlib>
#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "sha.h" // SHA-1 與 SHA-2 雜湊
#include "sha3.h" // SHA-3 雜湊
#include "blake2.h" // BLAKE2 雜湊
#include "hex.h"
// 啟用不安全的演算法(MD5 專用)
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include "md5.h" // MD5 雜湊
int main () {
using namespace CryptoPP;
// 指定採用的雜湊演算法
SHA1 hash; // SHA-1
// SHA224 hash; // SHA-224
// SHA256 hash; // SHA-256
// SHA384 hash; // SHA-384
// SHA512 hash; // SHA-512
// SHA3_224 hash; // SHA3-224
// SHA3_256 hash; // SHA3-256
// SHA3_384 hash; // SHA3-384
// SHA3_512 hash; // SHA3-512
// BLAKE2b hash; // BLAKE2
// Weak::MD5 hash; // MD5
// 原始資料
std::string msg = "Crypto++ is a free C++ library for cryptography.";
// 預留儲存雜湊值的空間
std::string digest;
digest.resize(hash.DigestSize());
// 輸入資料
hash.Update((const byte*) msg.data(), msg.size());
// 計算雜湊值
hash.Final((byte*) digest.c_str());
// 輸出資料與雜湊值
std::cout << "Message: " << msg << std::endl;
std::cout << hash.AlgorithmName() << " Digest: ";
StringSource(digest, true, new HexEncoder(new FileSink(std::cout)));
std::cout << std::endl;
return EXIT_SUCCESS;
}
將這份程式碼儲存為 my_hash.cpp,並以 g++ 編譯器進行編譯:
# 編譯 Crypto++ 應用程式
g++ -I/usr/include/crypto++ -o my_hash my_hash.cpp -lcryptopp
# 執行應用程式
./my_hash
Message: Crypto++ is a free C++ library for cryptography. SHA-1 Digest: 1A7588E2529D53DD5200371F6CF5084754A9B76C
由於 MD5 雜湊值屬於過時且不安全的雜湊演算法,所以在使用時要先將 CRYPTOPP_ENABLE_NAMESPACE_WEAK 設為 1,啟用不安全的演算法之後,才能使用 MD5 雜湊演算法。
在實務上若輸入的資料量很大,可以將資料分批以多次 Update() 輸入資料,等所有資料都輸入完之後,再呼叫 Final() 計算雜湊值。如果資料量很小,也可以使用 CalculateDigest() 輸入所有資料並計算出雜湊值:
#include <iostream>
#include <cstdlib>
#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "sha.h"
#include "hex.h"
int main () {
using namespace CryptoPP;
// 原始資料
std::string msg = "Crypto++ is a free C++ library for cryptography.";
// 預留儲存雜湊值的空間
std::string digest;
digest.resize(SHA1::DIGESTSIZE);
// 計算 SHA1 雜湊值
SHA1().CalculateDigest((byte*) digest.c_str(),
(byte*) msg.c_str(), msg.length());
// 輸出資料與雜湊值
std::cout << "Message: " << msg << std::endl;
std::cout << "Digest: ";
StringSource(digest, true, new HexEncoder(new FileSink(std::cout)));
std::cout << std::endl;
return EXIT_SUCCESS;
}
管線(Pipelining)
這裡的 StringSource()、HexEncoder() 與 FileSink() 是 Crypto++ 所提供的各種 Filter,多個 Filters 可以組成一條 管線(Pipelining),概念類似 Linux 中的指令管線(pipeline),將不同的小工具串接後,以資料流的概念來處理資料。
這裡的 HexEncoder 是一個可以將二進位資料轉換為十六進位(hex)文字的 Filter,轉換時可以調整英文字母的大小寫、分隔符號等,可以依照自己的需求自行設定。
以下是採用 Pipelining 寫法的雜湊計算程式碼範例:
#include <iostream>
#include <cstdlib>
#include "cryptlib.h"
#include "filters.h"
#include "sha.h"
#include "hex.h"
int main () {
using namespace CryptoPP;
// 指定採用 SHA1 雜湊演算法
SHA1 hash;
// 原始資料與儲存雜湊值的空間
std::string msg = "Crypto++ is a free C++ library for cryptography.";
std::string digest;
// 以 Pipelining 計算雜湊值
StringSource ss(msg, true,
new HashFilter(hash,
new HexEncoder(
new StringSink(digest)
) // HexEncoder
) // HashFilter
); // StringSource
// 輸出資料與雜湊值
std::cout << "Message: " << msg << std::endl;
std::cout << "Digest: " << digest << std::endl;
return EXIT_SUCCESS;
}
計算檔案雜湊值
若要計算檔案內容的雜湊值,可以使用 FileSource() 這個 Filter:
#include <iostream>
#include <cstdlib>
#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "sha.h"
#include "hex.h"
int main (int argc, char *argv[]) {
using namespace CryptoPP;
// 指定採用 SHA1 雜湊演算法
SHA1 hash;
// 儲存雜湊值的空間
std::string digest;
// 以 Pipelining 計算雜湊值
FileSource fs(argv[1], true,
new HashFilter(hash,
new HexEncoder(
new StringSink(digest)
) // HexEncoder
) // HashFilter
); // StringSource
// 輸出雜湊值
std::cout << "Digest: " << digest << std::endl;
return EXIT_SUCCESS;
}
將這份程式碼儲存為 file_sha1.cpp,並以 g++ 編譯器進行編譯:
# 編譯 Crypto++ 應用程式
g++ -I/usr/include/crypto++ -o file_sha1 file_sha1.cpp -lcryptopp
執行程式,並指定要計算雜湊值的檔案:
# 執行應用程式
./file_sha1 my_file.txt
Digest: 49FDC0FCAA06B59375CDDD9CB5C84D7AC37BC216
我們可以使用 Linux 中的 sha1sum 指令來驗證自己的計算是否正確:
# 以 sha1sum 指令計算雜湊碼
sha1sum my_file.txt
49fdc0fcaa06b59375cddd9cb5c84d7ac37bc216 my_file.txt
驗證雜湊值
Crypto++ 的各種雜湊演算法也可以用來驗證資料的雜湊值是否正確,以下是驗證 SHA-1 雜湊值的範例:
#include <iostream>
#include <cstdlib>
#include "cryptlib.h"
#include "filters.h"
#include "files.h"
#include "sha.h"
#include "hex.h"
int main () {
using namespace CryptoPP;
// 指定採用的雜湊演算法
SHA1 hash;
// 原始資料
std::string msg = "Crypto++ is a free C++ library for cryptography.";
// SHA1 雜湊值
unsigned char digest[] = {
0x1A, 0x75, 0x88, 0xE2, 0x52, 0x9D, 0x53, 0xDD, 0x52, 0x00,
0x37, 0x1F, 0x6C, 0xF5, 0x08, 0x47, 0x54, 0xA9, 0xB7, 0x6C};
// 輸入資料
hash.Update((const byte*) msg.data(), msg.size());
// 驗證雜湊值
if (hash.Verify((const byte*) digest))
std::cout << "驗證成功" << std::endl;
else
std::cout << "驗證失敗" << std::endl;
return EXIT_SUCCESS;
}
將這份程式碼儲存為 sha1_vfy.cpp,並以 g++ 編譯器進行編譯:
# 編譯 Crypto++ 應用程式
g++ -I/usr/include/crypto++ -o sha1_vfy sha1_vfy.cpp -lcryptopp
# 執行應用程式
./sha1_vfy
驗證成功
這裡只示範 SHA-1 雜湊值的驗證,其他雜湊演算法的驗證方式也都大同小異,只是抽換雜湊演算法而已。
