0 引言
為閱讀本文,讀者需要具備密碼學最基本的知識,如:對稱加密和非對稱 加密、數字簽名等。還好,准備這些知識,一個下午的時間就足夠了。
許多朋友問我 如何使用CryptoPP(目前最新版本為5.4),我以前也沒用過,但一直覺得是個好東西,屬於 經典的C++庫之一。因此,有必要把它作為我的軟件基石之一。我以前是用Windows的Crypt API的,ATL有對應的封裝類。但是,我遇到了一個問題之後,決定放棄Crypt API。原因是, 我使用Win2003加密的東西,在Win2000上解密失敗。很火大。水平有限,時間有限,就不深 入尋找原因了。
改投開源的CryptoPP C++庫門下,發現CryptoPP的用法詭異,到處是 陷阱一樣的模板,對於我這個對密碼學本身略知皮毛的人來說,無疑是雪上加霜。頭一次使 用,以失敗而铩羽。但是,CryptoPP在業界的好名聲,使我不忍放棄,時隔半年之後,我終 於重讀CryptoPP的例子,摸索出使用方法。但是,直接使用CryptoPP真的很煩瑣,索性包裝 為DLL,我把它取名字叫:CryptoPP32.dll。直接使用CryptoPP32.dll,不需要任何 cryptopp5.4的庫,因為我已經把cryptopp5.4靜態編譯進去了。
我在下面的地址:
http://www.3snews.net/index.php/5890/action_viewspace_itemid_9580.html
提供了整個工程的文件下載,包括cryptopp5.4、CryptoPP32和測試項目。用戶必須使用 VC7.1打開CryptoPP32_DLL目錄下的sln文件。第一次編譯,必須在生成管理器中選中 cryptlib。
(我不知道CSDN如何上傳文件。本人提供的下載文件,可以任意散發,復 制,但不得改變作者聲明。CSDN有很多地方做的不夠友好,希望改進!希望CSDN的BLOG編寫 組學學http://www.3snews.net的BLOG,比你們的強很多啊!)
1 CryptoPP54與 CryptoPP32
下面是CryptoPP32.h接口文件的方法:
// CryptoPP32.DLL接口方法
...
namespace CryptoPP32
{
bool CRYPTOPP32_DLL RSAES_OAEP_GenerateKeys(const char *privFilename, const char *pubFilename, unsigned int keyLength=512, const char *seed=0);
bool CRYPTOPP32_DLL RSAES_OAEP_GenerateKeys(string& strPrivKey, string& strPubKey, unsigned int keyLength=512, const char *seed=0);
bool CRYPTOPP32_DLL RSAES_OAEP_EncryptString(const char *pubFilename, const char *message, string& cipher, const char *seed=0);
bool CRYPTOPP32_DLL RSAES_OAEP_DecryptString(const char *privFilename, const char *cipher, string& message);
bool CRYPTOPP32_DLL RSAES_OAEP_EncryptString(const string& strPubKey, const char *message, string& cipher, const char *seed=0);
bool CRYPTOPP32_DLL RSAES_OAEP_DecryptString(const string& strPrivKey, const char *cipher, string& plain);
bool CRYPTOPP32_DLL RSAES_OAEP_EncryptString(const char* N, const char* E, const char* message, string& cipher, const char* seed=0);
bool CRYPTOPP32_DLL RSAES_OAEP_DecryptString(const char* N, const char* E, const char* D, const char* P, const char* Q, const char* dP, const char* dQ, const char* U, const char* cipher, string& plain);
bool CRYPTOPP32_DLL RSAES_PKCS_GenerateKeys(const char *privFilename, const char *pubFilename, unsigned int keyLength=512, const char *seed=0);
bool CRYPTOPP32_DLL RSAES_PKCS_GenerateKeys(string& strPrivKey, string& strPubKey, unsigned int keyLength=512, const char *seed=0);
bool CRYPTOPP32_DLL RSAES_PKCS_EncryptString(const char *pubFilename, const char *message, string& cipher, const char *seed=0);
bool CRYPTOPP32_DLL RSAES_PKCS_EncryptString(const string& strPubKey, const char *message, string& cipher, const char *seed=0);
bool CRYPTOPP32_DLL RSAES_PKCS_DecryptString(const char *privFilename, const char *cipher, string& message);
bool CRYPTOPP32_DLL RSAES_PKCS_DecryptString(const string& strPrivKey, const char *cipher, string& plain);
bool CRYPTOPP32_DLL RSAES_PKCS_EncryptString(const char* N, const char* E, const char* message, string& cipher, const char* seed=0);
bool CRYPTOPP32_DLL RSAES_PKCS_DecryptString(const char* N, const char* E, const char* D, const char* P, const char* Q, const char* dP, const char* dQ, const char* U, const char* cipher, string& plain);
bool CRYPTOPP32_DLL RSASS_PKCS_Sign(const char *privFilename, const char *msgFilename, const char *signFilename, const char *hashFunc="SHA");
bool CRYPTOPP32_DLL RSASS_PKCS_Verify(const char *pubFilename, const char *msgFilename, const char *signFilename, const char *hashFunc="SHA");
bool CRYPTOPP32_DLL RSASS_PKCS_Sign(const string& strPrivKey, const char *message, string& signature, const char *hashFunc="SHA");
bool CRYPTOPP32_DLL RSASS_PKCS_Verify(const string& strPubKey, const char *message, const string& signature, const char *hashFunc="SHA");
bool CRYPTOPP32_DLL HMAC_SHA1_EncryptString(const char *inString, const char *passPhrase, string& outString);
bool CRYPTOPP32_DLL HMAC_SHA1_DecryptString(const char *inString, const char *passPhrase, string& outString);
bool CRYPTOPP32_DLL HMAC_SHA1_EncryptFile(const char *inFilename, const char *outFilename, const char *passPhrase);
bool CRYPTOPP32_DLL HMAC_SHA1_DecryptFile(const char *inFilename, const char *outFilename, const char *passPhrase);
bool CRYPTOPP32_DLL GzipFile(const char *inFilename, const char *outFilename, int deflateLevel);
bool CRYPTOPP32_DLL GunzipFile(const char *inFilename, const char *outFilename);
bool CRYPTOPP32_DLL Base64Encode(const char *inFilename, const char *outFilename);
bool CRYPTOPP32_DLL Base64Decode(const char *inFilename, const char *outFilename);
bool CRYPTOPP32_DLL Base64Encode(const char *plain, string& encoded);
bool CRYPTOPP32_DLL Base64Decode(const char *encoded, string& plain);
bool CRYPTOPP32_DLL HexEncode(const char *inFilename, const char *outFilename);
bool CRYPTOPP32_DLL HexDecode(const char *inFilename, const char *outFilename);
bool CRYPTOPP32_DLL HexEncode(const char *plain, string& encoded);
bool CRYPTOPP32_DLL HexDecode(const char *encoded, string& plain);
};
讀者可以通過我提供的代碼來弄懂CryptoPP54的使用方法,也可以通過下 面的例子,來使用我包裝的CryptoPP32.dll:
// testCryptoPP32.cpp : 定義控制台應用程序的入口點。
// 作者:張亮
// [email protected]
#include "stdafx.h"
#define CRYPTOPP32_IMPORTS
#include "../CryptoPP32_DLL/CryptoPP32.h"
// 動態連接 CryptoPP32.DLL
#ifdef _DEBUG
#pragma comment(lib, "../CryptoPP32_DLL/Debug/CryptoPP32d.lib")
#else
#pragma comment(lib, "../CryptoPP32_DLL/Release/CryptoPP32.lib")
#endif
using namespace CryptoPP32;
int _tmain(int argc, _TCHAR* argv[])
{
// 生成公鑰和私鑰文件
CryptoPP32::RSAES_PKCS_GenerateKeys("c:\privkey.rsa", "c:\pubkey.rsa");
// 生成公鑰和私鑰字符串
string strPriv;
string strPub;
CryptoPP32::RSAES_PKCS_GenerateKeys(strPriv, strPub);
// 使用公鑰文件加密字符串:hello world
string cipher;
CryptoPP32::RSAES_PKCS_EncryptString("c:\pubkey.rsa", "hello world", cipher, "242352ef45tcrewrdwe5ctfdd");
// 使用私鑰文件解密字符串
string plain;
bool bres = CryptoPP32::RSAES_PKCS_DecryptString("c:\privkey.rsa", cipher.c_str(), plain);
// 使用公鑰串加密字符串:"this is a test! 上海"
string cipher2;
CryptoPP32::RSAES_PKCS_EncryptString(strPub, "this is a test! 上海", cipher2);
// 使用私鑰串解密字符串
string plain2;
bool bres2 = CryptoPP32::RSAES_PKCS_DecryptString(strPriv, cipher2.c_str(), plain2);
//
// 下面的用法與下面地址介紹內容的一致:
// http://www-cs-students.stanford.edu/~tjw/jsbn/
// JSBN使用的參數:n, e, d, p, q, dp, dq, u
char n[]="C4E3F7212602E1E396C0B6623CF11D26204ACE3E7D26685E037AD2507DCE82FC28F2D5F8A67FC3AFAB89A6D818D1F4C28CFA548418BD9F8E7426789A67E73E41h";
char e[]="10001h";
char d[]="7cd1745aec69096129b1f42da52ac9eae0afebbe0bc2ec89253598dcf454960e3e5e4ec9f8c87202b986601dd167253ee3fb3fa047e14f1dfd5ccd37e931b29dh";
char p[]="f0e4dd1eac5622bd3932860fc749bbc48662edabdf3d2826059acc0251ac0d3bh";
char q[]="d13cb38fbcd06ee9bca330b4000b3dae5dae12b27e5173e4d888c325cda61ab3h";
char dp[]="b3d5571197fc31b0eb6b4153b425e24c033b054d22b9c8282254fe69d8c8c593h";
char dq[]="968ffe89e50d7b72585a79b65cfdb9c1da0963cceb56c3759e57334de5a0ac3fh";
char u[]="d9bc4f420e93adad9f007d0e5744c2fe051c9ed9d3c9b65f439a18e13d6e3908h";
bres= CryptoPP32::RSAES_PKCS_EncryptString(n, e, "test", cipher);
bres= CryptoPP32::RSAES_PKCS_DecryptString(n, e, d, p, q, dp, dq, u, cipher.c_str(), plain);
return 0;
}
2 CryptoPP32與JavaScript
我再次強調我的偏好: JavaScript——真正的浏覽器語言。我包裝CryptoPP54的目的就是要使它和 JavaScript(JS)對應的類庫jsbn用法一致。這樣,使用浏覽器的客戶端可以用JSBN,服務 端使用CryptoPP32。
Browser(JSBN) <---------> Server(CryptoPP32)
JSBN是一套開源的JavaScript加密庫。目的與CryptoPP類似,可以從下面的網址得到 它的源代碼:
http://www-cs-students.stanford.edu/~tjw/jsbn/
當你了解 了JSBN使用的參數:n, e, d, p, q, dp, dq, u的意義和加密解密的技巧,回過來使用 CryptoPP32,就知道我所說的含義了。經過測試,CryptoPP32可以正確解密JSBN的加密的東 西,反之亦然。在CryptoPP32中,僅用到了下面2個函數:
RSAES_PKCS_EncryptString
RSAES_PKCS_DecryptString
3 應用情景
在一般目的使用的情形下:服 務和客戶每個會話都重新生成的私鑰和密鑰,然後交換公鑰;客戶使用服務的公鑰加密信息 ,然後傳給服務,服務使用自己的私鑰解密;同樣,服務使用客戶的公鑰加密信息,客戶使 用私鑰解密這一信息。這樣,在目前的B/S環境下,不用給客戶添加任何負擔,即解決了 internet信息傳輸過程的安全問題(仍沒解決服務和客戶欺詐的問題,這不是本文討論的議 題)。
最後,我很希望看到讀者的評論,因為我這方面的知識實在太欠缺了!