PHP解密使用mcrypt返回无法理解的文本,而不是原始明文


PHP decryption with mcrypt returns unintelligible text instead of original plaintext

我只是想加密和解密一个字符串。但是当我输出解密字符串时,我只得到:

��
  ^����V��_��n�.ZZ��Ǐ��:�2��
我代码:

function encrypt($string, $secret_key = "ATRTHTRAGSFRSGTS") {                                                                                                                   
   $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);                                                                      
   return mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $secret_key, $string, MCRYPT_MODE_CBC, $iv);                                                                             
}                                                                                                                                                                       
function decrypt($string, $secret_key = "ATRTHTRAGSFRSGTS") {                                                                                                                   
   $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND);                                                                      
   return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $secret_key, $string, MCRYPT_MODE_CBC, $iv);                                                                             
}                                                                                                                                                                       
$text = 'This is a test.';                                                                                                                                              
$enc = encrypt($text);                                                                                                                                                  
$dec = decrypt($enc);                                                                                                                                                   
echo $dec;

你知道有什么问题吗?

您在加密期间随机生成初始化向量(IV),这意味着密文将根据该IV随机化。当您解密时,您需要提供用于加密的相同IV。

由于IV不需要保密,您可以简单地将其附加到密文或以其他方式发送它。不要在解密过程中生成不同的IV。

如果明文较长(超过32字节),您会发现前32字节是错误的,但其余的是正确的。如果你想了解更多关于CBC模式的工作原理,维基百科已经为你提供了帮助。


在加密过程中,mcrypt对明文应用0x00字节的填充,因为CBC模式下的Rijndael工作在16字节的块上。您需要在解密后删除填充,因为它不会自动完成:

return rtrim(mcrypt_decrypt(...), "'0");

另外,不要忘记对您的密文进行身份验证,否则可以使用诸如padding-oracle攻击之类的攻击来完全解密某些密文。密文身份验证可以通过像GCM这样的身份验证模式来完成,也可以通过通过密文的HMAC传递生成的身份验证标记来完成。

参见

    A:如何加密和解密PHP字符串?
  • A:如何加密/解密数据在php?

在对mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB)不应该包含ECB,而是CBC模式的问题的评论中有一点争议,因为ECB模式不使用IV,但mcrypt是坏的,尽管请求"ECB IV"应该是0字节,但它很高兴地返回CBC的有效IV(在这种情况下为32字节)。

mcrypt是废弃软件,不应该再使用了。使用openssl/libsodium/缓解/…