CAPI 中 CryptExportKey 導出會話密鑰時,輸出為 **SIMPLEBLOB** 格式:前 12 字節為 BLOBHEADER + ALG_ID,後接 **用公鑰加密的會話密鑰明文**。若需獲取會話密鑰**原始字節值** (如跨進程共享、調試、非標準協議),可用**對應私鑰解密**該 Blob 尾部密文。本文給出最小化代碼流程。
+------------------+------------------+------------------------+ | BLOBHEADER (8B) | ALG_ID (4B) | Encrypted Key Material | | (type, version, | (CALG_3DES 等) | (RSA 公鑰加密) | | reserved) | | | +------------------+------------------+------------------------+ 12 字節固定頭部 可變長 (等於 RSA 密鑰長度/8)
CRYPT_EXPORTABLE);AT_KEYEXCHANGE);CryptExportKey(hSession, hPubKey, SIMPLEBLOB, 0, ...) 導出 Blob;CryptDecrypt(hPrivKey, 0, TRUE, 0, encryptedPart, &len) 解密得明文會話密鑰;
#define _WIN32_WINNT 0x0500 // 至少 Win2000
#include
#include
#include
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "advapi32.lib")
int main() {
HCRYPTPROV hProv = 0;
HCRYPTKEY hSessionKey = 0, hExchKey = 0;
BYTE *pBlob = NULL, *pEncKey = NULL, *pKeyMat = NULL;
DWORD blobLen = 0, keyMatLen = 0;
__try {
// 1. 獲取 CSP (機器級容器,持久化)
if (!CryptAcquireContext(&hProv, L"TestContainer", MS_ENHANCED_PROV,
PROV_RSA_FULL, CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) {
if (GetLastError() == NTE_EXISTS)
CryptAcquireContext(&hProv, L"TestContainer", MS_ENHANCED_PROV,
PROV_RSA_FULL, CRYPT_MACHINE_KEYSET);
else __leave;
}
// 2. 生成可導出 3DES 會話密鑰
if (!CryptGenKey(hProv, CALG_3DES, CRYPT_EXPORTABLE, &hSessionKey)) __leave;
// 3. 獲取密鑰交換公/私鑰對
if (!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hExchKey)) __leave;
// 4. 導出 SIMPLEBLOB (用公鑰加密會話密鑰)
if (!CryptExportKey(hSessionKey, hExchKey, SIMPLEBLOB, 0, NULL, &blobLen)) __leave;
pBlob = new BYTE[blobLen];
if (!CryptExportKey(hSessionKey, hExchKey, SIMPLEBLOB, 0, pBlob, &blobLen)) __leave;
// 5. 去除 12 字節頭部
DWORD encKeyLen = blobLen - 12;
pEncKey = new BYTE[encKeyLen];
memcpy(pEncKey, pBlob + 12, encKeyLen);
// 6. 用私鑰解密得會話密鑰明文
keyMatLen = encKeyLen; // 解密後長度同密文 (RSA 無填充模式)
pKeyMat = new BYTE[keyMatLen];
memcpy(pKeyMat, pEncKey, keyMatLen);
if (!CryptDecrypt(hExchKey, 0, TRUE, 0, pKeyMat, &keyMatLen)) __leave;
// 7. 輸出十六進制明文
std::cout << "Session Key (" << keyMatLen << " bytes): ";
for (DWORD i = 0; i < keyMatLen; ++i)
printf("%02X", pKeyMat[i]);
std::cout << std::endl;
}
__finally {
if (pKeyMat) delete[] pKeyMat;
if (pEncKey) delete[] pEncKey;
if (pBlob) delete[] pBlob;
if (hSessionKey) CryptDestroyKey(hSessionKey);
if (hExchKey) CryptDestroyKey(hExchKey);
if (hProv) CryptReleaseContext(hProv, 0);
}
return 0;
}
_WIN32_WINNT=0x0500 (Win2000+) 或 0x0400 (NT4);crypt32.lib、advapi32.lib;CRYPT_MACHINE_KEYSET 需管理員權限,用戶級用 0;CALG_AES_256);BCryptExportKey/BCryptDecrypt) 流程類似,算法標識改為 BCRYPT_AES_ALGORITHM 等。理解 SIMPLEBLOB 結構與私鑰解密邏輯,有助於調試密鑰交換協議、實現自定義密鑰包裝格式、對接非標準加密庫。實際開發中**堅持「密鑰不落地、不明文在內存停留」** 原則。