Crypto++是個免費的C++加解密類庫,由於資格太老、持續更新,最新版本到了CryptoPP 5.6,對天緣而言,第一眼看到CryptoPP就感覺頭大,根目錄下放置大量單源文件、編譯文件、項目文件,再加上多平台和多編譯器支持,文件幾乎又多了一倍,而且還是都混到一起,直接就讓人望而卻步。畢竟Crypto是個功能完整,且經過大量用戶使用考驗的開源庫。所以,皺眉學習匯總一下,遂成此文。
本文測試環境:Windows7 SP1+VC6,測試工程名為Test。用VC打開CryptoPP工程文件,會發現有四個子工程:
cryptdll - 生成cryptopp.dll動態庫
dlltest - 用來測試cryptopp.dll,依賴cryptdll工程
cryptlib - 生成cryptlib.lib靜態庫
cryptest - 用來測試cryptopp,依賴cryptlib工程
所以,我們有兩種使用CryptoPP方法,一種是靜態鏈接,還有一種是動態鏈接,使用對應的工程編譯即可,區別就不說了,我們下文以靜態鏈接為例,介紹幾種常用加解密算法使用。
一、編譯cryptlib
首先需要編譯cryptlib,最後得到cryptlib.lib文件。
先在測試工程Test下創建目錄cryptopp\lib和cryptopp\include,並把Project Settings-C/C++-Processor下Include目錄增加“cryptopp\include”。
把cryptlib.lib拷貝到Test\cryptopp\lib下。
把cryptoPP根目錄下所有的*.h文件都拷貝到Test\cryptopp\include下。當然實際上用不了那麼多,後續用到哪個include哪個。
下文開始測試使用CryptoPP,實際使用中,如果功能上邏輯上需要修改,可以參考上文測試工程中的示例程序,以及官方文檔。下文編譯如果報告XX重復定義等錯誤,請檢查LIB庫工程和本測試工程的:Project Setting-C/C++-Code Generation User run-time library是否統一。
二、測試cryptlib
1、測試MD5
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include "md5.h"
using namespace CryptoPP;
#pragma comment(lib, "cryptopp\\lib\\cryptlib.lib")
using namespace std;
void main() {
byte message[]="HelloWorld!";
byte mres[16];//MD5 128 bits=16bytes
Weak::MD5 md5;
md5.Update(message,11);//strlen=11
md5.Final(mres);
for(int i=0;i<16;i++)
printf("%02X",mres[i]);
printf("\n");
}
2、測試AES
//For AES encrypt
#include "default.h"
#include "cryptlib.h"
#include "filters.h"
#include "bench.h"
#include "osrng.h"
#include "hex.h"
#include "modes.h"
#include "files.h"
using namespace CryptoPP;
#pragma comment(lib, "cryptopp\\lib\\cryptlib.lib")
using namespace std;
void main() {
unsigned char key[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, 0x01,0x02, 0x03,0x04,0x05,0x06,0x07,0x08};//AES::DEFAULT_KEYLENGTH
unsigned char iv[] = {0x01,0x02,0x03,0x03,0x03,0x03,0x03,0x03, 0x03,0x03, 0x01,0x02,0x03,0x03,0x03,0x03};
int keysize = 16;
string message = "Hello World!";
string strEncTxt;
string strDecTxt;
//CBC - PADDING
//AES-CBC Encrypt(ONE_AND_ZEROS_PADDING)
CBC_Mode<AES>::Encryption Encryptor1(key,keysize,iv);
StringSource( message,
true,
new StreamTransformationFilter( Encryptor1,
new StringSink( strEncTxt ),
BlockPaddingSchemeDef::BlockPaddingScheme::ONE_AND_ZEROS_PADDING,
true)
);
//AES-CBC Decrypt
CBC_Mode<AES>::Decryption Decryptor1(key,keysize,iv);
StringSource( strEncTxt,
true,
new StreamTransformationFilter( Decryptor1,
new StringSink( strDecTxt ),
BlockPaddingSchemeDef::BlockPaddingScheme::ONE_AND_ZEROS_PADDING,
true)
);
//CTR - NO_PADDING
//AES-CTR Encrypt
CTR_Mode<AES>::Encryption Encryptor2(key,keysize,iv);
StringSource( message,
true,
new StreamTransformationFilter( Encryptor2,
new StringSink( strEncTxt ),
BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING,
true)
);
//AES-CTR Decrypt
CTR_Mode<AES>::Decryption Decryptor2(key,keysize,iv);
StringSource( strEncTxt,
true,
new StreamTransformationFilter( Decryptor2,
new StringSink( strDecTxt ),
BlockPaddingSchemeDef::BlockPaddingScheme::NO_PADDING,
true)
);
}
上文是使用StringSource方式加密字符串,還可以使用FileSource方式直接對文件進行加解密操作。示例如下:
SecByteBlock HexDecodeString(const char *hex) {
StringSource ss(hex, true, new HexDecoder);
SecByteBlock result((size_t)ss.MaxRetrievable());
ss.Get(result, result.size());
return result;
}
void AES_CTR_Encrypt(const char *hexKey, const char *hexIV, const char *infile, const char *outfile) {
SecByteBlock key = HexDecodeString(hexKey);
SecByteBlock iv = HexDecodeString(hexIV);
CTR_Mode<AES>::Encryption aes(key, key.size(), iv);
FileSource(infile, true, new StreamTransformationFilter(aes, new FileSink(outfile)));
}
直接調用AES_CTR_Encrypt函數即可,CBC函數需對應修改。
四、使用提示
1、StringSource類定義filters.h
//! zero terminated string as source
StringSource(const char *string, bool pumpAll, BufferedTransformation *attachment = NULL)
: SourceTemplate<StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));}
//! binary byte array as source
StringSource(const byte *string, size_t length, bool pumpAll, BufferedTransformation *attachment = NULL)
: SourceTemplate<StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));}
//! std::string as source
StringSource(const std::string &string, bool pumpAll, BufferedTransformation *attachment = NULL)
: SourceTemplate<StringStore>(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));}
2、RSA有關的加解密、簽名函數
更多請參考工程cryptest工程下test.cpp文件內函數
void GenerateRSAKey(unsigned int keyLength, const char *privFilename, const char *pubFilename, const char *seed);
string RSAEncryptString(const char *pubFilename, const char *seed, const char *message);
string RSADecryptString(const char *privFilename, const char *ciphertext);
void RSASignFile(const char *privFilename, const char *messageFilename, const char *signatureFilename);
bool RSAVerifyFile(const char *pubFilename, const char *messageFilename, const char *signatureFilename);