Delphi 7 - 使用 DEC 加密,并使用 PHP OpenSSL 解密(第二部分)

Delphi 7 - Encrypt with DEC, and decrypt with PHP OpenSSL (Part II)

请参考我之前的问题:Delphi 7 -

我的 Delphi 7 客户端应用程序(ICS 组件)正在将 base64 编码数据作为 HTTP POST 请求中的参数发送到 PHP Web 服务,它正在那里用 base64_decode 函数解码。但是,在 PHP 中生成的解码字符串与在 Delphi 中最初编码的字符串不同。我使用的 Delphi base64 编码函数来自 DEC (DEC v5.2) 库。

将数据从 Delphi 发送到 PHP(并接收响应)的示例代码实现如下:

Delphi 边:

uses
  OverbyteIcsHttpProt, OverbyteIcsLogger, OverbyteIcsWSocket, OverbyteIcsSslHttpRest, StrUtils,
  DecFmt;


var
  d: String;
  StatCode: Integer;
  sAPIResponse: WideString;
  APIRespData: TAPIRespData;
begin
  //
  d := 'The quick brown fox jumps over the lazy rabbit..'; 
  d := Encrypt(d); // Result string A
  d := TFormat_MIME64.Encode(d); // Result string B

  SslHttpRest1.RestParams.Clear;
  SslHttpRest1.RestParams.AddItem('data', d);
  StatCode := SslHttpRest1.RestRequest(httpPOST, strAPIUrl, False, '');
  sAPIResponse := SslHttpRest1.ResponseRaw; // Result string C

加密看起来像这样(代码来源:@AmigoJack):

const
  GLUE = '::';
  cPASSWORD = 'myownpassword';

function Encrypt(AStr: string): string;
var
  c: TDecCipher; // Successfully tested with DEC 5.2 on Delphi 7
  sKey, // The binary key we have to provide
  sIv, // Initialization vector, should be random in the real world
  sEncrypted, // Output of the encryption
  sPlain: AnsiString; // What we want to encrypt, in binary
  iPlus, // Input data padding
  iLength: Integer; // Plaintext length source, in bytes
begin
  // Keep in mind: Plain, Key and IV are all binary, not text!
  sPlain := AStr;
  sKey := cPASSWORD;

  SetLength(sIv, 16);
  RandomBuffer(sIv[1], 16);

  // The cipher/algorithm depends on fixed block sizes, so it is automatically
  // padded to the next full length. OpenSSL's padding byte is equal to the amount
  // of bytes to be added: if 6 bytes need to be added, then 6 times #6 is added.
  iLength := Length(sPlain);
  iPlus := 16 - (iLength mod 16);
  sPlain := sPlain + StringOfChar(Chr(iPlus), iPlus);

  // Expect DEC 5.2 to only deal with AES-128-CBC, not 256.
  c := ValidCipher(DecCipher.TCipher_Rijndael).Create;
  try
    c.Mode := cmCBCx;
    c.Init(sKey, sIv); // Provide binary key and binary IV
    SetLength(sEncrypted, Length(sPlain)); // Both are multiples of 16
    c.Encode(sPlain[1], sEncrypted[1], Length(sPlain));

    Result := TFormat_MIME64.Encode(sEncrypted) + GLUE + TFormat_MIME64.Encode(sIv) + GLUE + IntToStr(iLength);
  finally
    c.Free;
  end;
end;

结果字符串A:

gS4S0kX9BfrhBYlsZ3MHS9RdgNuuEmKub39aim4/0eiRBPiaw1ykOGOqEk6cY3ol::AAjcM0WrUSlfbBR5EtcPSw==::48

结果字符串B:

a1FUTWtyVFlNVWc1UlREL2lEOXVPaTZUcmtDaHRiMUFLWU9DRVRxODUvQVNpZkJzMEs2Y2xxMU50VGZCNjdOYzo6Nmw3R1U3TFl0MDRwVkhjLzAwZDdKZz09Ojo0OA==

结果字符串C:

B:a1FUTWtyVFlNVWc1UlREL2lEOXVPaTZUcmtDaHRiMUFLWU9DRVRxODUvQVNpZkJzMEs2Y2xxMU50VGZCNjdOYzo6Nmw3R1U3TFl0MDRwVkhjLzAwZDdKZz09Ojo0OA== A:kQTMkrTYMUg5RTD/iD9uOi6TrkChtb1AKYOCETq85/ASifBs0K6clq1NtTfB67Nc::6l7GU7LYt04pVHc/00d7Jg==::48

PHP 边:

$data=$_POST['data'];          echo 'B:' . $data;
$data=base64_decode($data);    echo ' A:' . $data;

我希望 String A 等于 String C (label A:) 中返回的字符串,但事实并非如此。

恕我直言,这个错误要么与字符集编码相关的缺失有关,要么与 DEC 的 TFormat_MIME64.Encode 函数和 PHP (PHP v7.4.7) 之间的不兼容有关 base64_decode函数。

感谢任何帮助解决此问题或为我指明正确方向的帮助!

这不可能是真的 - “结果字符串 B”不可能变成您所说的那样。您确定使用的是 DEC5.2 而不是旧版本吗?

var
  sAll, sAgain: AnsiString;
begin
  sAll:= 'gS4S0kX9BfrhBYlsZ3MHS9RdgNuuEmKub39aim4/0eiRBPiaw1ykOGOqEk6cY3ol::AAjcM0WrUSlfbBR5EtcPSw==::48';
  sAgain:= TFormat_MIME64.Encode( sAll );
  if sAgain<> 'Z1M0UzBrWDlCZnJoQllsc1ozTUhTOVJkZ051dUVtS3ViMzlhaW00LzBlaVJCUGlhdzF5a09HT3FFazZjWTNvbDo6QUFqY00wV3JVU2xmYkJSNUV0Y1BTdz09Ojo0OA==' then Halt;

此外,在 Base64 中再次 编码您的 ASCII 字符串完全没有意义 - 您只会将其膨胀得更多而没有任何好处。