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 字符串完全没有意义 - 您只会将其膨胀得更多而没有任何好处。
请参考我之前的问题: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 字符串完全没有意义 - 您只会将其膨胀得更多而没有任何好处。