基本介紹
- 中文名:CryptoAPI
- 全稱:加密應用程式接口
- 提供商:Microsoft
- 功能:加密
- 性質:一組函式
加密算法簡介,加密流程,套用,套用舉例,其他信息,
加密算法簡介
因為過於複雜的加密算法實現起來非常困難,所以在過去,許多應用程式只能使用非常簡單的加密技術,這樣做的結果就是加密的數據很容易就可以被人破譯。而使用Microsoft提供的加密應用程式接口(即Cryptography API),或稱CryptoAPI,就可以方便地在應用程式中加入強大的加密功能,而不必考慮基本的算法。本文將對CryptoAPI及其使用的數據加密原理作一簡單的介紹,然後給出了用CryptoAPI編寫加密程式的大致步驟,最後以一個檔案的加密、解密程式為例演示了CryptoAPI的部分功能。
CryptoAPI是一組函式,為了完成數學計算,必須具有密碼服務提供者模組(CSP)。Microsoft通過捆綁RSA Base Provider在作業系統級提供一個CSP,使用RSA公司的公鑰加密算法,更多的CSP可以根據需要增加到套用中。事實上,CSP有可能與特殊硬體設備(如智慧卡)一起來進行數據加密。CryptoAPI接口允許簡單的函式調用來加密數據,交換公鑰,散列一個訊息來建立摘要以及生成數字簽名。它還提供高級的管理操作,如從一組可能的CSP中使用一個CSP。此外,CryptoAPI還為許多高級安全性服務提供了基礎,包括用於電子商務的SET,用於加密客戶機/伺服器訊息的PCT,用於在各個平台之間來回傳遞機密數據和密鑰的PFX,代碼簽名等等。CryptoAPI的體系結構如下圖:
目前支持CryptoAPI的Windows系統有:Windows 95 OSR2、Windows NT SP3及後續版本、Windows 98、Windows 2000等。CryptoAPI的配置信息存儲在註冊表中,包括如下密鑰:
HKEY_LOCAL_MACHINE\SOFTWARE\
Microsoft Cryptography Defaults
HKEY_CURRENT_USER Software Microsoft
Cryptography Providers2.數據加密原理
加密流程
數據加密的流程
數據加密的流程如下圖:
CryptoAPI使用兩種密鑰:會話密鑰與公共/私人密鑰對。會話密鑰使用相同的加密和解密密鑰,這種算法較快,但必須保證密鑰的安全傳遞。公共/私人密鑰對使用一個公共密鑰和一個私人密鑰,私人密鑰只有專人才能使用,公共密鑰可以廣泛傳播。如果密鑰對中的一個用於加密,另一個一定用於解密。公共/私人密鑰對算法很慢,一般只用於加密小批數據,例如用於加密會話密鑰。
CryptoAPI支持兩種基本的編碼方法:流式編碼和塊編碼。流式編碼在明碼文本的每一位上創建編碼位,速度較快,但安全性較低。塊編碼在一個完整的塊上(一般為64位)工作,需要使用填充的方法對要編碼的數據進行捨入,以組成多個完整的塊。這種算法速度較慢,但更安全。
套用
CryptoAPI函式使用“加密服務提供者”(CSP)完成數據加密、解密以及密鑰的存儲管理、所有的CSP都是相互獨立的模組。理論上,CSP應該獨立於特定的應用程式,也就是說所有的應用程式可以使用任何一個CSP。但是,實際上有些應用程式只能與特定的CSP協作。CSP與應用程式之間的關係類似於Windows GDI模型。CSP就類似於圖形硬體驅動程式。
密鑰存儲的安全性完全取決於CSP的具體實現和作業系統沒有任何關係。這就使得應用程式無需修改就可以運行於多種安全環境之下。
應用程式於機密模組之間的訪問控制必須受到嚴格的控制。只要這樣才能保證套用的安全性和移植性。要遵循以下三條原則:
2)、應用程式不能指定加密操作細節。CSP允許應用程式選擇進行加密或者簽名操作使用的算法類型,但是實際的操作完全由CSP內部進行控制。
3)、應用程式不處理用戶的信任憑證或其它身份鑑別數據。用戶的鑑別是由CSP完成的。因此,對於未來可能出現的身份驗證方式,例如人體識別技術,應用程式無需修改其身份驗證的模型。
套用舉例
3.套用舉例
①檔案加密
#include < windows.h >
#include < stdio.h >
#include < stdlib.h >
#include < wincrypt.h >
//確定使用RC2塊編碼或是RC4流式編碼
#ifdef USE_BLOCK_CIPHER
#define ENCRYPT_ALGORITHMCALG_RC2
#define ENCRYPT_BLOCK_SIZE8
#else
#define ENCRYPT_ALGORITHMCALG_RC4
#define ENCRYPT_BLOCK_SIZE1
#endif
void CAPIEncryptFile(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 > [ < password > ]
");
exit(1);
}
//讀取參數.
szSource = argv[1];
szDestination = argv[2];
if(argc == 4) {
szPassword = argv[3];
}
CAPIEncryptFile(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
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(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
");
……//關閉檔案、釋放記憶體
}
②檔案解密
void CAPIDecryptFile(PCHAR szSource, PCHAR
szDestination, PCHAR szPassword)
{
……//變數聲明、檔案操作同檔案加密程式
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);
if(szPassword == NULL) {
// 口令為空,使用存儲在加密檔案中的會話密鑰解密
// 讀隱碼的長度並分配記憶體
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);