我试图在Windows 10的Delphi XE7中使用CryptProtectData。我以David's answer为基础。
该代码在32位平台上编译时有效,但我无法在64位平台上运行(符合要求,但我遇到运行时错误)。
这是代码(我稍微更改了David的代码以使用pOptionalEntropy参数):
unit Unit1;
interface
uses
System.SysUtils, Winapi.Windows;
const
CRYPTPROTECT_LOCAL_MACHINE = 4;
type
TLargeByteArray = array [0 .. Pred(MaxInt)] of byte;
PLargeByteArray = ^TLargeByteArray;
_CRYPTOAPI_BLOB = record
cbData: DWORD;
pbData: PByte;
end;
DATA_BLOB = _CRYPTOAPI_BLOB;
PDATA_BLOB = ^DATA_BLOB;
type
_CRYPTPROTECT_PROMPTSTRUCT = record
cbSize: DWORD;
dwPromptFlags: DWORD;
hwndApp: HWND;
szPrompt: PWideChar;
end;
CRYPTPROTECT_PROMPTSTRUCT = _CRYPTPROTECT_PROMPTSTRUCT;
PCRYPTPROTECT_PROMPTSTRUCT = ^CRYPTPROTECT_PROMPTSTRUCT;
function CryptProtectData(pDataIn: PDATA_BLOB;
szDataDescr: PWideChar; pOptionalEntropy: PDATA_BLOB;
pReserved: Pointer; pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD;
pDataOut: PDATA_BLOB): BOOL; stdcall; external 'Crypt32.dll';
function CryptUnprotectData(pDataIn: PDATA_BLOB; ppszDataDescr: PPWideChar;
pOptionalEntropy: PDATA_BLOB; pReserved: Pointer;
pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD;
pDataOut: PDATA_BLOB): BOOL; stdcall; external 'Crypt32.dll';
function EncryptData(const AStr: String; const AdditionalEntropy: string): string;
implementation
procedure FreeDataBlob(var Data: DATA_BLOB);
begin
if Assigned(Data.pbData) then
LocalFree(HLOCAL(Data.pbData));
FillChar(Data, SizeOf(DATA_BLOB), 0);
end;
function GetDataBlobText(Data: DATA_BLOB): string;
begin
SetString(Result, PChar(Data.pbData), Data.cbData div SizeOf(Char));
end;
function SetDataBlobText(const Text: string; var Data: DATA_BLOB): Boolean;
begin
FillChar(Data, SizeOf(DATA_BLOB), 0);
if Length(Text) > 0 then
begin
Data.cbData := SizeOf(Char) * Length(Text);
Data.pbData := Pointer(LocalAlloc(LPTR, Data.cbData));
if Assigned(Data.pbData) then
begin
Move(Pointer(Text)^, Data.pbData^, Data.cbData);
Result := True;
end
else
Result := False;
end
else
Result := True;
end;
function EncryptData(const AStr: String; const AdditionalEntropy: string): string;
var
DataIn: DATA_BLOB;
DataOut: DATA_BLOB;
DataEntropy: DATA_BLOB;
pDataEntropy: Pointer;
bRes: Boolean;
begin
if SetDataBlobText(AStr, DataIn) then
begin
DataOut.cbData := 0;
DataOut.pbData := nil;
try
pDataEntropy := nil;
if AdditionalEntropy <> '' then
begin
if not SetDataBlobText(AdditionalEntropy, DataEntropy) then
Exit;
pDataEntropy := @DataEntropy;
end;
try
FillChar(DataOut, SizeOf(DATA_BLOB), 0);
bRes := CryptProtectData(
@DataIn,
nil, //data description (PWideChar)
pDataEntropy, //optional entropy (PDATA_BLOB)
nil, //reserved
nil, //prompt struct
CRYPTPROTECT_LOCAL_MACHINE, //flags
@DataOut
);
if bRes then
begin
Result := GetDataBlobText(DataOut);
FreeDataBlob(DataOut);
end
else
RaiseLastOSError;
finally
if pDataEntropy <> nil then
FreeDataBlob(DataEntropy);
end;
finally
FreeDataBlob(DataIn);
end;
end;
end;
end.
当AdditionalEntropy常量不为空时,我在CryptProtectData中填充熵参数,但是CryptProtectData返回False,并且最后一个操作系统错误如下:
'c0000005 ACCESS_VIOLATION'
当AdditionalEntropy常量为空时,我将nil传递给CryptProtectData的第三个参数,这一次我得到了
'System Error. Code: 87. The parameter is incorrect'
在后一种情况下,程序有时会挂起。
代码有什么问题?