PHP 用 mcrypt 解密 returns 无法理解的文本而不是原始明文
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 模式如何工作的信息,Wikipedia 已为您介绍。
在加密期间,mcrypt 对明文应用 0x00 字节的填充,因为 Rijndael 在 CBC 模式下处理 16 字节的块。您需要在解密后删除填充,因为它不会自动完成:
return rtrim(mcrypt_decrypt(...), "[=10=]");
此外,不要忘记验证您的密文,否则可以使用诸如 padding-oracle 攻击之类的攻击来完全解密某些密文。密文身份验证可以使用 GCM 等身份验证模式或通过 HMAC 传递密文生成的身份验证标记来完成。
另见
- A: How do you Encrypt and Decrypt a PHP String?
- A: How to encrypt/decrypt data in php?
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB)
不应包含ECB
,而应包含CBC
模式的问题的评论中存在一些争议,因为ECB模式不使用IV,但是 mcrypt 很糟糕,它很高兴 returns 是 CBC 的有效 IV(在本例中为 32 字节),尽管请求的 "IV for ECB" 应该是 0 字节。
mcrypt 是废弃软件,不应再使用。使用 openssl/libsodium/defuse/...
我只是想加密和解密一个字符串。但是当我输出解密的字符串时,我只得到:
��
^����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 模式如何工作的信息,Wikipedia 已为您介绍。
在加密期间,mcrypt 对明文应用 0x00 字节的填充,因为 Rijndael 在 CBC 模式下处理 16 字节的块。您需要在解密后删除填充,因为它不会自动完成:
return rtrim(mcrypt_decrypt(...), "[=10=]");
此外,不要忘记验证您的密文,否则可以使用诸如 padding-oracle 攻击之类的攻击来完全解密某些密文。密文身份验证可以使用 GCM 等身份验证模式或通过 HMAC 传递密文生成的身份验证标记来完成。
另见
- A: How do you Encrypt and Decrypt a PHP String?
- A: How to encrypt/decrypt data in php?
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB)
不应包含ECB
,而应包含CBC
模式的问题的评论中存在一些争议,因为ECB模式不使用IV,但是 mcrypt 很糟糕,它很高兴 returns 是 CBC 的有效 IV(在本例中为 32 字节),尽管请求的 "IV for ECB" 应该是 0 字节。
mcrypt 是废弃软件,不应再使用。使用 openssl/libsodium/defuse/...