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) "test@test.com"

The output: string(16) "test@test.com"

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('test@test.com', $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)

stixx
  • 142
  • 1
  • 8

1 Answers1

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");
ItalyPaleAle
  • 7,185
  • 6
  • 42
  • 69
  • 1
    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 :) – Maarten Bodewes Aug 25 '14 at 17:01
  • @owlstead Thanks, for other ppl reading the PKCS#7 padding, see http://stackoverflow.com/questions/7314901/how-to-add-remove-pkcs7-padding-from-an-aes-encrypted-string for more info. – stixx Aug 26 '14 at 07:29
  • @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! – ItalyPaleAle Aug 26 '14 at 12:14
  • 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). – Maarten Bodewes Aug 26 '14 at 13:22
  • @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). – ItalyPaleAle Aug 26 '14 at 13:27