PHP OpenSSL 使用 DES-ECB 算法加密意外输出

PHP OpenSSL encrypt with DES-ECB algorithm unexpected output

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

键:96187BBAB2BD19ACF899B74FB4E37972

输入数据:F01DCCE40F8C365ADE0A7DC03BC11DDE

在线工具上的加密数据是355A627E977D8ECF4953C98D801E472Fhttps://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=

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

做网站需要注意什么?

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

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

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

如何修复PHP代码?

发布的 PHP 代码给出了不同的结果,因为 DES 被用作算法(在 ECB 模式下)并且十六进制 encoding/decoding 也丢失了。因此,要生成网站的结果,必须修复 encoding/decoding 并且必须将 DES-EDE-ECB 应用为算法(不要与 3TDEA/三倍长度密钥的 DES-EDE3-ECB 混淆):

$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.