【问题标题】:AES encrypt string in Delphi (10 Seattle) with DCrypt, decrypt with PHP/OpenSSLAES 在 Delphi (10 Seattle) 中使用 DCrypt 加密字符串,使用 PHP/OpenSSL 解密
【发布时间】:2016-12-23 04:15:53
【问题描述】:

鉴于此代码在 Delphi 中使用 DCrypt:

Uses DCPcrypt2, DCPblockciphers, DCPrijndael, DCPbase64;

procedure TForm1.Button1Click(Sender: TObject);
var Cipher : TDCP_rijndael;
    ss, k, Data, Key, IV : Ansistring;
const
  KeySize = 32; // 32 bytes = 256 bits
  BlockSize = 16; // 16 bytes = 128 bits // IV
begin
  key := '12345678901234567890123456789012';
  iv  := '1234567890123456';
  Data := 'thisis128bitstxt';

  Cipher := TDCP_rijndael.Create(nil);
  Cipher.Init(Key[1],128,@IV[1]);
  Cipher.EncryptCBC(Data[1],Data[1],Length(Data));
  Cipher.Free;

  Data := DCPBase64.Base64EncodeStr(Data);
  Memo1.Lines.Add(Data);
end;

我得到以下信息: Eq7iMlVKysMMXdhR0rtrwA==

用 OpenSSL 在 PHP 中尝试同样的方法:

<?
    $s = "thisis128bitstxt";
    $s = openssl_encrypt($s, "AES-128-CBC", "12345678901234567890123456789012", 0, "1234567890123456");
    echo $s . "</br>";
?>

返回:Eq7iMlVKysMMXdhR0rtrwEbhkypNJyuwGafLILvwpbY=

怎么了?

如果我尝试解密 delphi 输出,我会得到一个空字符串:

$s = "Eq7iMlVKysMMXdhR0rtrwA==";
$s = openssl_decrypt($s, "AES-128-CBC", "12345678901234567890123456789012", 0, "1234567890123456");
echo $s . "</br>";

【问题讨论】:

  • 看起来您缺少填充
  • 你的 Delphi 版本是多少?请编辑问题并添加正确的标签
  • 在加密方面没有“字符串”之类的东西。有字节序列。但是字符串不是字节序列吗?它们是,但是有许多不同的规则如何将文本转换为字节和字节转换为文本。它们被称为字符集、编码等等。您将 Delphi 字符串固定为 AnsiString... 看起来不错。两次,如果您的 DCPCrypt 副本也使用该类型,则不是模棱两可的string 通配符。但是 PHP 使用什么?您的编辑放入文件中的任何内容:php.net/manual/en/…
  • 所以 PHP 字符串是......好吧,任何东西。 Web 服务器期望的任何东西,或 PHP IDE 期望的任何东西......所以我将从相反的方向开始:获取 PHP 生成的字符串并尝试在 Delphi 中将其解码为TBytes 或其他原始字节类型序列,然后查看哪些字符集可用于将这些字节转换为文本。 UTF-16、UTF-8 等等……
  • 我需要处理的文本都是ansi

标签: delphi encryption openssl aes


【解决方案1】:

David Heffernan 已经为您指引了正确的方向。 我在这里完成它。

你不应该错过填充。 我将您的代码修复如下。

procedure TForm1.Button1Click(Sender: TObject);
var Cipher : TDCP_rijndael;
    Data, Key, IV : ansistring;
    index, dataLength, bsize, pad: integer;
begin
  key := '12345678901234567890123456789012';
  IV  := '1234567890123456';
  Data := 'thisis128bitstxt';

  Cipher := TDCP_rijndael.Create(nil);
  try
    Cipher.Init(Key[1],128,@IV[1]);

    //don't miss padding
    {start padding}
    dataLength := Length(Data);
    bsize := (Cipher.BlockSize div 8);
    pad := bsize - (dataLength mod bsize);
    for index := 1 to pad do
      Data := Data+chr(pad);
    {end padding}

    Cipher.EncryptCBC(Data[1],Data[1],Length(Data));
  finally
    Cipher.Free;
  end;

  Data := DCPBase64.Base64EncodeStr(Data);
  Memo1.Lines.Add(Data);
end;

你现在会得到和php一样的结果。

【讨论】:

  • 这有一个问题,如果现在我想解密数据我不会得到相同的原始输入,因为有额外的填充,你如何检测从最后删除多少100% 恢复原始内容?
  • nvm 那,切换到点击率,然后我不需要填充。
  • @hikari 这很容易。最后一个字符显示您应该删除多少。 slen:=Length(src); cipher.Init(key[0], 128, @iv[0]); cipher.Decrypt(src[0], dest[0], slen); pad := dest[slen - 1]; SetLength(dest, slen - pad); result := TEncoding.ASCII.GetString(dest);
  • 但是你如何辨别它是填充数据还是实际数据?
猜你喜欢
  • 1970-01-01
  • 2012-08-15
  • 1970-01-01
  • 2022-11-25
  • 1970-01-01
  • 2015-06-18
  • 2013-01-07
  • 2021-05-01
  • 1970-01-01
相关资源
最近更新 更多