Page 1 of 1

mcrypt_encrypt() PHP Guru needed (solved)

Posted: Tue May 10, 2005 12:37 pm
by hanji
Hello

I'm running into a weird problem with mcrypt and blowfish encryption. The problem is that the encrypted value is not always decryptable??? Which is a nightmare problem.

I'm using the following values to encrypt,decrypt in my test script:

Code: Select all

IV: 8c8NCvPtLlA=
KEYVAL: simp0lANDse3cur3
Here is my test FOR loop, which basically creates a random 32 char alphanumeric string, encrypts it and then decrypts it, 20 times a page:

Code: Select all

define("IV","8c8NCvPtLlA=");
define("KEYVAL","simp0lANDse3cur3");
for($i = 0; $i < 20; $i++){
        $clear          = md5(uniqid(rand(),1));
        $crypt          = base64_encode(encrypt(KEYVAL,trim($clear), base64_decode(IV)));
        echo "clear: ".$clear."<br>";
        echo "crypt: ".$crypt."<br>";
        $clear          = $crypt;
        $clear          = decrypt(KEYVAL,trim(base64_decode($clear)), base64_decode(IV));
        echo "clear: ".$clear."<br>";
        echo "<br>";
}
Now this is where it gets weird.. approximately 1 out of every 3 page calls.. one of the values won't decrypt properly.. please look at last grouping in this example:

Code: Select all

clear: f7911bfb78742d0ecc9c91526095f922
crypt: /kMQy/EinWFpeDiM+ipsfJba8FTh1XxJOjCIaL310xc=
clear: f7911bfb78742d0ecc9c91526095f922

clear: 3c5f9a28b0b4501b843cb678a1aa1cff
crypt: xeqejfC2CrlxWhR6Q/+pS6Ukupf9Q7J+oEhwznhyHX0=
clear: 3c5f9a28b0b4501b843cb678a1aa1cff

clear: 4b7a719f31083f215d8cf7aa537b5a9e
crypt: xZNkyZl9HKr9CexhKZbUua5CesVCO9nmsEFTxlwxFW0=
clear: 4b7a719f31083f215d8cf7aa537b5a9e

clear: 68f54b5db93a503d143cb8e078a6fb5a
crypt: 63a0LHg6iN/diocj1YiENPL3bzn85o7GWY7Ckgbqn1I=
clear: 68f54b5db93a503d143cb8e078a6fb5a

clear: 9438340b57d1192e946dc339ef163486
crypt: SLV0hR7BVWMsYxmf6w69wZh6LzWk3i6KU73buuwVwjI=
clear: 9438340b57d1192e946dc339ef163486

clear: 288f03bc63afe251cc4dd2219c59d1df
crypt: NnlyzXpHQtxjo1Myu0wxNqP7UQti/dmlQHeAQ8lQb5Q=
clear: 288f03bc63afe251cc4dd2219c59d1df

clear: 3e8859650f7a1df2d35311717091d1ab
crypt: C7+E2WcmRvrRlm7nMD8O+3CkPJig8fuDjcMJ2botD8w=
clear: \u20ac ø-ä&#1111;\u0153Ð\u2021·\u2021\u017d· zbb0çïq ´
Here are the functions I'm using:

Code: Select all

function make_iv(){
        srand ((float) microtime() * 10000000);
        return mcrypt_create_iv(mcrypt_get_iv_size (MCRYPT_BLOWFISH, MCRYPT_MODE_CBC), MCRYPT_RAND);
}

function encrypt($key, $data, $iv){
        return mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_CBC, $iv);
}

function decrypt($key, $data, $iv){
        return mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_CBC, $iv);
}

This is a huge problem, and if anyone can help it would really be appreciated. The gravity of the issue is great to say the least.

Thanks!
hanji

Posted: Tue May 10, 2005 2:08 pm
by Roja
I'm going to guess that it's always happening in the last result on the page.

It looks (to me) like a compression error. Check to ensure that all compression options (ob_gzip, output_compression, etc etc) are all turned *OFF*, and then retest.

I'm willing to bet the problem isn't in the encrypt/decrypt, but in the display.

Alternatively, put in a paragraph of placeholder text at the bottom of the page, and I bet *that* gets 'corrupted' the same way.

I could of course be wrong, but it looks like it to me..

Posted: Tue May 10, 2005 3:10 pm
by hanji
Hello

Thanks for your post. It's not the last iteration of the loop on the page.. just ran it again.. notice the middle group.. and the last group. The middle group 'failed' and the last group 'partially' decrypted the string:

Code: Select all

clear: 383f4d2f715d666d8aaa361f5327f770
crypt: KFqzQLIP6hDmh3xc1k7wRNwOVYDFXUm2iLQx4RBtuKk=
clear: 383f4d2f715d666d8aaa361f5327f770

clear: c3be3cc3e771adf9925aa6779ab5b702
crypt: D8NcamA9Afhs29KeD+7HzcVAyoCrdeWYH9GPmL/dSZg=
clear: c3be3cc3e771adf9925aa6779ab5b702

clear: 9e309f185580198075d78e6757727805
crypt: CTim5jBQ0vZf9VFoCLYElyZJVezlSXiwHbU5+4gCS2I=
clear: yîVcõà4æv•úpÿ¥'2y&m&áSƒr!Ji

clear: 2b0233bf3107d7869663d33280577dba
crypt: X2jAniK15bi7TZT49aFhA97hu4JZdlT+Uti9MUQsWmI=
clear: 2b0233bf3107d7869663d33280577dba

clear: c5fc43a3b570a0424acfd976be281547
crypt: tOgcqODD7Ncvq1EWVupDnt3LDoexzEimLwuKQY6g0go=
clear: c5fc43a3b570a0424acfd976Ôxé&#1111;$P
I'm unclear on these options (ob_gzip, output_compression)?

Thanks!
hanji

Posted: Tue May 10, 2005 4:18 pm
by phpScott
I'm going to ask why you need to encrypt and decrypt so much on one page, or is this just for fun/comparission case.

Posted: Tue May 10, 2005 4:34 pm
by hanji
Hello

I don't need to encrypt/decrypt this much on this page.. but proves the point that decryption is not working 100% of the time. Why this 'test' script was created was because I was encrypting a single 'ID' value which is like the 'clear' in my test script.. but was failing. No matter what, I couldn't get the ID value to decrypt right, but other ID fields worked fine. This made me want to see if I could get it to fail (with this script) and was surprised how many times this fails. If I can't get encryption/decryption to work 100% of the time.. what is the point? The problem now is that I have an application that has encrypted data.. and I'm not sure if I'll be able to encrypt them all... which is bad.. very bad.

Thanks for your reply
hanji

Posted: Tue May 10, 2005 4:53 pm
by Roja
I'm still not convinced its not output related, but I'm really baffled. The only thing I could suggest to narrow it down is to try listing the clear output multiple times (on each variable), and see if they all match.

The output ("yîVcõà4æv•úpÿ¥'2y&m&áSƒr!Ji") looks *exactly* like what happens when output buffering finishes improperly, and the browser tries to 'back fill' the gaps with bytes from memory.

Beyond that.. dunno.

Posted: Tue May 10, 2005 5:32 pm
by hanji
Hello again.. thanks much for the help.

I've added this to the script.. so I'm checking the values.. and not just viewing what is presented to the screen.

Code: Select all

define("IV","8c8NCvPtLlA=");
define("KEYVAL","simp0lANDse3cur3");
for($i = 0; $i < 20; $i++){
        $clear          = md5(uniqid(rand(),1));
        $crypt          = base64_encode(encrypt(KEYVAL,trim($clear), base64_decode(IV)));
        $clear2          = decrypt(KEYVAL,trim(base64_decode($crypt)), base64_decode(IV));
        if($clear == $clear2){
                echo "These value match<br>";
        }else{
                echo "These values don't match.. and I'm not outputting them to the browser until now.<br>";
                echo "HERE ARE THE VALUES: ".$clear." AND ".$clear2."<br>";
        }
        echo "<br>";
}

This is my output:

Code: Select all

These value match

These value match

These value match

These value match

These value match

These values don't match.. and I'm not outputting them to the browser until now.
HERE ARE THE VALUES: d07cde7fe6354864d85a0ed19d02d6c6 AND d07cde7fe6354864d85a0ed1V%ú@

These value match

These value match

These value match

These value match

These value match

These values don't match.. and I'm not outputting them to the browser until now.
HERE ARE THE VALUES: bcada7bc6bf910e99f9ddfdfb5ff3d72 AND wP&gt;à(CÂ÷:´ˆð

Posted: Tue May 10, 2005 9:39 pm
by Roja
hanji wrote: Like I've said.. I can run this script over and over.. and I get between 1-2 errors / per 20 iterations. Can you try to run my script.. to see if you get the same outcome??
I can confirm that it happens here too.

Its not output related in any way. I was completely wrong. Sorry about that.

The code seems straightforward, I dont see the bug. :(

Posted: Tue May 10, 2005 10:06 pm
by hanji
Hello All

This is solved. I received the solution from a php-badass!! The problem is sooo simple. It's the trim() on the base64_encode()
I can tell you what's wrong with the code you're using to test - you're
doing a trim() on the base64 decoded value prior to decrypting it. This
should not be done. The reason it's base64 encoded in the first place is
to make sure any trailing spaces are preserved. For example, the output
of encrypt() could theoretically look like this:

"sdflksjfdlsdkfjssdf "

If you insert that into MySQL, the trailing space is lost. Hence, the
base64 encode. Now what your test code is doing is taking that value
from the database, stripping the space off the end and then doing a
decrypt, which then fails, because the space is missing, and this was
part of the original encrypted value.
So the correct code should look like this..

Code: Select all

define("IV","8c8NCvPtLlA=");
define("KEYVAL","simp0lANDse3cur3");
for($i = 0; $i < 20; $i++){
        $clear          = md5(uniqid(rand(),1));
        $crypt          = base64_encode(encrypt(KEYVAL,trim($clear), base64_decode(IV)));
        $clear2          = decrypt(KEYVAL,base64_decode($crypt), base64_decode(IV));
        if($clear == $clear2){
                echo "These value match<br>";
        }else{
                echo "These values don't match.. and I'm not outputting them to the browser until now.<br>";
                echo "HERE ARE THE VALUES: ".$clear." AND ".$clear2."<br>";
        }
        echo "<br>";
}
I really appreciate everyone's help.
hanji

Posted: Wed May 11, 2005 3:29 am
by phpScott
thanks for posting that as I will have to tuck it away in the back of my mind for later reference.

cheers.