5

Delphi 2007 で開発されたアプリケーションがあります。このアプリケーションでは、値が PHP によって暗号化され、アプリケーションで復号化されます。暗号化アルゴリズムは RIJNDAEL 128 です。XE2 を移動し、DCPcrypt の最新バージョンをインストールすると、アプリケーションは実行されますが、PHP から暗号化された文字列を復号化できなくなります。結果は漢字のように見えるので、XE2 が Unicode 文字を使用しているという事実を説明するために、暗号化キー、ベクトル、または暗号化された文字列の処理を変更する必要があるかどうか疑問に思っています。

PHP 暗号化は次のように実行されます: (mcrypt_cbc(MCRYPT_RIJNDAEL_128,$key,$date_str,MCRYPT_ENCRYPT,$iv))

関連する 2 つの Delphi 関数は次のとおりです。

function PadWithZeros(const str : string; size : integer) : string;
var
  origsize, i : integer;
begin
  Result := str;
  origsize := Length(Result);
  if ((origsize mod size) <> 0) or (origsize = 0) then
  begin
    SetLength(Result,((origsize div size)+1)*size);
    for i := origsize+1 to Length(Result) do
      Result[i] := #0;
  end;
end;

procedure TfrmMain.btnDecryptClick(Sender: TObject);
var
  Cipher : TDCP_rijndael;
  Data, Key, IV : string;
begin
  // Pad Key and IV with zeros as appropriate
  Key := PadWithZeros(boxKey.Text,KeySize);
  IV := PadWithZeros(boxIV.Text,BlockSize);
  // Decode the Base64 encoded string
  Data := Base64DecodeStr(boxCipherTextIn.Text);
  // Create the cipher and initialise according to the key length
  Cipher := TDCP_rijndael.Create(Self);
  if Length(boxKey.Text) <= 16 then
    Cipher.Init(Key[1],128,@IV[1])
  else if Length(boxKey.Text) <= 24 then
    Cipher.Init(Key[1],192,@IV[1])
  else
    Cipher.Init(Key[1],256,@IV[1]);
  // Decrypt the data
  Cipher.DecryptCBC(Data[1],Data[1],Length(Data));
  // Free the cipher and clear sensitive information
  Cipher.Free;
  FillChar(Key[1],Length(Key),0);
  // Display the result
  boxPlainTextOut.Text := Data;
end;
4

2 に答える 2

10

この問題は文字エンコーディングに関連していますが、DCPCrypt が UTF-16 を処理できないわけではありません。

PHP 文字列は UTF-8 です。PHP から Dephi にパスワード (「キー」) を base64 でエンコードされた文字列として渡します。奇妙なことに、デコードされたキーを UTF-16LE 文字列に格納しています。より適切なのは、rawbytestring、TBytes、または TMemoryStream です。Key のペイロードのバイナリ レイアウトは、UTF16-LE として型指定されているため、エンコード側でのバイナリ レイアウトとは異なります (Delphi の用語では、「ユニコード文字列」 - Microsoft と Embarcadero の不正行為)。

また、このコード行は、明らかな理由により、「ユニコード」(sic) コンパイラでは間違っています...

FillChar(Key[1],Length(Key),0);

サイドノート

私は TurboPower LockBox 3 の作成者であり、フォーラムで最も多く寄せられる問題は、ansistring、utf-8 文字列、および utf-16le 文字列の間の混乱から生じます。多くの人は、PHP が理解するパスワード「abc」は、Delphi 2010 の「abc」と同じパスワードであると考えています。パスワード文字列から暗号化ライブラリが使用するのは、文字列のセマンティックではなく、文字列のエンコーディングに起因するバイナリ ペイロードです。文字列としての意味。

于 2012-08-17T08:44:17.133 に答える
5

アプリケーションは XE2 で適切にコンパイルされるようになり、Delphi 2007 でコンパイルされたバージョンからレコードを復号化できるようになりました。コメントをお寄せいただきありがとうございます。さまざまなパースペクティブは、変数を ANSI 文字列として定義する必要がある場合を明確にするのに役立ちます。

他の誰かが同様の更新を試みていて、PHP で生成された暗号テキストを復号化する必要がある場合に備えて、私の復号化関数とサポートする padWithZeros() 関数は DCPcrypt サイトから取得したので、変更したコードをここに投稿します。また、2012 年 7 月 21 日に XE2 用の DCPcrypt に更新プログラムをインストールしたことも忘れてはなりません

function TForm1.AESDecrypt(const DecKeyStr: AnsiString;
                              const DecIVStr: AnsiString;
                              const CypherTextIn: AnsiString): String;
var
  Cipher : TDCP_rijndael;
  Data, Key, IV : AnsiString;
begin
  // Pad Key and IV with zeros as appropriate
  Key := PadWithZeros(DecKeyStr,KeySize);
  IV := PadWithZeros(DecIVStr,BlockSize);
  // Decode the Base64 encoded string
  Data := Base64DecodeStr(CypherTextIn);
  // Create the cipher and initialise according to the key length
  Cipher := TDCP_rijndael.Create(nil);
  if Length(DecKeyStr) <= 16 then
    Cipher.Init(Key[1],128,@IV[1])
  else if Length(DecKeyStr) <= 24 then
    Cipher.Init(Key[1],192,@IV[1])
  else
    Cipher.Init(Key[1],256,@IV[1]);
  // Decrypt the data
  Cipher.DecryptCBC(Data[1],Data[1],Length(Data));
  // Free the cipher and clear sensitive information
  Cipher.Free;
  FillChar(Key[1],Length(Key),0);
  // Display the result
  Result := String(Data);
(* *)
end;

function TForm1.PadWithZeros(const str:AnsiString; size:integer):AnsiString;
var
  origsize, i : integer;
begin
  Result := str;
  origsize := Length(Result);
  if ((origsize mod size) <> 0) or (origsize = 0) then
  begin
    SetLength(Result,((origsize div size)+1)*size);
    for i := origsize+1 to Length(Result) do
      Result[i] := #0;
  end;
end;
于 2012-08-27T01:25:51.560 に答える