1

I'm trying to encrypt some data using the MCRYPT_RIJNDAEL_128 algoritm. But somehow when I encrypt and afterwards decrypt, the decrypted data has randomly added bytes.

The input: string(13) "[email protected]"

The output: string(16) "[email protected]"

enter image description here

As you can see the output has 16 characters while the input has 13.

The following is the code used for encryption.

class Cipher
{

/**
 * The key/salt(bin2hex format) used to encrypt data with in AES(RIJNDAEL) format.
 * @var string
 */
private static $encryptionKey = 'baafbd1f8d752d920caae00ae550be8185c1183207a142c97c36fca3edc507da';

/**
 * Gets and transforms the encryption key to binary format.
 * @return string (in binary format)
 */
public static function getEncryptionKey()
{
    return hex2bin(self::$encryptionKey);
}

/**
 * Generates a new random main encryption key used to encrypt data.
 * Store the generated key in the private property of this class.
 * @param bool $strong Whether the encryption will be strong.
 * @return string The generated key in hexadecimal format.
 */
public static function generateEncryptionKey($strong = true)
{
    $keySize = mcrypt_get_key_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    return bin2hex(openssl_random_pseudo_bytes($keySize, $strong));
}

/**
 * Creates an encryption key IV used to store near the database record for the encrypted data.
 * Use bin2hex function for a representational string.
 * @return string (in binary format)
 */
public static function createIv()
{
    $ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    return mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
}

/**
 * Encrypts a given string by the generated encryption key and generated IV.
 * @param string $string The string which will be encrypted.
 * @param string $iv The dynamic key used to encrypt.
 * @return string (in binary format)
 */
public static function encrypt($string, $iv)
{
    return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, self::getEncryptionKey(), $string, MCRYPT_MODE_CBC, $iv);
}

/**
 * Decrypts a given string by the generated encryption key and generated IV.
 * @param string $string The binary string which will be decrypted.
 * @param string $iv The dynamic key which belongs to the encrypted string.
 * @return string The decrypted string.
 */
public static function decrypt($string, $iv)
{
    return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, self::getEncryptionKey(), $string, MCRYPT_MODE_CBC, $iv);
}

}

The encryption key showed here isn't used in production or testing environments and is only used for display purposes.

The following is used to display the decryption

$iv = Cipher::createIv();
$emailAddress = Cipher::encrypt('[email protected]', $iv);

var_dump(Cipher::decrypt($emailAddress, $iv));exit;

I'm using the following environments:

Ubuntu: 14.10

PHP: PHP 5.5.9-1ubuntu4.3 (cli) (built: Jul 7 2014 16:36:58)

1 Answer 1

1

Those are just padding 0x00 characters added at the end, because the string's length for that cryptographic algorithms has to be a multiple of 16 (with 128 bit).

Indeed, if you add at the end of your code:

var_dump(bin2hex(Cipher::decrypt($emailAddress, $iv)));

You can see that the last 6 characters are all 0's (which means there are 3 0x00 bytes at the end).

To remove them, just run:

$decrypted = rtrim($decrypted, "\0");
Sign up to request clarification or add additional context in comments.

5 Comments

Note that the rtrim trick only works if the input does not end on 00h. Strings usually don't as 00h is not a printable character. Otherwise you need to add PKCS#7 padding (yourself, before encryption, and remove it after decryption, of course). PS he does not need to use hex decode, the character blocks in the question already contain the value - four zero's in the square showing the unrecognized character :)
@owlstead Thanks, for other ppl reading the PKCS#7 padding, see stackoverflow.com/questions/7314901/… for more info.
@owlstead Unless he's encrypting binary data, he should never have any \0 in the strings (actually, it wouldn't be a bad idea to filter all non-printable characters... I use $string = preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/u', '', $string); ) For the hex decoding... It was just to make debugging easier :) He doesn't need to use that code!
PHP mcrypt explicitly adds only \0 characters; removing all non-printable characters would only cover up encoding mistakes. And yes, I understood about the hex for debugging, I just wanted to point out that the information was already present in the question (funny enough, I am saying this while the firewall rules have removed the actual image with the "zero characters" :P).
@owlstead I do that filtering on all input data (when expecting strings from users), it was unrelated with mcrypt. That regex is unicode-safe, as it will remove characters and not bytes (see the "u" flag).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.