使用CryptProtectData&在Delphi中的CryptUnprotectData [英] Use CryptProtectData & CryptUnprotectData in Delphi

查看:169
本文介绍了使用CryptProtectData&在Delphi中的CryptUnprotectData的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要使用 CryptUnprotectData & Crypt32.dll 中的 CryptProtectData

I want to use CryptUnprotectData & CryptProtectData in Crypt32.dll.

我的代码是:

unit Unit1;

interface

uses   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type   TForm1 = class(TForm)
    btn1: TButton;
    btn2: TButton;
    edt1: TEdit;
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);   private
    { Private declarations }   public
    { Public declarations }   end;

var   Form1: TForm1; const CRYPTPROTECT_LOCAL_MACHINE = 4 ;

type   TLargeByteArray = array [0..Pred(MaxInt)] of byte;   PLargeByteArray = ^TLargeByteArray;

  _CRYPTOAPI_BLOB = packed record
    cbData: DWORD;
    pbData: PByte;   end;   TCryptoApiBlob     = _CRYPTOAPI_BLOB;   PCrypyoApiBlob     = ^TCryptoApiBlob;   CRYPT_INTEGER_BLOB =
_CRYPTOAPI_BLOB;   PCRYPT_INTEGER_BLOB = ^CRYPT_INTEGER_BLOB;   CRYPT_UINT_BLOB    = _CRYPTOAPI_BLOB;   PCRYPT_UINT_BLOB   = ^CRYPT_INTEGER_BLOB;   CRYPT_OBJID_BLOB   = _CRYPTOAPI_BLOB;   PCRYPT_OBJID_BLOB  = ^CRYPT_INTEGER_BLOB;   CERT_NAME_BLOB     =
_CRYPTOAPI_BLOB;   PCERT_NAME_BLOB    = ^CRYPT_INTEGER_BLOB;   CERT_RDN_VALUE_BLOB = _CRYPTOAPI_BLOB;   PCERT_RDN_VALUE_BLOB = ^CRYPT_INTEGER_BLOB;   CERT_BLOB          = _CRYPTOAPI_BLOB;   PCERT_BLOB         = ^CRYPT_INTEGER_BLOB;   CRL_BLOB           =
_CRYPTOAPI_BLOB;   PCRL_BLOB          = ^CRYPT_INTEGER_BLOB;   DATA_BLOB          = _CRYPTOAPI_BLOB;   PDATA_BLOB         = ^CRYPT_INTEGER_BLOB;   CRYPT_DATA_BLOB    = _CRYPTOAPI_BLOB;   PCRYPT_DATA_BLOB   = ^CRYPT_INTEGER_BLOB;   CRYPT_HASH_BLOB    =
_CRYPTOAPI_BLOB;   PCRYPT_HASH_BLOB   = ^CRYPT_INTEGER_BLOB;   CRYPT_DIGEST_BLOB  = _CRYPTOAPI_BLOB;   PCRYPT_DIGEST_BLOB = ^CRYPT_INTEGER_BLOB;   CRYPT_DER_BLOB     = _CRYPTOAPI_BLOB;   PCRYPT_DER_BLOB    = ^CRYPT_INTEGER_BLOB;   CRYPT_ATTR_BLOB    =
_CRYPTOAPI_BLOB;   PCRYPT_ATTR_BLOB   = ^CRYPT_INTEGER_BLOB;

type   _CRYPTPROTECT_PROMPTSTRUCT = packed record
    cbSize:        DWORD;
    dwPromptFlags: DWORD;
    hwndApp:       HWND;
    szPrompt:      LPCWSTR;   end;   TCryptProtectPromptStruct  = _CRYPTPROTECT_PROMPTSTRUCT;   PCryptProtectPromptStruct  = ^TCryptProtectPromptStruct;   CRYPTPROTECT_PROMPTSTRUCT  =
_CRYPTPROTECT_PROMPTSTRUCT;   PCRYPTPROTECT_PROMPTSTRUCT = ^_CRYPTPROTECT_PROMPTSTRUCT;

function CryptProtectData(pDataIn: PDATA_BLOB; szDataDescr: LPCWSTR {PWideChar}; pOptionalEntropy: PDATA_BLOB; pReserved: Pointer;   pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall; external 'Crypt32.dll';

function CryptUnprotectData(pDataIn: PDATA_BLOB; var ppszDataDescr: LPWSTR; pOptionalEntropy: PDATA_BLOB; pReserved: Pointer;   pPromptStruct: PCRYPTPROTECT_PROMPTSTRUCT; dwFlags: DWORD; pDataOut: PDATA_BLOB): BOOL; stdcall; external 'Crypt32.dll';

implementation {$R *.DFM}

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   if (Data.cbData > 0) and Assigned(Data.pbData) then
    SetString(Result, PChar(Data.pbData), Data.cbData)   else
    SetLength(Result, 0); end;

function SetDataBlobText(Text: string; var Data: DATA_BLOB): boolean; begin   FillChar(Data, SizeOf(DATA_BLOB), 0);   if (Length(Text) > 0) then   begin
    Data.pbData := Pointer(LocalAlloc(LPTR, Succ(Length(Text))));
    if Assigned(Data.pbData) then
    begin
      StrPCopy(PChar(Data.pbData), Text);
      Data.cbData := Length(Text);
      Result := True;
    end
    else
      Result := False;   end   else
    Result := True; end;






{============================================     }

function EncryptPassword(Password: string): string; var   DataIn: DATA_BLOB;   dwFlags: DWORD;   DataOut: PDATA_BLOB;   I: Integer;   P: PByte; begin   Result := '';   DataIn.cbData := Length(Password);   DataIn.pbData := Pointer(PChar(Password));   dwFlags := CRYPTPROTECT_LOCAL_MACHINE;   if CryptProtectData(@DataIn, 'Password', nil, nil, nil, dwFlags, DataOut) then   begin
    P := DataOut.pbData;
    I := DataOut.cbData;
    Result := IntToHex(I, 8);
    while (I > 0) do
    begin
      Dec(I);
      Result := Result + IntToHex(P^, 2);
      Inc(P);
    end;
    LocalFree(Cardinal(DataOut.pbData));   end; end;

function DecryptPassword(Password: string): string; var   DataIn: DATA_BLOB;   dwFlags: DWORD;   DataOut: PDATA_BLOB;   I, J: Integer;   P: PByte;   DataDescr: LPWSTR; begin   Result := '';   if (Length(Password) > 0) then   begin
    DataIn.cbData := StrToIntDef('$' + Copy(Password, 1, 8), 0);
    if (DataIn.cbData > 0) then
    begin
      GetMem(DataIn.pbData, DataIn.cbData);
      I := DataIn.cbData;
      J := 9;
      P := DataIn.pbData;
      while (I > 0) and (J < Length(Password)) do
      begin
        Dec(I);
        P^ := StrToInt('$' + Copy(Password, J, 2));
        Inc(P);
        Inc(J, 2);
      end;
      dwFlags := CRYPTPROTECT_LOCAL_MACHINE;
      if CryptUnprotectData(@DataIn, DataDescr, nil, nil, nil, dwFlags, DataOut) then
      begin
        Result := Copy(string(DataOut.pbData), 0, DataOut.cbData);
        LocalFree(Cardinal(DataOut.pbData));
      end;
    end;   end; end;

procedure TForm1.btn1Click(Sender: TObject); var   DataIn:  DATA_BLOB; DataOut: DATA_BLOB;   DataCheck: DATA_BLOB;   lpwszDesc: PWideChar; begin   FillChar(DataIn, SizeOf(DATA_BLOB), 0);   FillChar(DataOut, SizeOf(DATA_BLOB), 0);   FillChar(DataCheck, SizeOf(DATA_BLOB), 0);   if SetDataBlobText('Hello world this is a test!', DataIn) then   begin
    try
      if CryptProtectData(@DataIn, PWideChar(WideString('Hello Test')), nil, nil, nil, 0, @DataOut) then
      begin
        MessageBox(0, PChar(GetDataBlobText(DataOut)), PChar(Format('%d bytes returned', [DataOut.cbData])), MB_OK or MB_ICONINFORMATION);
        try
          if CryptUnprotectData(@DataOut, lpwszDesc, nil, nil, nil, 0, @DataCheck) then
          begin
            try
              MessageBox(0, PChar(GetDataBlobText(DataCheck)), PChar(string(WideString(lpwszDesc))), MB_OK or MB_ICONINFORMATION);
            finally
              LocalFree(HLOCAL(lpwszDesc));
              FreeDataBlob(DataCheck);
            end;
          end;
        finally
          FreeDataBlob(DataIn);
        end;
      end;
    finally
      FreeDataBlob(DataIn);
    end;   end;

end;

procedure TForm1.btn2Click(Sender: TObject); begin   ShowMessage(DecryptPassword(edt1.Text)); end;

end.

但是我在2个按钮中有错误,无法获取真实的字符串。

But I have error in 2 buttons and cant get the real string.

btn1错误:

---------------------------
Project1
---------------------------
Access violation at address 76F2E23E in module 'ntdll.dll'. Read of address 22481A56.
---------------------------
OK   
---------------------------

btn2解密后显示null并显示此错误:

btn2 after decrypt show null and show me this error :

---------------------------
Project1
---------------------------
Access violation at address 00000000. Read of address 00000000.
---------------------------
OK   
---------------------------

有什么问题?

推荐答案

您的代码已格式化,因此几乎无法阅读和分析。如果格式更好,那么我认为您会得到更全面的答案。我可以看到以下内容:

Your code is formatted so that it is next to impossible to read and analyse. If it was better formatted then I think you'd get more comprehensive answers. Here's what I can see:


  1. 记录不应该打包。

  2. 第二个参数 CryptUnprotectData 不应是var参数。通过将其设置为 var 参数,您可以强制自己传递它。由于不想使用它,因此应将其声明为指向 PWideChar 的指针,以便可以选择不使用它。

  3. btn1Click 中,您没有为 lpwszDesc 分配任何内容。更重要的是,您随后将其传递给 LocalFree

  4. 您正在使用Unicode Delphi,因此没有理由使用 WideString 在这里。只需将已经为UTF-16的字符串转换为 PWideChar

  5. 您不允许在Unicode Delphi中 SizeOf(Char)为2的事实。因此,您对 cbData 的处理是错误的。

  6. DecryptPassword 传递了一个统一指针到 CryptUnprotectData

  7. DecryptPassword 泄漏使用<$ c $分配的内存c> GetMem 。

  8. 我真的不知道 DecryptPassword 试图做什么,但这是显然坏了。我无法解决,因为我不知道您的目标是什么。

  1. The records should not be packed.
  2. The second parameter to CryptUnprotectData should not be a var parameter. By making it a var parameter you force yourself to pass it. Since you don't want to use it, you should declare it as a pointer to PWideChar so that you can opt not to use it.
  3. In btn1Click you did not assign anything to lpwszDesc. What's more you then passed it to LocalFree.
  4. You are using a Unicode Delphi and so have no reason to use WideString here. Simply cast a string, which is already UTF-16, to PWideChar.
  5. You are not allowing for the fact that SizeOf(Char) is 2 in your Unicode Delphi. So your treatment of cbData in wrong.
  6. DecryptPassword passed an unitialised pointer to CryptUnprotectData.
  7. DecryptPassword leaks the memory allocated with GetMem.
  8. I don't really know what DecryptPassword is attempting to do, but it's clearly broken. I can't fix it since I've no idea what your goals are.






但是,我敢肯定会有更多问题。我为您提供一些一般性建议。问题中有太多代码。您应尽可能删除。您应该使用尽可能小的 SSCCE 。这应该是一个简单的控制台应用程序。该代码应格式化为可读的,并且最好不要诉诸于水平滚动。


However, I'm sure there are more problems. I have some general advice for you. There is too much code in the question. You should remove as much as possible. You should make the smallest possible SSCCE. This should be a simple console application. The code should be formatted to be readable, and preferably without resort to horizontal scrolling. This will help you as much as it helps us.

重点是您在寻找错误。如果您将代码缩减为尽可能简单,那么检查的内容就更少了。如果代码清晰可见且布局整洁,则检查起来会更容易。

The point is that you are searching for errors. If you cut the code down to be as simple as possible, then there is less to check. If the code is visible and layed out neatly, it is easier to check.

除了正确地处理特定细节外,了解如何编写代码的一般原则也是如此。

As much as getting the specific details right, the general principle of knowing how to make your code readable and concise is much more important here.

所以,为了向您展示我的意思,这是将您的原始帖子转换为SSCCE,其中包含许多已修复错误:

So, just to show you what I mean, here is your original post converted into an SSCCE, and with a number of the bugs fixed:

program SO17823083;

{$APPTYPE CONSOLE}

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';

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 DecryptPassword(Password: string): string;
var
  DataIn: DATA_BLOB;
  dwFlags: DWORD;
  DataOut: DATA_BLOB;
  I, J: Integer;
  P: PByte;
begin
  Result := '';
  if (Length(Password) > 0) then
  begin
    DataIn.cbData := StrToIntDef('$' + Copy(Password, 1, 8), 0);
    if (DataIn.cbData > 0) then
    begin
      GetMem(DataIn.pbData, DataIn.cbData);
      I := DataIn.cbData;
      J := 9;
      P := DataIn.pbData;
      while (I > 0) and (J < Length(Password)) do
      begin
        Dec(I);
        P^ := StrToInt('$' + Copy(Password, J, 2));
        Inc(P);
        Inc(J, 2);
      end;
      dwFlags := CRYPTPROTECT_LOCAL_MACHINE;
      if CryptUnprotectData(@DataIn, nil, nil, nil, nil, dwFlags, @DataOut)
      then
      begin
        Result := GetDataBlobText(DataOut);
        LocalFree(Cardinal(DataOut.pbData));
      end;
      FreeMem(DataIn.pbData);
    end;
  end;
end;

procedure Test1;
var
  DataIn: DATA_BLOB;
  DataOut: DATA_BLOB;
  DataCheck: DATA_BLOB;
begin
  if SetDataBlobText('Hello world this is a test!', DataIn) then
  begin
    try
      if CryptProtectData(@DataIn, PChar('Hello Test'), nil,
        nil, nil, 0, @DataOut) then
      begin
        Writeln(GetDataBlobText(DataOut));
        Writeln(Format('%d bytes returned', [DataOut.cbData]));
        try
          if CryptUnprotectData(@DataOut, nil, nil, nil, nil, 0,
            @DataCheck) then
          begin
            try
              Writeln(GetDataBlobText(DataCheck));
            finally
              FreeDataBlob(DataCheck);
            end;
          end;
        finally
          FreeDataBlob(DataIn);
        end;
      end;
    finally
      FreeDataBlob(DataIn);
    end;
  end;
end;

procedure Test2;
begin
  Writeln(DecryptPassword('1111'));
end;

begin
  try
    Test1;
    Test2;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

我使用Delphi IDE的代码格式化功能将代码布置为可读的样式。然后,我将其转换为控制台应用程序,以便您拥有包含整个程序的单个文件。

I used the code formatting feature of the Delphi IDE to lay the code out in a readable style. And I converted it to a console application so that you have a single file that contains the entire program.

此版本至少可以运行并且不会引发访问冲突。现在,由您决定实际执行您想做的事情。

This version does at least run and not raise access violations. Now it's up to you to make it actually do what you want it to do.

这篇关于使用CryptProtectData&amp;在Delphi中的CryptUnprotectData的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆