簡單實現強大的加密功能——CryptoAPI
CryptoAPI是Microsoft提供的加密應用程式介面,他其實是一組函式,他為許多高階安全性服務提供了基礎,包括用於電子商務的SET,用於加密客戶機/伺服器訊息的PCT,用於在各個平臺之間來回傳遞機密資料和金鑰的PFX,程式碼簽名等等。
支援這種功能的主要有2000/XP(98和ME下不詳)
其配置資訊(金鑰)主要在
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft
\ Cryptography \Defaults
HKEY_CURRENT_USER\ Software \ Microsoft
\ Cryptography \Providers
中,
下面以兩個檔案加密與解密的C程式片斷為例,演示一下CryptoAPI的強大功能。這兩個程式均為Win32控制檯應用,程式省略了出錯處理,實際執行時請加入。
----1. 檔案加密
#include
#include
#include
#include
//確定使用RC2塊編碼或是RC4流式編碼,這就是CryptoAPI支援的兩種基本編碼方式
#ifdef USE_BLOCK_CIPHER
#define ENCRYPT_ALGORITHM CALG_RC2
#define ENCRYPT_BLOCK_SIZE 8
#else
#define ENCRYPT_ALGORITHM CALG_RC4
#define ENCRYPT_BLOCK_SIZE 1
#endif
void CAPIDecryptFile(PCHAR szSource,
PCHAR szDestination, PCHAR szPassWord);
void _cdecl main(int argc, char *argv[])
{
PCHAR szSource = NULL;
PCHAR szDestination = NULL;
PCHAR szPassword = NULL;
// 驗證引數個數
if(argc != 3 && argc != 4) {
printf(“USAGE: decrypt < source file >
< dest file > [ ]\n");
exit(1);
}
//讀取引數.
szSource = argv[1];
szDestination = argv[2];
if(argc == 4) {
szPassword = argv[3];
}
CAPIDecryptFile(szSource, szDestination, szPassword);
}
/*szSource為要加密的檔名稱,
szDestination為加密過的檔名稱,
szPassword為加密口令*/
void CAPIEncryptFile(PCHAR szSource,
PCHAR szDestination, PCHAR szPassword)
{
FILE *hSource = NULL;
FILE *hDestination = NULL;
INT eof = 0;
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCRYPTKEY hXchgKey = 0;
HCRYPTHASH hHash = 0;
PBYTE pbKeyBlob = NULL;
DWORD dwKeyBlobLen;
PBYTE pbBuffer = NULL;
DWORD dwBlockLen;
DWORD dwBufferLen;
DWORD dwCount;
hSource= fopen(szSource,“rb"));// 開啟原始檔
hDestination = fopen(szDestination,“wb") ;//.開啟目標檔案
// 連線預設的CSP,密碼服務提供者模組(CSP),這是通過WIN系統中捆綁的RSA Base Provider實現的。
CryptAcquireContext(&hProv, NULL, NULL,
PROV_RSA_FULL, 0));
if(szPassword == NULL) {
//口令為空,使用隨機產生的會話金鑰加密
// 產生隨機會話金鑰。
CryptGenKey(hProv, ENCRYPT_ALGORITHM,
CRYPT_EXPORTABLE, &hKey)
// 取得金鑰交換對的公共金鑰
CryptGetUserKey(hProv, AT_KEYEXCHANGE,
&hXchgKey);
// 計算隱碼長度並分配緩衝區
CryptExportKey(hKey, hXchgKey,
SIMPLEBLOB, 0, NULL, &dwKeyBlobLen);
pbKeyBlob=malloc(dwKeyBlobLen)) == NULL) ;
// 將會話金鑰輸出至隱碼
CryptExportKey(hKey, hXchgKey,
SIMPLEBLOB, 0, pbKeyBlob, &dwKeyBlobLen));
// 釋放金鑰交換對的控制代碼
CryptDestroyKey(hXchgKey);
hXchgKey = 0;
// 將隱碼長度寫入目標檔案
fwrite(&dwKeyBlobLen, sizeof(DWORD), 1, hDestination);
//將隱碼長度寫入目標檔案
fwrite(pbKeyBlob,1,dwKeyBlobLen, hDestination);
} else {
//口令不為空, 使用從口令派生出的金鑰加密檔案
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
// 建立散列表
CryptHashData(hHash, szPassword, strlen(szPassword), 0);
//雜湊口令
// 從散列表中派生金鑰
CryptDeriveKey(hProv, ENCRYPT_ALGORITHM, hHash, 0, &hKey);
// 刪除散列表
CryptDestroyHash(hHash);
hHash = 0;
}
//計算一次加密的資料位元組數,
必須為ENCRYPT_BLOCK_SIZE的整數倍
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
//如果使用塊編碼,則需要額外空間
if(ENCRYPT_BLOCK_SIZE > 1) {
dwBufferLen=dwBlockLen + ENCRYPT_BLOCK_SIZE;
} else {
dwBufferLen = dwBlockLen;
}
//分配緩衝區
pbBuffer = malloc(dwBufferLen);
//加密原始檔並寫入目標檔案
do {
// 從原始檔中讀出dwBlockLen個位元組
dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);
eof = feof(hSource);
//加密資料
CryptEncrypt(hKey, 0, eof, 0, pbBuffer, &dwCount, dwBufferLen);
// 將加密過的資料寫入目標檔案
fwrite(pbBuffer, 1, dwCount, hDestination);
} while(!feof(hSource));
printf("OK\n");
......//關閉檔案、釋放記憶體
}
----2 檔案解密
void CAPIDecryptFile(PCHAR szSource,
PCHAR szDestination, PCHAR szPassword)
{
......//變數宣告、檔案操作同文件加密程式
CryptAcquireContext(&hProv, NULL, NULL,
PROV_RSA_FULL, 0);
if(szPassword == NULL) {
// 口令為空,使用儲存在加密檔案中的會話金鑰解密
// 讀隱碼的長度並分配記憶體
fread(&dwKeyBlobLen,sizeof(DWORD),1,hSource);
pbKeyBlob=malloc(dwKeyBlobLen))== NULL);
// 從原始檔中讀隱碼.
fread(pbKeyBlob, 1, dwKeyBlobLen, hSource);
// 將隱碼輸入CSP
CryptImportKey(hProv, pbKeyBlob,
dwKeyBlobLen, 0, 0, &hKey);
} else {
// 口令不為空, 使用從口令派生出的金鑰解密檔案
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);
CryptHashData(hHash, szPassword, strlen
(szPassword), 0);
CryptDeriveKey(hProv, ENCRYPT_ALGORITHM,
hHash, 0, &hKey);
CryptDestroyHash(hHash);
hHash = 0;
}
dwBlockLen=1000-1000%ENCRYPT_BLOCK_SIZE;
if(ENCRYPT_BLOCK_SIZE > 1) {
dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
} else {
dwBufferLen = dwBlockLen;
}
pbBuffer = malloc(dwBufferLen);
//解密原始檔並寫入目標檔案
do {
dwCount = fread(pbBuffer, 1, dwBlockLen,
hSource);
eof = feof(hSource);
// 解密資料
CryptDecrypt(hKey, 0, eof, 0, pbBuffer, &dwCount);
// 將解密過的資料寫入目標檔案
fwrite(pbBuffer, 1, dwCount, hDestination);
} while(!feof(hSource));
printf(“OK\n");
......//關閉檔案、釋放記憶體
}
----以上程式碼在windows 2000、Visual C++6.0環境中編譯通過。