Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I Trim the Decrypted String after mcrypt_decrypt?

Tags:

php

encryption

I have a code that goes something like:

$cipher_alg = MCRYPT_RIJNDAEL_128;
$decrypted_string = mcrypt_decrypt($cipher_alg, $key, 
$encrypted_string , MCRYPT_MODE_CBC, trim(hex2bin(trim($hexiv))));

I worry that in the process of decoding the mcrypt_decrypt will introduce a gratuitous whitespace or null characters at the back or front of the $decrypted_string.

So should I trim it?

Note: I could have run the code and find this out. But since I can never run enough samples to prove ( or disprove) my point, I want some concrete and theoretical answers, probably based on the inner working of the mcrypt_decrypt algorithm. Another reason I ask is that I believe this is going to help others.

Note 2: Notwithstanding with the answer below ( now deleted and only 10K users can see it), it seems that the examples here do use trimming to get the correct decrypted string.

like image 203
Graviton Avatar asked Jun 30 '09 04:06

Graviton


1 Answers

Actually both mcrypt_encrypt() and mcrypt_decrypt() as well as the other en-/decryption functons (like mcrypt_generic() or mdecrypt_generic()) do pad the $data parameter to a length of n * <<blocksize>>. The padding character is the NUL character (\x0 or \0) whereas the <<blocksize>> depends on the cipher and the block cipher modes used. You should have a look at Block cipher modes of operation and Padding (cryptography).

The following is the output of mcrypt_get_block_size() for each of the available ciphers and modes on my machine. Obviously the function does not take into account that modes such as CFB, OFB and CTR do not require any special measures to handle messages whose lengths are not multiples of the block size, since they all work by XORing the plaintext with the output of the block cipher (quote from Wikipedia). CBC which is used in your example always requires that the final block is padded before encryption.

cast-128
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
gost
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
rijndael-128
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
twofish
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
arcfour
    cbc: not supported
    cfb: not supported
    ctr: not supported
    ecb: not supported
    ncfb: not supported
    nofb: not supported
    ofb: not supported
    stream: 1 bytes
cast-256
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
loki97
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
rijndael-192
    cbc: 24 bytes
    cfb: 24 bytes
    ctr: 24 bytes
    ecb: 24 bytes
    ncfb: 24 bytes
    nofb: 24 bytes
    ofb: 24 bytes
    stream: not supported
saferplus
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
wake
    cbc: not supported
    cfb: not supported
    ctr: not supported
    ecb: not supported
    ncfb: not supported
    nofb: not supported
    ofb: not supported
    stream: 1 bytes
blowfish-compat
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
des
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
rijndael-256
    cbc: 32 bytes
    cfb: 32 bytes
    ctr: 32 bytes
    ecb: 32 bytes
    ncfb: 32 bytes
    nofb: 32 bytes
    ofb: 32 bytes
    stream: not supported
serpent
    cbc: 16 bytes
    cfb: 16 bytes
    ctr: 16 bytes
    ecb: 16 bytes
    ncfb: 16 bytes
    nofb: 16 bytes
    ofb: 16 bytes
    stream: not supported
xtea
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
blowfish
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
enigma
    cbc: not supported
    cfb: not supported
    ctr: not supported
    ecb: not supported
    ncfb: not supported
    nofb: not supported
    ofb: not supported
    stream: 1 bytes
rc2
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported
tripledes
    cbc: 8 bytes
    cfb: 8 bytes
    ctr: 8 bytes
    ecb: 8 bytes
    ncfb: 8 bytes
    nofb: 8 bytes
    ofb: 8 bytes
    stream: not supported

Therefore you have to rtrim() the output of the decryption functions to get the original string if your cipher operates on fixed length blocks:

$output = rtrim($decrypted, "\0");
like image 143
Stefan Gehrig Avatar answered Nov 16 '22 02:11

Stefan Gehrig