Crypto++ 使用方法
——长时间以来,没增加新文章!凡所增加,必属原创。
2007-7-24
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信息传输过程的安全问题(仍没解决服务和客户欺诈的问题,这不是本文讨论的议题)。
最后,我很希望看到读者的评论,因为我这方面的知识实在太欠缺了!