【问题标题】:PHP OpenSSL encrypt with DES-ECB algorithm unexpected outputPHP OpenSSL 加密与 DES-ECB 算法意外输出
【发布时间】:2021-11-10 17:28:59
【问题描述】:

我尝试通过 PHP 7.4 (Laravel) 和 OpenSSL 使用 DES-ECB 加密值,并尝试使用在线工具 https://emvlab.org/descalc/ 加密值,结果符合预期。

密钥:96187BBAB2BD19ACF899B74FB4E37972

输入数据:F01DCCE40F8C365ADE0A7DC03BC11DDE

加密数据是在线工具上的355A627E977D8ECF4953C98D801E472F。 https://emvlab.org/descalc/?key=96187BBAB2BD19ACF899B74FB4E37972&iv=0000000000000000&input=f01dcce40f8c365ade0a7dc03bc11dde&mode=ecb&action=Encrypt&output=D5131A2B35766D371420F679F15969FF

当下一个用 PHP 编写的代码时,我无法复制结果:

$data = "F01DCCE40F8C365ADE0A7DC03BC11DDE";
$key = "96187BBAB2BD19ACF899B74FB4E37972";
$encrypted = openssl_encrypt($data, 'DES-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
echo base64_encode($encrypted); // KV8Vie63pG2ZyjW7U5NRJUwOrbsEt+lnG1hNyS331Yk=

有没有办法获得与在线工具相同的字符串? 谢谢!

【问题讨论】:

  • 我确定数据和密钥是十六进制编码的,所以第一步你应该使用 hex2bin 将其转换为二进制。第二:我怀疑在线工具没有使用“无填充”,而是使用 PKCS#7 填充(或者可能使用 x00 填充)。

标签: php laravel algorithm encryption openssl


【解决方案1】:

网站必须考虑什么?

该网站允许在 2TDEA 变体(双长度密钥)中使用 DES 和 TripleDES 进行加密。该算法由密钥大小决定:对于 8 字节密钥,使用 DES,对于 16 字节密钥 TripleDES/2TDEA。支持的模式是 ECB 和 CBC。
密钥、IV(在 CBC 模式的情况下)、明文和密文必须在网站上输入十六进制编码。应用零填充(如果明文长度已经是 8 字节的 DES/TripleDES 块大小的整数倍,则不填充的变体)。

这对发布的数据意味着什么?

由于发布的十六进制编码密钥 96187BBAB2BD19ACF899B74FB4E37972 的大小为 16 字节,因此使用 TripleDES/2TDEA(在 ECB 模式下)。
十六进制编码的明文F01DCCE40F8C365ADE0A7DC03BC11DDE 的大小为 16 字节,因此没有填充。因此,生成的十六进制编码密文355A627E977D8ECF4953C98D801E472F 具有相同的长度。

如何修复 PHP 代码?

发布的 PHP 代码给出了不同的结果,因为 DES 用作算法(在 ECB 模式下),并且缺少十六进制编码/解码。因此,要产生网站的结果,编码/解码必须固定,DES-EDE-ECB 必须作为算法应用(不要与 DES-EDE3-ECB 混淆,用于 3TDEA/三倍长度密钥):

$data = hex2bin("F01DCCE40F8C365ADE0A7DC03BC11DDE");                                                // hex decode the 16 bytes data
$key = hex2bin("96187BBAB2BD19ACF899B74FB4E37972");                                                 // hex decode the 16 bytes key key
$encrypted = openssl_encrypt($data, 'DES-EDE-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);  // apply DES-EDE-ECB; use OPENSSL_ZERO_PADDING
echo bin2hex($encrypted); // 355a627e977d8ecf4953c98d801e472f                                       // hex encode the 16 bytes ciphertext

输出:

355a627e977d8ecf4953c98d801e472f

这等于网站的结果,s。 here


DES 如何获得一致的结果?

当前 PHP 代码应用 DES,因此仅使用前 8 个字节隐式地将密钥截断为 8 个字节。这可以通过删除密钥的最后 8 个字节轻松验证。结果没有改变。
如果将缩短的密钥应用于网站,则结果会再次匹配。

$data = hex2bin("F01DCCE40F8C365ADE0A7DC03BC11DDE");                                            // hex decode the 16 bytes data
$key = hex2bin("96187BBAB2BD19AC");                                                             // hex decode the 8 bytes key
$encrypted = openssl_encrypt($data, 'DES-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);  // apply DES-ECB; use OPENSSL_ZERO_PADDING
echo bin2hex($encrypted); // 692370230b8176f011760ddc07392a4f                                   // hex encode the 16 bytes ciphertext

输出:

692370230b8176f011760ddc07392a4f

这等于网站的结果,s。 here.

【讨论】:

  • 感谢您的回答,它适用于DES-EDE-ECB!非常感谢,你拯救了我的一天。还有一个关于DES-EDE-ECB 的问题,LibreSSL 2.8.3 (MacOS Big Sur) 不支持DES-EDE-ECB,我应该在我的 MacBook 上安装 OpenSSL 来解决这个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多