使用 CryptoAPI 获取明文会话密钥






4.90/5 (14投票s)
如何使用 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日:更新 - 修正了文本和许可中的一些问题