如果密码少于16个字符,为什么带有ecb的河豚的mcrypt和openssl_encrypt不能给出相同的结果?

时间:2019-01-14 11:16:37

标签: php openssl mcrypt

我已经阅读了一般建议: mcrypt is deprecated, what is the alternative?PHP7.1 mcrypt alternative

并测试了以下解决方案: Migrating mcrypt with Blowfish and ECB to OpenSSLphp: mcrypt_encrypt to openssl_encrypt, and OPENSSL_ZERO_PADDING problems

他们没有用。这是我使用的代码:

$message = "My secret message";
$key = "mysecretpasswor"; // <- if you add one more character here, it's working
$iv = "\0\0\0\0\0\0\0\0";

$message_padded = $message;

if(strlen($message_padded) % 8) {
  $message_padded = str_pad($message_padded, strlen($message_padded) + 8 - strlen($message_padded) % 8, "\0");
}

$encrypted_mcrypt = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $message, MCRYPT_MODE_ECB, $iv);
$encrypted_openssl = openssl_encrypt($message_padded, "bf-ecb", $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);

printf("%s => %s\n", $message, base64_encode($encrypted_mcrypt));
printf("%s => %s\n", $message_padded, base64_encode($encrypted_openssl));

使用“ DES-EDE3-CBC”之类的加密方法确实有效。但是我无法更改所使用的加密。我必须将旧代码迁移到新代码。有时会使用少于16个字符的键。

有什么建议吗?

1 个答案:

答案 0 :(得分:2)

首先,OPENSSL_NO_PADDING不应该与openssl_encrypt()一起使用。 Its documentation提到OPENSSL_ZERO_PADDING,(令人困惑地)表示“无填充”。那就是你想要的。

OPENSSL_NO_PADDINGintended for use with asymmetric cryptography。碰巧的是,它的值3等于OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING。这就是为什么您不正确地使用它而不造成后果的原因(在这种情况下)。

您的密文有所不同,因为默认情况下,openssl_encrypt()模式下的功能bf-ecb会在密钥的长度小于16个字节时用\0填充密钥。河豚不需要这样做,mcrypt_encrypt()则不需要。为了关闭该行为,请在调用OPENSSL_DONT_ZERO_PAD_KEY时使用标志openssl_encrypt()。由于似乎未记录此标志,因此您必须前往the source code进行了解:-)。或阅读Bug #72362 OpenSSL Blowfish encryption is incorrect for short keys

这样,openssl_encrypt()的正确调用变为:

$opts = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING | OPENSSL_DONT_ZERO_PAD_KEY;
$encrypted_openssl = openssl_encrypt($message_padded, "bf-ecb", $key, $opts);

测试:

$ php bf.php
My secret message => JPO/tvAqFD2KCTqfv0l8uWLfPUWdZIxQ
My secret message => JPO/tvAqFD2KCTqfv0l8uWLfPUWdZIxQ