0

I am trying to use mcrypt to encrypt a value on one PHP site and decrypt it on another one. Sometimes it works (like 80% of the time), sometimes it doesn't work. Now I found out that the encrypted text is different when encrypting the same values with the same key. How is this possible? What am I missing?

Here is the code for encryption:

# key is always the same
$key = "mysimplekey";

# text is always the same
$plaintext = "text_to_encrypt";

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);

$ciphertext = $iv . $ciphertext;

$ciphertext_base64 = base64_encode($ciphertext);
$ciphertext_url = rawurlencode($ciphertext_base64);

# gives different values for the same key & encryption text:                    
echo $ciphertext_url;

Code for decryption:

$key = 'mysimplekey';

$ciphertext_dec = base64_decode($_REQUEST['u']);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);

# retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
$iv_dec = substr($ciphertext_dec, 0, $iv_size);

# retrieves the cipher text (everything except the $iv_size in the front)
$ciphertext_dec = substr($ciphertext_dec, $iv_size);

# may remove 00h valued characters from end of plain text
$ciphertext_dec = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec));
Danmoreng
  • 2,367
  • 1
  • 19
  • 32
  • 1
    URL's have a maximum input (i believe 2048), can this be the cause? – Youri Jan 29 '16 at 16:50
  • `$iv` - you're generating new initialization vector every time – Iłya Bursov Jan 29 '16 at 16:53
  • Yes but the vector is prepended to the string and this should not be the problem for decryption should it? But yeah technically you're right my question was asked in a wrong way. – Danmoreng Jan 29 '16 at 16:54
  • how decryptor will know what part of final url is iv and what is text? – Iłya Bursov Jan 29 '16 at 16:55
  • How are you constructing the URL to send to the decryption script? If you are doing it in javascript, something may be adding an additional layer of encoding. – ChrisRibe Jan 29 '16 at 20:11
  • Easy mode: Don't implement it yourself, just use [a secure encryption library](https://github.com/defuse/php-encryption). – Scott Arciszewski Jan 29 '16 at 20:24
  • @ChrisRive the URL is constructed in PHP, simply something like echo 'link.com/site.html?parameter1=xyz&u='. $ciphertext_url; – Danmoreng Jan 30 '16 at 19:38

2 Answers2

0

I suspect the combination of rawurlencode() and the decoding done by PHP to populate the $_REQUEST array are mangling your ciphertext/iv.

Update: I tested your code and it is working as expected in my implementation. Perhaps the encoded text is being modified on the client side in your implementation.

ChrisRibe
  • 168
  • 5
  • 1
    I don't see `rawurldecode` in OP's code, so this might be it. – Artjom B. Jan 29 '16 at 19:18
  • I had rawurldecode() in the decoding before and it made no difference. The text won't be modified on the client side, since it is just embeded as url parameter into a link of the page. This link then links to the page which does the decryption. It's only because on the first page I have a user login value which I don't have on the second page, but need to pass to it to make sure the user is authorized to access the content. – Danmoreng Jan 30 '16 at 19:33
0

Sooooo.

The problem was apparently nothing I mentioned in the question itself. I am sorry.

Standalone this should work like @ChrisRibe tested out in his answer.

The problem in this particular case - which I didn't mention in my question - was, that the whole URL was ALSO urlencoded because it was passed as a PARAMETER onto another url (namely an html2pdf.it server). Therfor it worked if the encrypted, base64-encoded text had no special url reserved characters in it - but of course did not work if there were any url reserved characters!

Solution:

Instead of using rawurlencode for the base64-encoded encrypted text I now replace the 3 symbols which cause problems with urls with my own function, like answered in this stackoverflow question: Passing base64 encoded strings in URL

function base64_url_encode($input) {
 return strtr(base64_encode($input), '+/=', '-_~');
}

function base64_url_decode($input) {
 return base64_decode(strtr($input, '-_~', '+/='));
}
Community
  • 1
  • 1
Danmoreng
  • 2,367
  • 1
  • 19
  • 32