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

Microsoft CryptoAPI 加密技術深度解析(二):非對稱加密、雜湊與數位簽章

     編輯:VC 教學

前言

承接上篇,本文深入探討公開金鑰加密、雜湊演算法、數位簽章與金鑰容器管理,並提供完整 CryptoAPI 程式碼範例。

一、公開金鑰加密體系

二、CSP 金鑰容器結構

每個 CSP (Cryptographic Service Provider) 擁有一個金鑰資料庫,包含一或多個金鑰容器。每個容器通常持有兩組金鑰對:

  • AT_KEYEXCHANGE:金鑰交換對 (加密 Session Key)
  • AT_SIGNATURE:簽章對 (數位簽章/驗證)

三、取得或建立金鑰對

HCRYPTPROV hProv; // 已取得 CSP 控制代碼
HCRYPTKEY hKey;

// 1. 嘗試取得現有簽章金鑰
if (CryptGetUserKey(hProv, AT_SIGNATURE, &hKey)) {
    printf("簽章金鑰已存在\n");
} else {
    DWORD err = GetLastError();
    if (err == NTE_NO_KEY) {
        // 2. 不存在則建立新簽章金鑰對
        if (CryptGenKey(hProv, AT_SIGNATURE, 0, &hKey)) {
            printf("建立簽章金鑰對成功\n");
        } else {
            printf("建立失敗: 0x%08X\n", GetLastError());
        }
    } else {
        printf("取得金鑰錯誤: 0x%08X\n", err);
    }
}

// 同理處理 AT_KEYEXCHANGE

四、雜湊演算法

特性說明
金鑰對公開金鑰 (可公開) + 私有金鑰 (嚴守秘密)
加密/解密公鑰加密 → 唯有對應私鑰能解密;私鑰加密(簽章) → 唯有對應公鑰能驗證
效能極低 (對稱加密的 1/1000),不適合大量資料
實務用法加密對稱金鑰 (Session Key)、數位簽章、金鑰交換

雜湊計算流程

HCRYPTHASH hHash;
CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash);

// 分塊更新 (大檔案/串流)
BYTE buffer[4096];
DWORD read;
while (ReadFile(hFile, buffer, sizeof(buffer), &read, NULL) && read > 0) {
    CryptHashData(hHash, buffer, read, 0);
}

// 取得雜湊值
BYTE hash[32]; // SHA-256 = 32 bytes
DWORD hashLen = 32;
CryptGetHashParam(hHash, HP_HASHVAL, hash, &hashLen, 0);

CryptDestroyHash(hHash);

五、數位簽章完整流程

簽章端 (持有私鑰)

// 1. 計算資料雜湊
CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash);
CryptHashData(hHash, data, dataLen, 0);

// 2. 使用私鑰 (AT_SIGNATURE) 簽署雜湊
BYTE sig[256]; // 視金鑰長度而定
DWORD sigLen = sizeof(sig);
CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, sig, &sigLen);

// 3. 輸出:原始資料 + 簽章 + 演算法標識

驗證端 (持有公鑰)

// 1. 取得對方公開金鑰 (從憑證、金鑰 Blob 或 CSP 匯入)
HCRYPTKEY hPubKey;
CryptImportKey(hProv, pubKeyBlob, blobLen, 0, 0, &hPubKey);

// 2. 計算相同資料雜湊
CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash);
CryptHashData(hHash, data, dataLen, 0);

// 3. 驗證簽章
if (CryptVerifySignature(hHash, sig, sigLen, hPubKey, NULL, 0)) {
    printf("簽章驗證通過:資料完整且來源可信\n");
} else {
    printf("驗證失敗: 0x%08X\n", GetLastError());
    // NTE_BAD_SIGNATURE = 簽章不符 (資料被竄改或非持有私鑰者簽署)
}

CryptDestroyKey(hPubKey);
CryptDestroyHash(hHash);

六、Session Key 加密傳輸 (混合加密)

// 發送端
HCRYPTKEY hSessionKey;
CryptGenKey(hProv, CALG_AES_256, CRYPT_EXPORTABLE, &hSessionKey);

// 用對方公鑰加密 Session Key
BYTE keyBlob[1024];
DWORD blobLen = sizeof(keyBlob);
CryptExportKey(hSessionKey, hRecipientPubKey, SIMPLEBLOB, 0, keyBlob, &blobLen);

// 傳送:keyBlob + 用 Session Key 加密的資料

// 接收端
HCRYPTKEY hImportedSessionKey;
CryptImportKey(hProv, keyBlob, blobLen, hMyPrivateKey, 0, &hImportedSessionKey);
// 現在可用 hImportedSessionKey 解密資料

七、最佳實踐與遷移建議

⚠ CryptoAPI 狀態

  • Windows 2000 時代核心 API,已標記為 Legacy
  • 新專案強烈建議使用 CNG (Cryptography Next Generation):BCrypt*/NCrypt* API
  • CNG 支援現代演算法 (AES-GCM, ChaCha20-Poly1305, ECDSA, Ed25519)、硬體金鑰儲存 (TPM, KSP)、更佳效能與安全性

遷移對照

演算法CALG 常數輸出長度現代建議
MD5CALG_MD5128 bits已脆弱,僅用於非安全校驗
SHA-1CALG_SHA1160 bits理論碰撞風險,漸淘汰
SHA-256CALG_SHA_256256 bits推薦標準
SHA-384CALG_SHA_384384 bits高安全需求
SHA-512CALG_SHA_512512 bits最高安全需求
CryptoAPICNG
HCRYPTPROVBCRYPT_ALG_HANDLE / NCRYPT_KEY_HANDLE
CryptAcquireContextBCryptOpenAlgorithmProvider / NCryptOpenStorageProvider
CryptGenKeyBCryptGenerateSymmetricKey / NCryptCreatePersistedKey
CryptEncrypt/DecryptBCryptEncrypt/Decrypt
CryptSignHash/VerifySignatureBCryptSignHash/VerifySignature

結語

CryptoAPI 奠定了 Windows 加密基礎設施,理解其金鑰容器、雜湊、簽章、混合加密流程對維護舊系統至關重要。新開發專案請全面採用 CNG,享受現代密碼學標準與硬體加速優勢。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved