1. 程式人生 > >簡單實現強大的加密功能——CryptoAPI

簡單實現強大的加密功能——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環境中編譯通過。