分享
 
 
 

用DPAPI保护你的数据

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

用DPAPI保护你的数据

我们已经知道,用Win32API函数EncryptFile和DecryptFile可以方便的加解密文件。但是,这两个函数与系统帐户联系过于紧密,能否解密完全看当前帐户是否有更高的权限,用户的数据实际上并没有得到真正的保护。下面将介绍一种更为灵活的数据保护方法。

从Win2000开始,操作系统开始提供一个名为Data Protection API (DPAPI)的数据保护接口。该接口一共有两个函数,他们提供了系统级的数据保护服务。这两个函数存在于Crypt32.dll库中,是CryptAPI的一部分,但使用起来要比其他的CryptAPI函数简单得多。

DPAPI可以实现基于口令的数据加密和解密。也就是说我们提供一个口令用于加密,而其他人只有知道这个口令才能解密。实际上,DPAPI上在后台为我们完成了相当复杂的加密解密操作,包括密钥的产生、存储、使用等。本文只想介绍一下如何使用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;

参数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使用用户帐户联系的,所以一台机器上加密的数据,一般不能在另一台机器上解密(特殊情况请参阅MSDN相关内容)。

下面的程序利用DPAPI实现了文件的加密和解密,其中Password是可选的,但如果加密时使用了Password,那么解密时就必须提供相同的Password.。

/********************************************************

*DPAPI.EXE

*Encrypt and Decrypt file

*Wrote by WABC on 2002-5-20

********************************************************/

#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.\n",FileName,rc);

return 0;

}

printf("encrypt successfully!\n");

}else{ //Decrypt

rc=MyDecryptFile(FileName,OutputFileName,Password);

if(rc!=0){

printf("Can't decrypt the file '%s',error code:%d.\n",FileName,rc);

return 0;

}

printf("decrypt successfully!\n");

}

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]\n");

printf(" e encrypt file\n");

printf(" d decrypt file\n");

}

要想编译上面的程序,你必须首先下载一个PlatfromSDK(因为VC附带的Crypt32.lib导出库中没有DPAPI的函数说明,但操作系统的Crypt32.dll中确实存在DPAPI函数),然后把PlatformSDK中的Crypt32.lib加入到你的VC工程中,最后在VC工程中的stdafx.h中加入宏定义#define _WIN32_WINNT 0x500。

使用DPAPI应该注意以下几点:

1、加密和解密操作必须在同一台计算机上进行;

2、如果加密时提供了额外的口令保护,那么解密时必须提供相同的口令;

3、在DPAPI函数之后,一定要记着用LocalFree函数释放系统分配的内存;

4、DPAPI没有存储数据的机制,应用程序必须负责存储加密或解密后的数据。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有