返回> 网站首页 

[转载]一个公钥加密演示

yoours2011-08-16 11:01:17 阅读 1404

简介一边听听音乐,一边写写文章。

    关于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自动接收的公钥列表里都一堆我的公钥了。


微信小程序扫码登陆

文章评论

1404人参与,0条评论