首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

CryptoAPI 取得純文字 Session Key 實戰技巧

     編輯:關於C++

背景與挑戰

CryptoAPI 的 CryptExportKey / CryptImportKey 要求以另一把金鑰加密/解密 Session Key,無法直接匯出明文金鑰。MSDN 範例使用私鑰解密,流程冗長。本文提供更簡潔高效的方法:利用金鑰交換對的私鑰直接解密 SIMPLEBLOB 取得明文 Session Key。

環境需求

  • VC6 SP5 / Win2000 SP1 / NT4 SP3
  • 專案設定:_WIN32_WINNT=0x0500 (Win2K) 或 0x0400 (NT4)、_CRYPT32_
  • 連結 crypt32.lib

核心步驟

  1. CryptAcquireContext 取得 CSP Handle (建立/使用金鑰容器)
  2. CryptGenKey 產生可匯出的 3DES Session Key (CALG_3DES | CRYPT_EXPORTABLE)
  3. CryptGetUserKey 取得金鑰交換對 Handle (AT_KEYEXCHANGE)
  4. CryptExportKey 以交換對公鑰加密 Session Key 為 SIMPLEBLOB
  5. 移除 Blob 前 12 字節 Header,取得純加密資料
  6. CryptDecrypt 以交換對私鑰解密,獲得明文 Key Material

完整程式碼


#include 
#include 
#include 

#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 {
        // 1. 取得 CSP
        if (!CryptAcquireContext(&hProv, "Container Name", MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
            __leave;

        // 2. 產生 Session Key
        if (!CryptGenKey(hProv, CALG_3DES, CRYPT_EXPORTABLE, &hSessionKey))
            __leave;

        // 3. 取得金鑰交換對
        if (!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hExchangeKeyPair))
            __leave;

        // 4. 匯出加密後的 Session Key (SIMPLEBLOB)
        if (!CryptExportKey(hSessionKey, hExchangeKeyPair, SIMPLEBLOB, 0, NULL, &dwSize))
            __leave;
        pbExportedKeyBlob = new BYTE[dwSize];
        if (!CryptExportKey(hSessionKey, hExchangeKeyPair, SIMPLEBLOB, 0, pbExportedKeyBlob, &dwSize))
            __leave;

        // 5. 移除 12 字節 Header
        pbEncryptedKey = new BYTE[KEY_PAIR_SIZE];
        for (c = 0; c < KEY_PAIR_SIZE; c++)
            pbEncryptedKey[c] = pbExportedKeyBlob[c + 12];

        // 6. 以私鑰解密取得明文 Key Material
        if (!CryptDecrypt(hExchangeKeyPair, 0, TRUE, 0, pbEncryptedKey, &dwKeyMaterial))
            __leave;

        pbKeyMaterial = new BYTE[SESSION_KEY_SIZE];
        for (c = 0; c < SESSION_KEY_SIZE; c++)
            pbKeyMaterial[c] = pbEncryptedKey[c];
        // 此時 pbKeyMaterial 即為純文字 Session Key
    }
    __finally {
        if (pbKeyMaterial) LocalFree(pbKeyMaterial);
        if (hSessionKey) CryptDestroyKey(hSessionKey);
        if (hExchangeKeyPair) CryptDestroyKey(hExchangeKeyPair);
        if (hProv) CryptReleaseContext(hProv, 0);
    }
}

關鍵點提示

  • SIMPLEBLOB 結構:前 12 字節為標頭,其後為加密的金鑰資料。
  • CryptDecrypt 最後參數 pdwDataLen 為輸入緩衝區大小,呼叫後回傳解密後資料長度。
  • 記憶體釋放務必在 __finally 區塊,確保異常時也能釋放。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved