I am just trying to encrypt and decrypt a string. But when I output the decrypted string I only get:
��
^����V��_��n�.ZZ��Ǐ��:�2��
My code:
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;
Any idead what could be wrong?
You're randomly generating the initialization vector (IV) during encryption which means that the ciphertext will be randomized according to that IV. When you decrypt, you need to provide the same IV that you used for encryption.
Since the IV doesn't need to be secret, you can simply prepend it to the ciphertext or send it along in some other way. Don't generate a different IV during decryption.
If your plaintext were longer (more than 32 bytes), you would have seen that the first 32 bytes were wrong, but the rest were correct. If you want to know more about how CBC mode works, Wikipedia has got you covered.
During encryption, mcrypt applies a padding of 0x00 bytes to the plaintext, because Rijndael in CBC mode works on blocks of 16 bytes. You need to remove the padding after decryption, because it isn't done automatically:
Also, don't forget to authenticate your ciphertexts, because otherwise attacks such as padding-oracle attack can be used to completely decrypt some ciphertext. Ciphertext authentication can be done with an authenticated mode like GCM or with an authentication tag generated through an HMAC pass over the ciphertext.
See also
There was a little controversy in the comments to the question that
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB)
should not containECB
, but ratherCBC
mode, because ECB mode doesn't use an IV, but mcrypt is bad and it happily returns a valid IV for CBC (32 byte in this case) despite requesting an "IV for ECB" which should have been 0 byte.mcrypt is abandonware and should not be used anymore. Use openssl/libsodium/defuse/...