介紹如何在 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; }
這裡的 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 雜湊值的驗證,其他雜湊演算法的驗證方式也都大同小異,只是抽換雜湊演算法而已。