從Win2000開始,操作系統提供一個名爲Data Protection API (DPAPI)的數據保護接口。 該接口一共有兩個函數,他們提供了系統級的數據保護服務。這兩個函數存在於Crypt32.dll庫中,是CryptAPI的一部分。
DPAPI可以實現基於口令的數據加密和解密。也就是說我們提供一個口令用於加密,而其他人只有知道這個口令才能解密。
您可以訪問http://support.microsoft.com/kb/309408/zh-cn來了解DPAPI的詳細信息。
#include <windows.h>
#include <wincrypt.h>
DWORD MyEncryptFile(LPCSTR FileName,LPCSTR OutputFileName,LPCSTR Password);
DWORD MyDecryptFile(LPCSTR FileName,LPCSTR OutputFileName,LPCSTR Password);
void PrintUsage();
int main(int argc,char *argv[])
{
//Command Line: dpapi <e/d> <filename> <output filename> <password>
if(argc<4 || argc>5){
PrintUsage();
return 0;
}
char *FileName=argv[2];
char *OutputFileName=argv[3];
char *Password=NULL;
if(argc==5)Password=argv[4];
DWORD rc=0;
if(argv[1][0]=='e'){ //Encrypt
rc=MyEncryptFile(FileName,OutputFileName,Password);
if(rc!=0){
printf("Can't encrypt the file '%s',error code:%d. ",FileName,rc);
return 0;
}
printf("encrypt successfully! ");
}else{ //Decrypt
rc=MyDecryptFile(FileName,OutputFileName,Password);
if(rc!=0){
printf("Can't decrypt the file '%s',error code:%d. ",FileName,rc);
return 0;
}
printf("decrypt successfully! ");
}
return 0;
}
//Encrypt function
DWORD MyEncryptFile(LPCSTR FileName,LPCSTR OutputFileName,LPCSTR Password)
{
HANDLE hFile=NULL;
DWORD FileLen=0;
BYTE *FileData=NULL;
DATA_BLOB DataIn;
DATA_BLOB DataOut;
DATA_BLOB DataPwd;
DATA_BLOB *pDataPwd=NULL;
ZeroMemory(&DataIn,sizeof(DATA_BLOB));
ZeroMemory(&DataOut,sizeof(DATA_BLOB));
ZeroMemory(&DataPwd,sizeof(DATA_BLOB));
if(Password!=NULL){
DataPwd.cbData=strlen(Password);
DataPwd.pbData=(BYTE*)Password;
pDataPwd=&DataPwd;
}
try{
hFile=CreateFile(FileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)throw "";
FileLen=GetFileSize(hFile,NULL);
FileData=new BYTE[FileLen];
if(FileData==NULL)throw "";
ReadFile(hFile,FileData,FileLen,&FileLen,NULL);
CloseHandle(hFile);
hFile=NULL;
DataIn.pbData=FileData;
DataIn.cbData=FileLen;
if(!CryptProtectData(
&DataIn,
L"This is the description string.", // A description sting.
pDataPwd, // Optional entropy not used.
NULL, // Reserved.
NULL, // Pass a PromptStruct.
0,
&DataOut))
{
throw "";
}
delete[] FileData;
FileData=NULL;
hFile=CreateFile(OutputFileName,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)throw "";
WriteFile(hFile,DataOut.pbData,DataOut.cbData,&FileLen,NULL);
CloseHandle(hFile);
hFile=NULL;
LocalFree(DataOut.pbData);
ZeroMemory(&DataOut,sizeof(DataOut));
}catch(...){
if(hFile)CloseHandle(hFile);
if(FileData)delete[] FileData;
if(DataOut.pbData)LocalFree(DataOut.pbData);
return GetLastError();
}
return 0;
}
//Decrypt function
DWORD MyDecryptFile(LPCSTR FileName,LPCSTR OutputFileName,LPCSTR Password)
{
HANDLE hFile=NULL;
DWORD FileLen=0;
BYTE *FileData=NULL;
DATA_BLOB DataIn;
DATA_BLOB DataOut;
DATA_BLOB DataPwd;
DATA_BLOB *pDataPwd=NULL;
ZeroMemory(&DataIn,sizeof(DATA_BLOB));
ZeroMemory(&DataOut,sizeof(DATA_BLOB));
ZeroMemory(&DataPwd,sizeof(DATA_BLOB));
if(Password!=NULL){
DataPwd.cbData=strlen(Password);
DataPwd.pbData=(BYTE*)Password;
pDataPwd=&DataPwd;
}
try{
hFile=CreateFile(FileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)throw "";
FileLen=GetFileSize(hFile,NULL);
FileData=new BYTE[FileLen];
if(FileData==NULL)throw "";
ReadFile(hFile,FileData,FileLen,&FileLen,NULL);
CloseHandle(hFile);
hFile=NULL;
DataIn.pbData=FileData;
DataIn.cbData=FileLen;
if(!CryptUnprotectData(
&DataIn,
NULL,
pDataPwd, // Optional entropy
NULL, // Reserved
NULL, // Optional PromptStruct
0,
&DataOut))
{
throw "";
}
delete[] FileData;
FileData=NULL;
hFile=CreateFile(OutputFileName,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)throw "";
WriteFile(hFile,DataOut.pbData,DataOut.cbData,&FileLen,NULL);
CloseHandle(hFile);
hFile=NULL;
LocalFree(DataOut.pbData);
ZeroMemory(&DataOut,sizeof(DataOut));
}catch(...){
if(hFile)CloseHandle(hFile);
if(FileData)delete[] FileData;
if(DataOut.pbData)LocalFree(DataOut.pbData);
return GetLastError();
}
return 0;
}
void PrintUsage()
{
printf("Usage: dpapi <e/d> <filename> <output filename> [password] ");
printf(" e encrypt file ");
printf(" d decrypt file ");
}
#include <wincrypt.h>
DWORD MyEncryptFile(LPCSTR FileName,LPCSTR OutputFileName,LPCSTR Password);
DWORD MyDecryptFile(LPCSTR FileName,LPCSTR OutputFileName,LPCSTR Password);
void PrintUsage();
int main(int argc,char *argv[])
{
//Command Line: dpapi <e/d> <filename> <output filename> <password>
if(argc<4 || argc>5){
PrintUsage();
return 0;
}
char *FileName=argv[2];
char *OutputFileName=argv[3];
char *Password=NULL;
if(argc==5)Password=argv[4];
DWORD rc=0;
if(argv[1][0]=='e'){ //Encrypt
rc=MyEncryptFile(FileName,OutputFileName,Password);
if(rc!=0){
printf("Can't encrypt the file '%s',error code:%d. ",FileName,rc);
return 0;
}
printf("encrypt successfully! ");
}else{ //Decrypt
rc=MyDecryptFile(FileName,OutputFileName,Password);
if(rc!=0){
printf("Can't decrypt the file '%s',error code:%d. ",FileName,rc);
return 0;
}
printf("decrypt successfully! ");
}
return 0;
}
//Encrypt function
DWORD MyEncryptFile(LPCSTR FileName,LPCSTR OutputFileName,LPCSTR Password)
{
HANDLE hFile=NULL;
DWORD FileLen=0;
BYTE *FileData=NULL;
DATA_BLOB DataIn;
DATA_BLOB DataOut;
DATA_BLOB DataPwd;
DATA_BLOB *pDataPwd=NULL;
ZeroMemory(&DataIn,sizeof(DATA_BLOB));
ZeroMemory(&DataOut,sizeof(DATA_BLOB));
ZeroMemory(&DataPwd,sizeof(DATA_BLOB));
if(Password!=NULL){
DataPwd.cbData=strlen(Password);
DataPwd.pbData=(BYTE*)Password;
pDataPwd=&DataPwd;
}
try{
hFile=CreateFile(FileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)throw "";
FileLen=GetFileSize(hFile,NULL);
FileData=new BYTE[FileLen];
if(FileData==NULL)throw "";
ReadFile(hFile,FileData,FileLen,&FileLen,NULL);
CloseHandle(hFile);
hFile=NULL;
DataIn.pbData=FileData;
DataIn.cbData=FileLen;
if(!CryptProtectData(
&DataIn,
L"This is the description string.", // A description sting.
pDataPwd, // Optional entropy not used.
NULL, // Reserved.
NULL, // Pass a PromptStruct.
0,
&DataOut))
{
throw "";
}
delete[] FileData;
FileData=NULL;
hFile=CreateFile(OutputFileName,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)throw "";
WriteFile(hFile,DataOut.pbData,DataOut.cbData,&FileLen,NULL);
CloseHandle(hFile);
hFile=NULL;
LocalFree(DataOut.pbData);
ZeroMemory(&DataOut,sizeof(DataOut));
}catch(...){
if(hFile)CloseHandle(hFile);
if(FileData)delete[] FileData;
if(DataOut.pbData)LocalFree(DataOut.pbData);
return GetLastError();
}
return 0;
}
//Decrypt function
DWORD MyDecryptFile(LPCSTR FileName,LPCSTR OutputFileName,LPCSTR Password)
{
HANDLE hFile=NULL;
DWORD FileLen=0;
BYTE *FileData=NULL;
DATA_BLOB DataIn;
DATA_BLOB DataOut;
DATA_BLOB DataPwd;
DATA_BLOB *pDataPwd=NULL;
ZeroMemory(&DataIn,sizeof(DATA_BLOB));
ZeroMemory(&DataOut,sizeof(DATA_BLOB));
ZeroMemory(&DataPwd,sizeof(DATA_BLOB));
if(Password!=NULL){
DataPwd.cbData=strlen(Password);
DataPwd.pbData=(BYTE*)Password;
pDataPwd=&DataPwd;
}
try{
hFile=CreateFile(FileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)throw "";
FileLen=GetFileSize(hFile,NULL);
FileData=new BYTE[FileLen];
if(FileData==NULL)throw "";
ReadFile(hFile,FileData,FileLen,&FileLen,NULL);
CloseHandle(hFile);
hFile=NULL;
DataIn.pbData=FileData;
DataIn.cbData=FileLen;
if(!CryptUnprotectData(
&DataIn,
NULL,
pDataPwd, // Optional entropy
NULL, // Reserved
NULL, // Optional PromptStruct
0,
&DataOut))
{
throw "";
}
delete[] FileData;
FileData=NULL;
hFile=CreateFile(OutputFileName,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)throw "";
WriteFile(hFile,DataOut.pbData,DataOut.cbData,&FileLen,NULL);
CloseHandle(hFile);
hFile=NULL;
LocalFree(DataOut.pbData);
ZeroMemory(&DataOut,sizeof(DataOut));
}catch(...){
if(hFile)CloseHandle(hFile);
if(FileData)delete[] FileData;
if(DataOut.pbData)LocalFree(DataOut.pbData);
return GetLastError();
}
return 0;
}
void PrintUsage()
{
printf("Usage: dpapi <e/d> <filename> <output filename> [password] ");
printf(" e encrypt file ");
printf(" d decrypt file ");
}
參數szDataDescr是一個字串,可以是關於加密的描述信息或其他的任何信息,但不能爲NULL,該信息將以明文的方式存在於最終輸出的密文數據中。
參數pOptionalEntropy用於額外的密碼保護。
參數pPromptStruct用於指定一個安全提示對話框,在加密解密操作時,將彈出該對話框提示用戶正在進行安全操作。如果該參數爲NULL,則不會彈出對話框。這裏就不在列出CRYPTPROTECT_PROMPTSTRUCT結構的詳細定義,你可以查閱MSDN的相關內容。後面的程序將把該參數設置爲NULL;
參數dwFlags是關於加密的一些選項標誌,一般設置爲0就可以了,詳細的說明請參閱MSDN的相關內容;
參數pDataOut是輸出數據,同樣是一個DATA_BLOB結構,但應該注意的是pDataOut->pbData所指向的內存是由系統分配的,在使用完輸出數據後應該用LocalFree函數釋放該內存。
DPAPI解密函數
BOOL WINAPI CryptUnprotectData (
[IN] DATA_BLOB *pDataIn, //輸入數據,密文
[OUT] LPCWSTR *ppszDataDescr, //輸出描述信息
[IN] DATA_BLOB *pOptionalEntropy, //額外的保護信息
[IN] PVOID pvReserved, //保留參數,必須爲NULL
[IN] CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, //提示對話框結構
[IN] DWORD dwFlags, //標誌位
[OUT] DATA_BLOB *pDataOut //輸出數據,明文
);
解密函數的參數與加密函數的參數基本類似,唯一需要指出的是參數ppszDataDescr在這裏應該被指定爲一個指針變量,在解密完成後,該變量將指向加密時指定的描述信息,最後應該使用LocalFree函數釋放該字串。如果你不想得到描述信息,可以將該參數設置爲NULL。
DPAPI和系統帳戶聯繫仍然十分緊密,他會自動使用當前用戶的系統登錄口令作爲加解密的口令,這樣一來同一臺機器的所有程序都可以解密其他程序加密的數據。爲了防止這一點,函數提供了pOptionalEntropy參數,使我們有機會使用自己的口令。如果提供了pOptionalEntropy參數,DPAPI將使用當前用戶系統登錄口令和我們提供的額外保護口令的組合進行加解密操作。如果你不想使用額外口令保護,則可設置該參數爲NULL。
因爲DPAPI使用用戶帳戶聯繫的,所以一臺機器上加密的數據,一般不能在另一臺機器上解密
BOOL WINAPI CryptUnprotectData (
[IN] DATA_BLOB *pDataIn, //輸入數據,密文
[OUT] LPCWSTR *ppszDataDescr, //輸出描述信息
[IN] DATA_BLOB *pOptionalEntropy, //額外的保護信息
[IN] PVOID pvReserved, //保留參數,必須爲NULL
[IN] CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, //提示對話框結構
[IN] DWORD dwFlags, //標誌位
[OUT] DATA_BLOB *pDataOut //輸出數據,明文
);
解密函數的參數與加密函數的參數基本類似,唯一需要指出的是參數ppszDataDescr在這裏應該被指定爲一個指針變量,在解密完成後,該變量將指向加密時指定的描述信息,最後應該使用LocalFree函數釋放該字串。如果你不想得到描述信息,可以將該參數設置爲NULL。
DPAPI和系統帳戶聯繫仍然十分緊密,他會自動使用當前用戶的系統登錄口令作爲加解密的口令,這樣一來同一臺機器的所有程序都可以解密其他程序加密的數據。爲了防止這一點,函數提供了pOptionalEntropy參數,使我們有機會使用自己的口令。如果提供了pOptionalEntropy參數,DPAPI將使用當前用戶系統登錄口令和我們提供的額外保護口令的組合進行加解密操作。如果你不想使用額外口令保護,則可設置該參數爲NULL。
因爲DPAPI使用用戶帳戶聯繫的,所以一臺機器上加密的數據,一般不能在另一臺機器上解密
DPAPI加密函數
BOOL WINAPI CryptProtectData (
[IN] DATA_BLOB *pDataIn, //輸入數據,明文
[IN] LPCWSTR szDataDescr, //描述信息
[IN] DATA_BLOB *pOptionalEntropy, //額外的保護信息
[IN] PVOID pvReserved, //保留參數,必須爲NULL
[IN] CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, //提示對話框結構
[IN] DWORD dwFlags, //標誌位
[OUT] DATA_BLOB *pDataOut //輸出數據,密文
);
輸入數據參數pDataIn是一個DATA_BLOB結構,該結構的定義如下:
typedef struct _CRYPTOAPI_BLOB {
DWORD cbData; //數據的長度
BYTE* pbData; //指向數據的指針
}DATA_BLOB;
BOOL WINAPI CryptProtectData (
[IN] DATA_BLOB *pDataIn, //輸入數據,明文
[IN] LPCWSTR szDataDescr, //描述信息
[IN] DATA_BLOB *pOptionalEntropy, //額外的保護信息
[IN] PVOID pvReserved, //保留參數,必須爲NULL
[IN] CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, //提示對話框結構
[IN] DWORD dwFlags, //標誌位
[OUT] DATA_BLOB *pDataOut //輸出數據,密文
);
輸入數據參數pDataIn是一個DATA_BLOB結構,該結構的定義如下:
typedef struct _CRYPTOAPI_BLOB {
DWORD cbData; //數據的長度
BYTE* pbData; //指向數據的指針
}DATA_BLOB;