在64位平台上的Delphi中的CryptProtectData

时间:2018-12-16 11:02:22

标签: delphi delphi-xe7

我试图在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'

在后一种情况下,程序有时会挂起。

代码有什么问题?

0 个答案:

没有答案