davidjhp
davidjhp

Reputation: 8016

Why is mcrypt_encrypt() putting binary characters at the end of my string?

Here is a PHP demo script that encrypts and decrypts data:

<?

$encryptionkey = 'h8y2p9d1';

$card_nbr = "1234";
echo "original card_nbr: $card_nbr <br>\n";

$card_nbr_encrypted=encrypt_data($card_nbr);
echo "card_nbr_encrypted: $card_nbr_encrypted <br>\n";

$card_nbr_decrypted=decrypt_data($card_nbr_encrypted);
echo "card_nbr_decrypted: $card_nbr_decrypted <br>\n";

$len=strlen($card_nbr_decrypted);
echo "length: $len <br>\n";



function encrypt_data($text){
  global $encryptionkey;
  $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
  $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
  $encrypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $encryptionkey, $text, MCRYPT_MODE_ECB, $iv);
  return $encrypted_text;
}

function decrypt_data($text){
  global $encryptionkey;
  $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
  $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
  $decrypted_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $encryptionkey, $text, MCRYPT_MODE_ECB, $iv);
  return $decrypted_text;
}

?>


The output is:

original card_nbr: 1234
card_nbr_encrypted: vY¨(Z$<§G3-žÃ-Éù3Ý2Ê×rz¨VÛ
card_nbr_decrypted: 1234  (and 28 binary characters)
length: 32 


The output is successfully decrypted, but 28 binary characters are added to the end. This can most easily be seen in Firefox, when viewing HTML source. The string length of 32 also demonstrates this. Any ideas?

enter image description here

Upvotes: 8

Views: 6758

Answers (4)

bLuEdDy
bLuEdDy

Reputation: 193

I think the problem is that you are using binary data when:

mcrypt_encrypt — Encrypts plaintext with given parameters

You can use base64_encode($text) for use plaintext.

Upvotes: -1

Mark Fox
Mark Fox

Reputation: 8924

You're receiving null bytes because you're using Electronic Code Block (ECB) for your block cipher mode of operation, which pads the end of your plaintext to fit into the block size. In your case the block size is 256 bits because you're using MCRYPT_RIJNDAEL_256.

You can avoid this padding problem all together if you use Cipher Feedback (CFB) mode — MCRYPT_MODE_CFB — no null bytes, no need to trim. But, with CFB you should HMAC your encrypted data, to verify it hasn't been tampered with (see "Mallet"). You can find an example of a working implementation at: Cryptography For The Average Developer.

Also of note, ECB mode is considered less secure because it can reveal data patterns. Plus, ECB (and CBC since it also pads) can be vulnerable to padding oracle attack.

Upvotes: 2

drew010
drew010

Reputation: 69937

The returned string is padded out to fill n * blocksize bytes using the null character \0 so that is why you are seeing the extra data.

If you run $card_nbr_decrypted= rtrim($card_nbr_decrypted, "\0"); it should return the actual data.

Upvotes: 8

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798626

It seems to be a known problem. Use rtrim() after decoding to remove the excess NULs.

Upvotes: 3

Related Questions