从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 ");

}

参数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使用用户帐户联系的,所以一台机器上加密的数据,一般不能在另一台机器上解密
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;