-1

CryptUnprotectDataで&CryptProtectDataを使いたい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 つのボタンにエラーがあり、実際の文字列を取得できません。

btn1 エラー:

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

btn2 復号化した後、null を表示し、次のエラーを表示します。

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

問題は何ですか?

4

2 に答える 2

3

コードがフォーマットされているため、読み取りと分析がほぼ不可能です。より適切にフォーマットされていれば、より包括的な回答が得られると思います。ここに私が見ることができるものがあります:

  1. レコードはパックしないでください。
  2. の 2 番目のパラメーターCryptUnprotectDataは、var パラメーターであってはなりません。それをvarパラメーターにすることで、強制的に渡すことができます。使用したくないので、使用しPWideCharないことを選択できるように、へのポインターとして宣言する必要があります。
  3. ではbtn1Clickに何も割り当てていませんlpwszDesc。さらに、それを に渡しましたLocalFree
  4. Unicode Delphi を使用しているため、ここで使用する理由はありませんWideStringstringすでに UTF-16 になっている を にキャストするだけPWideCharです。
  5. SizeOf(Char)Unicode Delphi で 2 であることを認めていません。だからあなたの扱いはcbData間違っています。
  6. DecryptPasswordに初期化されたポインタを渡しましたCryptUnprotectData
  7. DecryptPasswordで割り当てられたメモリをリークしますGetMem
  8. DecryptPassword何をしようとしているのかはよくわかりませんが、明らかに壊れています。あなたの目標が何かわからないので、私はそれを修正することはできません。

しかし、もっと問題があると確信しています。一般的なアドバイスがあります。質問のコードが多すぎます。できるだけ取り除く必要があります。SSCCEは可能な限り小さくする必要があります。これは単純なコンソール アプリケーションである必要があります。コードは読みやすく、できれば水平スクロールに頼らないようにフォーマットする必要があります。これは私たちを助けるのと同じくらいあなたを助けるでしょう.

ポイントは、エラーを探しているということです。コードを可能な限り単純化すると、チェックする必要が少なくなります。コードが見やすく、きれいに配置されていると、確認しやすくなります。

ここでは、特定の詳細を正しく理解するのと同じくらい、コードを読みやすく簡潔にする方法を知るという一般原則がはるかに重要です。

だから、私が何を意味するかを示すために、これが SSCCE に変換された元の投稿であり、多くのバグが修正されています。

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 のコード フォーマット機能を使用して、コードを読みやすいスタイルにレイアウトしました。そして、プログラム全体を含む 1 つのファイルを作成できるように、これをコンソール アプリケーションに変換しました。

このバージョンは少なくとも実行され、アクセス違反は発生しません。実際にやりたいことを実行させるのはあなた次第です。

于 2013-07-24T06:14:18.687 に答える
2

Jedi Apilibは実績があり、時間が試されているため、変換 (JwaWinCrypt) する代わりにJedi Apilibを使用することから始めます。

私のブログには、小さなサンプル コードがあります。

于 2013-07-24T06:12:33.943 に答える