65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 CryptoAPI 获取明文会话密钥

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (14投票s)

2001年12月11日

MIT
viewsIcon

163450

downloadIcon

1603

如何使用 CryptoAPI 获取明文会话密钥

引言

有时,提取原始会话密钥是必要的,尤其是在实现加密协议时。然而,Microsoft 加密服务提供程序(基础和增强型)不支持此功能。CryptExportKey()CryptImportKey() 分别需要有效的密钥句柄来加密和解密会话密钥。MSDN 展示了一种使用指数为一的私钥来执行此操作的方法。本文展示了一种执行相同过程的更好方法。这种方法更快、更直接。

它已经准备就绪,但您必须在 项目 -> 设置 (Visual Studio 6.0) 中设置以下参数:

  • 在 C++/预处理器定义中添加:_WIN32_WINNT=0x0500, _CRYPT32_(WIN2K)_WIN32_WINNT=0x0400, _CRYPT32_(NT4)
  • 并链接此库 crypt32.lib

代码列表

#include <windows.h>
#include <wincrypt.h>

#define KEY_PAIR_SIZE     dwSize - 12
#define SESSION_KEY_SIZE  dwKeyMaterial

void main()
{
    HCRYPTPROV hProv = 0;
    HCRYPTKEY hExchangeKeyPair = 0;
    HCRYPTKEY hSessionKey = 0;
    BYTE *pbKeyMaterial  = NULL;
    DWORD dwKeyMaterial ;   
    BYTE *pbExportedKeyBlob = NULL;
    BYTE *pbEncryptedKey    = NULL;
    DWORD dwSize;
    unsigned int c;

    __try
    {
        if (!CryptAcquireContext( &hProv, "Container Name", 
            MS_ENHANCED_PROV , PROV_RSA_FULL, CRYPT_MACHINE_KEYSET ))
        {
            __leave;
        }

        //---------------------------------------------------
        //Creating a session key. In this sample we'll use a 
        //3DES key with 168 bits

        if (!CryptGenKey(hProv,CALG_3DES,CRYPT_EXPORTABLE,
            &hSessionKey))
        {
            __leave;
        }

        //---------------------------------------------------
        //Getting a handle to the Exchange Key pair

        if (!CryptGetUserKey( hProv, AT_KEYEXCHANGE, 
            &hExchangeKeyPair))
        {
            __leave;
        }

        //--------------------------------------------------------
        //Encrypting the session key with the public key part
        //of the keypair. The first call gets the size necessary to 
        //hold the encrypted session key and the second exports it.

        if (!CryptExportKey( hSessionKey, hExchangeKeyPair, 
            SIMPLEBLOB, 0, NULL, &dwSize))
        {
            __leave;
        }

        pbExportedKeyBlob = new BYTE[dwSize];

        if (!CryptExportKey( hSessionKey, hExchangeKeyPair, SIMPLEBLOB, 
            0, pbExportedKeyBlob,  &dwSize))
        {
            __leave;
        }

        //--------------------------------------------------------
        //Let's  remove the first 12 bytes of Blob information 

        pbEncryptedKey  =  new BYTE [KEY_PAIR_SIZE];  

        for ( c = 0 ; c < KEY_PAIR_SIZE ; c++ )
        {
            pbEncryptedKey[c] =  pbExportedKeyBlob[c+12]; 
        }

        //--------------------------------------------------------
        //Now it's time to get the value of the session key, we'll
        //use the private part of the key pair. 

        if (!CryptDecrypt( hExchangeKeyPair,0, TRUE, 0,  
            pbEncryptedKey, &dwKeyMaterial))
        {
            __leave;
        }

        //-------------------------------------------------------
        //The pbKeyMaterial is the value of the key

        pbKeyMaterial = new BYTE[ SESSION_KEY_SIZE ];

        for ( c = 0; c <  SESSION_KEY_SIZE ; c++ )
        {
            pbKeyMaterial[c] = pbEncryptedKey[c];    
        }

        //-------------------------------------------------------
        //The key is in big-endian format, because that's the way
        //the encryption block is built.
    }
    __finally
    {
        if (pbKeyMaterial ) LocalFree(pbKeyMaterial );
        if (hSessionKey) CryptDestroyKey(hSessionKey);
        if (hExchangeKeyPair) CryptDestroyKey(hExchangeKeyPair);
        if (hProv) 
        {  
            CryptReleaseContext(hProv, 0);
        }
    }

} // End Main

历史

  • 2001年12月11日:初始版本
  • 2022年12月22日:更新 - 修正了文本和许可中的一些问题 
© . All rights reserved.