Win32 API提供了完整的加密解密解决方案,包含各种加密算法,可用于网络数据传输、数字签名。我编写的这两个类是用于网络数据传输的。CSender代表一个发送端程序,CReceiver代表一个接受端程序。这两个类是演示加密解密及传输数据过程的模型,实际使用时可根据具体情况加以修改。这段程序是在VC7/Win2000下编译调试的。我使用DES和RSA两种加密算法:DES是常规加密算法,价密解密使用相同的密钥,用于加密解密数据;RSA是公开密钥算法,用公钥加密DES密钥,用私钥解密DES密钥,保证DES密钥的安全性。由于公开密钥算法一般计算方法复杂,速度较慢,所以不用于加密大量数据。关于加密算法、公开密钥体制等概念原理兄弟我就不介绍了,太麻烦了。加密解密及传输数据过程如下:
1.发送端和接受端分别启动CSP(Windows加密服务)。
2.接受端随机生成一个RSA密钥对,并把公钥传给发送端。
3.发送端随机生成一个DES密钥,用收到的公钥加密,再发送给接受端。
4.接受端用私钥解密DES密钥。
(之后发送端和接受端就可以反复使用DES密钥传输数据了)
5.发送端用DES密钥加密数据,发送给接受端。
6.接受端用DES密钥恢复数据。
兄弟我抛砖引玉,错误不足之处请多指教。[注]
本文是根据《程序员》杂志2001年第8期文章《互联网数据传输的加密方法》写成的。

解决方案 »

  1.   

    //必须包含的头文件
    #include "WinCrypt.h"//接收数据端
    class CReceiver
    {
    public:
        CReceiver();
        virtual ~CReceiver(); //初始化CSP服务
        BOOL Init(); //随机生成一个密钥对,并把公钥导出到m_pPublicKey中
        BOOL CreatePublicKey(); //用私钥解密DES密钥
        BOOL DecryptSessionKey(const BYTE* pSessionKey, DWORD iSessionKeySize); //用DES密钥解密数据
        BOOL Decrypt(const BYTE* pCipherText, DWORD iCipherTextSize); //获得公钥的指针
        const BYTE* GetPublicKey() const; //获得公钥数据的字节数
        DWORD GetPublicKeySize() const; //获得解密后的明文数据指针
        const BYTE* GetPlainText() const; //获得解密后的明文数据的字节数
        DWORD GetPlainTextSize() const;private:
    //CSP服务句柄
        HCRYPTPROV m_hProv; //RSA密钥对句柄
        HCRYPTKEY m_hExchangeKey; //DES密钥句柄
        HCRYPTKEY m_hSessionKey; //公钥数据
        BYTE* m_pPublicKey; //公钥数据的字节数
        DWORD m_iPublicKeySize; //明文数据
        BYTE* m_pPlainText; //明文数据的字节数
        DWORD m_iPlainTextSize;
    };//发送数据端
    class CSender
    {
    public:
        CSender();
        virtual ~CSender(); //初始化CSP服务
        BOOL Init(); //随机生成DES密钥,用公钥加密,并导出到m_pSessionKey
        BOOL CreateSessionKey(const BYTE* pPublicKey, DWORD iPublicKeySize); //加密数据,pData是任意二进制数据,iDataSize是待加密数据的字节数
        BOOL Encrypt(const BYTE* pData, DWORD iDataSize); //获得“块”的字节数。加密算法分为“流”加密和“块”加密,DES属于“块”加密
    //本程序并未用到此函数。加密上百兆的数据一般就需要用。见MSDN关于CryptEncrypt()倒数第二个参数的说明
        DWORD GetBlockSize(); //获得CSP服务版本号,Win2000/XP的CSP是2.0版本,Win98是1.0版
    //1.0版好像不能使用DES加密,但可以使用RC等加密算法,我也没试过
        WORD GetCSPVersion(); //获得DES密钥的指针
        const BYTE* GetSessionKey() const; //获得DES密钥的字节数
        DWORD GetSessionKeySize() const; //获得密文数据的指针
        const BYTE* GetCipherText() const; //获得密文数据的字节数
        DWORD GetCipherTextSize() const;private:
    //CSP服务句柄
        HCRYPTPROV m_hProv; //DES密钥句柄
        HCRYPTKEY m_hSessionKey; //DES密钥数据
        BYTE* m_pSessionKey; //DES密钥数据的字节数
        DWORD m_iSessionKeySize; //密文数据
        BYTE* m_pCipherText; //密文数据的字节数
        DWORD m_iCipherTextSize;
    };
      

  2.   

    #include "stdafx.h"
    #include ".\sender.h"
    CReceiver::CReceiver()
    {
        m_hProv = NULL;
        m_hExchangeKey = NULL;
        m_hSessionKey = NULL;
        m_pPublicKey = NULL;
        m_iPublicKeySize = 0;
        m_pPlainText = NULL;
        m_iPlainTextSize = 0;
    }CReceiver::~CReceiver()
    {
        if (m_pPublicKey)
            delete m_pPublicKey;
        if (m_pPlainText)
            delete m_pPlainText; // release CSP服务
        if (m_hProv)
            CryptReleaseContext(m_hProv, 0);
    }const BYTE* CReceiver::GetPublicKey() const
    {
        return m_pPublicKey;
    }DWORD CReceiver::GetPublicKeySize() const
    {
        return m_iPublicKeySize;
    }const BYTE* CReceiver::GetPlainText() const
    {
        return m_pPlainText;
    }DWORD CReceiver::GetPlainTextSize() const
    {
        return m_iPlainTextSize;
    }BOOL CReceiver::Init()
    {
        LPCTSTR sContainer = _T("ReceiverContainer"); //启动新的CSP服务
        BOOL bCSPOK = CryptAcquireContext(&m_hProv, sContainer, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET);    if (!bCSPOK)
        {
    //此CSP服务已存在,最后一个参数改为0,获得其句柄
            if (GetLastError() == NTE_EXISTS)
                bCSPOK = CryptAcquireContext(&m_hProv, sContainer, 0, PROV_RSA_FULL, 0);
        }    if (!bCSPOK)
            m_hProv = NULL;
        return bCSPOK;
    }BOOL CReceiver::CreatePublicKey()
    {
        ASSERT(m_hProv); //随机生成RSA密钥对
        BOOL bReturn = CryptGenKey(m_hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &m_hExchangeKey); //导出公钥,第一次调用CryptExportKey()是为了计算公钥字节数,后面有很多类似的用法
        bReturn = CryptExportKey(m_hExchangeKey, 0, PUBLICKEYBLOB, 0, NULL, &m_iPublicKeySize);
        if (m_pPublicKey)
            delete m_pPublicKey;
        m_pPublicKey = new BYTE[m_iPublicKeySize];
        bReturn = CryptExportKey(m_hExchangeKey, 0, PUBLICKEYBLOB, 0, m_pPublicKey, &m_iPublicKeySize);    return bReturn;
    }BOOL CReceiver::DecryptSessionKey(const BYTE* pSessionKey, DWORD iSessionKeySize)
    {
        ASSERT(m_hProv);
        ASSERT(pSessionKey); //解密DES密钥
        return CryptImportKey(m_hProv, pSessionKey, iSessionKeySize, m_hExchangeKey, 0, &m_hSessionKey);
    }BOOL CReceiver::Decrypt(const BYTE* pCipherText, DWORD iCipherTextSize)
    {
        ASSERT(m_hProv);
        ASSERT(m_hSessionKey);
        ASSERT(pCipherText);    if (m_pPlainText)
            delete m_pPlainText;
        m_pPlainText = new BYTE[iCipherTextSize];
        CopyMemory(m_pPlainText, pCipherText, iCipherTextSize);
        m_iPlainTextSize = iCipherTextSize; //解密数据保存在m_pPlainText中
        return CryptDecrypt(m_hSessionKey, 0, TRUE, 0, m_pPlainText, &m_iPlainTextSize);
    }
    CSender::CSender()
    {
        m_hProv = NULL;
        m_pSessionKey = NULL;
        m_iSessionKeySize = 0;
        m_pCipherText = NULL;
        m_iCipherTextSize = 0;
    }CSender::~CSender()
    {
        if (m_pSessionKey)
            delete m_pSessionKey;
        if (m_pCipherText)
            delete m_pCipherText;
        if (m_hProv)
            CryptReleaseContext(m_hProv, 0);
    }const BYTE* CSender::GetSessionKey() const
    {
        return m_pSessionKey;
    }DWORD CSender::GetSessionKeySize() const
    {
        return m_iSessionKeySize;
    }const BYTE* CSender::GetCipherText() const
    {
        return m_pCipherText;
    }DWORD CSender::GetCipherTextSize() const
    {
        return m_iCipherTextSize;
    }DWORD CSender::GetBlockSize()
    {
        ASSERT(m_hSessionKey);    DWORD iBlockSize;
        DWORD iDataSize( sizeof(DWORD) );
        CryptGetKeyParam(m_hSessionKey, KP_BLOCKLEN, (BYTE*)&iBlockSize, &iDataSize, 0);
        return iBlockSize;
    }WORD CSender::GetCSPVersion()
    {
        ASSERT(m_hProv);    DWORD iDataSize;
        CryptGetProvParam(m_hProv, PP_VERSION, NULL, &iDataSize, 0);
        BYTE* pData = new BYTE[iDataSize]; //按MSND,pData[0]是小版本号,pData[1]是主版本号
        CryptGetProvParam(m_hProv, PP_VERSION, pData, &iDataSize, 0);
        WORD iCSPVersion;
        CopyMemory(&iCSPVersion, pData, 2);
        delete pData;
        return iCSPVersion;
    }BOOL CSender::Init()
    {
        LPCTSTR sContainer = _T("SenderContainer");
        BOOL bCSPOK = CryptAcquireContext(&m_hProv, sContainer, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET);
        if (!bCSPOK)
        {
            if (GetLastError() == NTE_EXISTS)
                bCSPOK = CryptAcquireContext(&m_hProv, sContainer, 0, PROV_RSA_FULL, 0);
        }
        if (!bCSPOK)
            m_hProv = NULL;
        return bCSPOK;
    }BOOL CSender::CreateSessionKey(const BYTE* pPublicKey, DWORD iPublicKeySize)
    {
        ASSERT(m_hProv);
        ASSERT(pPublicKey);    HCRYPTKEY hPublicKey;
    BOOL bReturn = CryptImportKey(m_hProv, pPublicKey, iPublicKeySize, 0, 0, &hPublicKey); //随机生成DES密钥
        bReturn = CryptGenKey(m_hProv, CALG_DES, CRYPT_EXPORTABLE, &m_hSessionKey); //用公钥加密DES密钥并导出到m_pSessionKey
        bReturn = CryptExportKey(m_hSessionKey, hPublicKey, SIMPLEBLOB, 0, NULL, &m_iSessionKeySize);
        if (m_pSessionKey)
            delete m_pSessionKey;
        m_pSessionKey = new BYTE[m_iSessionKeySize];
        bReturn = CryptExportKey(m_hSessionKey, hPublicKey, SIMPLEBLOB, 0, m_pSessionKey, &m_iSessionKeySize);    return bReturn;
    }BOOL CSender::Encrypt(const BYTE* pData, DWORD iDataSize)
    {
        ASSERT(m_hProv);
        ASSERT(m_hSessionKey);
        ASSERT(pData); //计算需要的缓存字节数,一般大于待加密数据的字节数
    //密文一般比实际要加密的数据大,如有必要,还要通知接收端实际的数据字节数
    //本程序以'\0'结尾的字符串为测试数据,所以没有通知接收端实际的数据字节数
        m_iCipherTextSize = iDataSize;
        BOOL bReturn = CryptEncrypt(m_hSessionKey, 0, TRUE, 0, NULL, &m_iCipherTextSize, 0);    if (m_pCipherText)
            delete m_pCipherText;
        m_pCipherText = new BYTE[m_iCipherTextSize];    ZeroMemory(m_pCipherText, m_iCipherTextSize);
        CopyMemory(m_pCipherText, pData, iDataSize); //加密数据
        bReturn = CryptEncrypt(m_hSessionKey, 0, TRUE, 0, m_pCipherText, &iDataSize, m_iCipherTextSize);
        return bReturn;
    }
      

  3.   

    代码格式乱了,CSDN需要改进阿下面是一个应用的例子
    //发送数据端
    CSender g_Sender;
    //接受数据端
    CReceiver g_Receiver;//1.发送端和接受端分别启动CSP
    void CSampleView::OnNetworkCspversion()
    {
    if ( g_Sender.Init() && g_Receiver.Init() )
    MessageBox( _T("Init O.K.") );
    }//2.接受端随机生成一个RSA密钥对,并把公钥传给发送端。
    void CSampleView::OnNetworkPublickey()
    {
    VERIFY( g_Receiver.CreatePublicKey() ); CString str;
    str.Format("The size of the Public Key is %d bytes.", g_Receiver.GetPublicKeySize() );
    MessageBox(str);
    }//3.发送端随机生成一个DES密钥,用收到的公钥加密,再发送给接受端。
    void CSampleView::OnNetworkSessionkeydata()
    {
    VERIFY( g_Sender.CreateSessionKey( g_Receiver.GetPublicKey(), g_Receiver.GetPublicKeySize() ) ); CString str;
    str.Format( "The size of the Session Key is %d bytes.", g_Sender.GetSessionKeySize() );
    MessageBox(str);
    }//4.接受端用私钥解密DES密钥。
    void CSampleView::OnNetworkDecryptsessionkey()
    {
    VERIFY( g_Receiver.DecryptSessionKey( g_Sender.GetSessionKey(), g_Sender.GetSessionKeySize() ) ); MessageBox( _T("Decryption is done.") );
    }//5.发送端用DES密钥加密数据,发送给接受端。
    void CSampleView::OnNetworkEncryptdata()
    {
    //const TCHAR szPlainText[] = _T("Nobody could be happy if that happiness is rooted in the pain of others.");
        const TCHAR s[] = _T("Sample Data");
    VERIFY( g_Sender.Encrypt( (BYTE*)s, sizeof(s) ) ); CString str;
    str.Format("Plain Text: %s", s);
    MessageBox(str);
    }//6.接受端用DES密钥恢复数据。
    void CSampleView::OnNetworkDecryptdata()
    {
    VERIFY( g_Receiver.Decrypt( g_Sender.GetCipherText(), g_Sender.GetCipherTextSize() ) ); CString str;
    str.Format( "Text Decrypted: %s", g_Receiver.GetPlainText());
    MessageBox(str);
    }