返回> 网站首页
[转载]一个公钥加密演示
yoours2011-08-16 11:01:17
简介一边听听音乐,一边写写文章。
关于WinCrypt API一直没有一个比较好的例子,虽然Defoliate中没有使用WinCrypt API,但我在研究数据证书时看了一下,留下一段代码吧,不过产品级的东东最好不要用WinCrypt API 。
/********************************************************************
created: 2007/07/07
created: 7:7:2007 21:09
filename:c:\VcWork\Secure\Secure.cpp
file path: c:\VcWork\Secure
file base: Secure
file ext: cpp
purpose: 公钥加密技术演示,巨老的经典模型(几十年前就定型了),不敢班门弄斧,也许对密码学小鸟有点帮助。
*********************************************************************/
#include "stdafx.h"
using namespace std;
//创建密钥对,我发现XP SP2系统WinCrypt API确实可以创建达到8192位的RSA密钥,不太可能吧,也许会留有暗门,老美不会对我们这么好吧!!!
//所以一般我们宁愿自己写大整数运算类(网络也能找到),再包装RSA和ECC算法,对称加密算法网络上找到的到是比较透明。
//Defoliate中我就没有用WinCrypt API
void GenKeyPair(void)
{
CCryptProv Prov;
Prov.Initialize(PROV_RSA_FULL,NULL,MS_STRONG_PROV);
const int KeySize=4096;
CCryptRandomKey KeyPair;
//要等几秒种,跟据Key的大小,Key越大时间越长
if(FAILED(KeyPair.Initialize(Prov,CALG_RSA_KEYX,CRYPT_EXPORTABLE|(KeySize<<16))))
return;
//其实导出时应该先用Hash函数Hash一个密码,再用从Hash值派生出一个密钥,再加密导出的私钥
DWORD dwLen=0;
if(FAILED(KeyPair.ExportPrivateKeyBlob(CCryptKey::EmptyKey,CRYPT_OAEP,NULL,&dwLen)))
return;
char *szBase64=NULL;
PBYTE pPrivateKey=new BYTE[dwLen];
if(pPrivateKey)
{
KeyPair.ExportPrivateKeyBlob(CCryptKey::EmptyKey,CRYPT_OAEP,pPrivateKey,&dwLen);
int cbBase64=Base64EncodeGetRequiredLength(dwLen);
szBase64=new char[cbBase64+4];
if(szBase64)
{
Base64Encode(pPrivateKey,dwLen,szBase64,&cbBase64);
szBase64[cbBase64]=0;
FILE *fp=fopen("PrivateKey.txt","w");
if(fp)
{
fprintf(fp,"%s",szBase64);
fclose(fp);
}
cout<<"PrivateKey:"<<endl<<szBase64<<endl;
delete []szBase64;
szBase64=NULL;
}
delete []pPrivateKey;
pPrivateKey=NULL;
}
if(FAILED(KeyPair.ExportPublicKeyBlob(CCryptKey::EmptyKey,CRYPT_OAEP,NULL,&dwLen)))
return;
PBYTE pPublicKey=new BYTE[dwLen];
if(pPublicKey)
{
KeyPair.ExportPublicKeyBlob(CCryptKey::EmptyKey,CRYPT_OAEP,pPublicKey,&dwLen);
int cbBase64=Base64EncodeGetRequiredLength(dwLen);
szBase64=new char[cbBase64];
if(szBase64)
{
Base64Encode(pPublicKey,dwLen,szBase64,&cbBase64);
szBase64[cbBase64]=0;
FILE *fp=fopen("PublicKey.txt","w");
if(fp)
{
fprintf(fp,"%s",szBase64);
fclose(fp);
}
cout<<"PublicKey:"<<endl<<szBase64<<endl;
delete []szBase64;
szBase64=NULL;
}
delete []pPublicKey;
pPublicKey=NULL;
}
}
//模仿网络中的发送的一端(Email和文件都是一种数据,从这个概念上讲它们和TestEncrypt函数中的szText变量没有任何区别)
//创建随机的会话密钥加密数据,再使用公钥加密会话密钥
void TestEncrypt(void)
{
FILE *fp=fopen("PublicKey.txt","r");
if(fp)
{
fseek(fp,0,SEEK_END);
int iSize=ftell(fp);
if(iSize)
{
char *szBase64=new char[iSize+4];
if(szBase64==NULL)
{
fclose(fp);
return;
}
fseek(fp,0,SEEK_SET);
iSize=fread(szBase64,1,iSize,fp);
PBYTE pPublicKey=new BYTE[iSize];
if(pPublicKey)
{
Base64Decode(szBase64,iSize,pPublicKey,&iSize);
CCryptProv Prov;
if(SUCCEEDED(Prov.Initialize(PROV_RSA_FULL,NULL,MS_STRONG_PROV)))
{
//导入公钥匙
CCryptImportKey PublicKey;
PublicKey.Initialize(Prov,pPublicKey,iSize,CCryptKey::EmptyKey,CRYPT_OAEP);
CCryptRandomKey SessionKey;
char szText[128]={"hello WinCrypt"};
//用CryptGenKey创建一个随机密钥,并使用对称算法以该密钥快速加密数据,
//虽然XP SP2中RSA密钥可以很长,但Cipher算法却很少,2K3中包括了AES算法,
//XP中稍微安全一点的,,只能选择RC5或是3DES了,EFS到底用的是什么算法?
if(SUCCEEDED(SessionKey.Initialize(Prov,CALG_3DES)))
{
DWORD cbText=strlen(szText);
SessionKey.Encrypt(TRUE,(PBYTE)szText,&cbText,128);
int iEncode=iSize;
Base64Encode((PBYTE)szText,cbText,szBase64,&iEncode);
szBase64[iEncode]=0;
cout<<endl<<"CipherText in Base64:"<<szBase64<<endl;
//加密导出会话密钥
SessionKey.ExportSimpleBlob(PublicKey,CRYPT_OAEP,pPublicKey,(DWORD*)&iSize);
//保存密文
FILE *fpCipherText=fopen("CipherText.bin","wb");
if(fpCipherText)
{
fwrite(szText,cbText,1,fpCipherText);
fclose(fpCipherText);
}
//保存会话密钥
FILE *fpSessionKey=fopen("SessionKey.bin","wb");
if(fpSessionKey)
{
fwrite(pPublicKey,iSize,1,fpSessionKey);
fclose(fpSessionKey);
}
}
delete []pPublicKey;
}
delete []szBase64;
}
}
fclose(fp);
}
}
//这里相当与网络的接收一端
void TestDecrypt(void)
{
FILE *fp=fopen("PrivateKey.txt","r");
if(fp)
{
fseek(fp,0,SEEK_END);
int iSize=ftell(fp);
if(iSize)
{
char *szBase64=new char[iSize+4];
if(szBase64==NULL)
{
fclose(fp);
return;
}
fseek(fp,0,SEEK_SET);
iSize=fread(szBase64,1,iSize,fp);
PBYTE pPrivateKey=new BYTE[iSize];
if(pPrivateKey)
{
Base64Decode(szBase64,iSize,pPrivateKey,&iSize);
CCryptProv Prov;
if(SUCCEEDED(Prov.Initialize(PROV_RSA_FULL,NULL,MS_STRONG_PROV)))
{
CCryptImportKey PrivateKey;
PrivateKey.Initialize(Prov,pPrivateKey,iSize,CCryptKey::EmptyKey,CRYPT_OAEP);
//导入会话密钥
FILE *fpSessionKey=fopen("SessionKey.bin","rb");
if(fpSessionKey)
{
int iRet=fread(pPrivateKey,1,iSize,fpSessionKey);
CCryptImportKey SessionKey;
SessionKey.Initialize(Prov,pPrivateKey,iRet,PrivateKey,CRYPT_OAEP);
FILE *fpCipherText=fopen("CipherText.bin","rb");
if(fpCipherText)
{
static char TextBuf[204800]={0};
iRet=fread(TextBuf,1,204800,fpCipherText);
//解密密文
SessionKey.Decrypt(TRUE,(PBYTE)TextBuf,(DWORD*)&iRet);
TextBuf[iRet]=0;
cout<<"Decrypt String:"<<TextBuf<<endl;
fclose(fpCipherText);
}
fclose(fpSessionKey);
}
delete []pPrivateKey;
}
delete []szBase64;
}
}
fclose(fp);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
//创建密钥对
GenKeyPair();
//和你的朋友交换密钥吧.
//更标准的用法应该使用数字证书,这个例子里没有使用x509之类的证书,WinCrypt完全支持PKCS2和x509
//....................
//用你朋友的公钥加密数据
TestEncrypt();
//你的朋友可以用私钥解密数据
TestDecrypt();
//在这个例子,"你"和"你的朋友"都是一个"人"存在于这一个程序里,呵呵
//这样的话以后我们可以在马里面加一个公钥,回传数据前加密,回来后用私钥解密
system("pause");
return 0;
}
运行效果:
PrivateKey:
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
PublicKey:
BgIAAACkAABSU0ExABAAAAEAAQBJhKMtZTLaXviA7WDZdi2g0TuDjHzi7+jaufA/fJBkJ4z1HTup
hvlco/Ukv0ovMgaG+YGzs8PBeR3NIZdpZ8q27VBzOYTdlTHcfXqbxoCt2BvmPB7/4VlkgQl0P9U3
DzNjDqK3w6Ypw+cPMKhP3O/aFYLBgHO9JaEqWa6Kf5Erm8E22EUFE3090SPxqqWk66vtgJVGw43G
cpc35a9DaQh2mx2O7jTbQQNmsygXzBO9l3raf0ex1WffDqJTe9EkK//4qWJ65wM1juGXRy3xpOlt
O2mZXoVrJbVR9jTiimZxXigMgWuam86CqIzMFbf7slHQ4kH6EuykLy3FCcH8jvsSjkGgWRFAfzNv
kwC5uIU0rYd1CP9Z7DRVNzMRaFwZ99A+HQ0IfXBW/Jjm76IKCu2oJCjy3XdPUhjKQr7dpRbckG2o
Rrc8TMVRWtS1BrknTOsMn3eB3TSuT5F+XMLJ0hAsxlFvDAy+aCDb69MwGbrbg5zsH5ZrtXLiLj0Z
BdyzSKys4bX5YR+bAijfRx/+ZDf6ifeLyPwhppwqXEEeIjwdHKjACgc6dgxiygeq32al6RCZcF6u
a4mTh0Phw6xv111xV4yb41pbeKESgP5XVBfToOwtgQtzW7UNMqvtI8w+ONfF41Duc96gcr01jnpM
vyfRYnaDP8qiM3p1d4rEevNnuw==
CipherText in Base64:GiMxjL9jPIBARrEwy0TTUA==
Decrypt String:hello WinCrypt
请按任意键继续. . .
公钥加密机制的意义在于,网络上不出现明文的密钥传输,你可以破解我用的对称加密密钥(随机的会话密钥),得到我一次通讯的数据,但你下次又要这样重复破解一遍,比如我用Secway和别人聊天,每一条加密信息你都要重复算一遍,累不累?不累吧!!!资源上很浪费(花费掉的时间、人力或是计算机硬件),除非算出我的私钥,可这需要付出相当大的代价(PrivateKey>4096位时),或许在算出来以前,我的密钥已经过期,我已经使用另一个密钥对了,有一个非常关键的切入点可以攻击,就是在我的机器上如何得到经过口令加密的私钥文件,再破解口令(异或是直接键盘记录得到),异或是直接拿刀架着我让我说出来,呵呵!
另,每次用Secway时都创建一个新的椭圆曲线密钥,加密的口令无规律乱敲我自己十秒钟后都记不得(反正只用一次),记得417大哥说他那Secway自动接收的公钥列表里都一堆我的公钥了。