I've wrote the codes below to make an encryption and decryption mechanism. Everything works fine, but I would like to prevent showing unreadable characters if somebody enter a wrong key while decryption. Instead, I would like to show him a certain error message. How can I do it?
My PHP codes:
<?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
?>
You can only detect whether a key was correct if you already know something about the plain text.
You could modify your encrypt()
function so that it always adds something to the plain text, e.g. $plaintext = 'correct key' . $plaintext;
.
In your decrypt()
function you could now check whether this string exists and remove it before returning.
You would have to replace the last line of decrypt()
with this:
$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;
}
The problem here is that knowing part of the encrypted message potentially weakens the security of the encryption. So don't do that.
Instead of modifying the plain text, you could just save a finger print (e.g. a SHA1 hash) of it.
Modify the encrypt()
function like this:
return sha1($plaintext) . base64_encode($ciphertext);
And the decrypt()
function like this:
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;
}
}