在 PHP 中使用 mcrypt 函数时检测到错误的解密密钥

Detect wrong decryption key while working with mcrypt functions in PHP

我写了下面的代码来做一个加解密机制。一切正常,但如果有人在解密时输入错误的密钥,我想防止显示不可读的字符。相反,我想向他显示一条特定的错误消息。我该怎么做?
我的 PHP 代码:

<?php

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

function encrypt($plaintext,$key) {
    global $iv, $iv_size;
    $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
    $ciphertext = $iv . $ciphertext;
    return base64_encode($ciphertext);
}

function decrypt($ciphertext_base64,$key) {
    global $iv, $iv_size;
    $ciphertext_dec = base64_decode($ciphertext_base64);
    $iv_dec = substr($ciphertext_dec, 0, $iv_size);
    $ciphertext_dec = substr($ciphertext_dec, $iv_size);
    return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
}

echo decrypt(encrypt('Hello World','123'),'123');
// Correct key used for decryption and result will be `Hello world`

echo decrypt(encrypt('Hello World','123'),'321');
// Wrong key used for decryption and result will be something like :ŘI¨ĄěđŘcSNŔ¶¸˘ÚE‘Z‰ŃZŃ9

?>

如果您已经了解有关纯文本的,则只能检测密钥是否正确。

(坏)方法一:在纯文本中添加静态字符串

您可以修改 encrypt() 函数,使其始终向纯文本添加一些内容,例如$plaintext = 'correct key' . $plaintext;.

在您的 decrypt() 函数中,您现在可以检查此字符串是否存在并在返回之前将其删除。

您必须将 decrypt() 的最后一行替换为:

$decrypted_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
if (strpos($decrypted_text, 'correct key') === 0) {
    return substr($decrypted_text, strlen('correct key'));
} else {
    // key was wrong
    return false;
}

这里的问题是,了解部分加密消息可能会削弱加密的安全性。所以不要那样做。

(更好)方法 2:使用散列验证纯文本

无需修改纯文本,您可以只保存它的指纹(例如 SHA1 哈希值)。

像这样修改encrypt()函数:

return sha1($plaintext) . base64_encode($ciphertext);

decrypt() 函数是这样的:

function decrypt($ciphertext, $key) {
    global $iv, $iv_size;

    $fingerprint = substr($ciphertext, 0, 32);
    $ciphertext_base64 = substr($ciphertext, 32);

    $ciphertext_dec = base64_decode($ciphertext_base64);
    $iv_dec = substr($ciphertext_dec, 0, $iv_size);
    $ciphertext_dec = substr($ciphertext_dec, $iv_size);

    $decrypted_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
    if (sha1($decrypted_text) == $fingerprint) {
        return $decrypted_text;
    } else {
        // key was wrong
        return false;
    }
}