11

I'm messing with a simple authorization scheme. I think the easiest way to do it without SSL or other HTTP auth would be a shared key encryption. Adapting a simple example from the PHP manual, I came up with the following:

$text = "boggles the invisible monkey will rule the world";
$key = "This is a very secret key";

$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

$enc = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $text, MCRYPT_MODE_ECB, $iv);

$iv = base64_encode($iv);
$enc = base64_encode($enc);

echo '<a href="temp2.php?iv='.$iv.'&text='.$enc.'">link</a><br />';

The page that receives this request (temp2.php) looks like this:

$key = "This is a very secret key";

$iv = base64_decode($_GET["iv"]);
$enc = base64_decode($_GET["text"]);

$crypttext = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $enc, MCRYPT_MODE_ECB, $iv);

echo "$crypttext<br>";

This gets very close, but it doesn't decode properly-- it echoes

boggles the invisible monkey will rule t—;eôügJë

I'm not sure what the hangup is, I tried urlencode/urldecode and htmlentities, thinking maybe a character was mangled in the request, but no difference.

Is there something else I'm missing? Perhaps padding?

Thanks

julio
  • 6,630
  • 15
  • 60
  • 82
  • 3
    Base64 strings frequently end in the `=` char. I bet you'r losing one during URL parsing (since = is something of a special char). Try `urlencode(base64_encode())`? – Frank Farmer Apr 22 '11 at 17:08
  • 1
    Plus, you should be posting this data, since there are limits to the size of the get string (it's up there in modern servers, but they do exist) – ircmaxell Apr 22 '11 at 17:10
  • @Frank Farmer-- I've tried the urlencode/decode route. Didn't help. @ircmaxwell-- you're right, but this is a pretty small string initially. – julio Apr 22 '11 at 17:13

1 Answers1

29

It happens that your encrypted text will end up looking something like:

Z5DlBqT8yEB4HKLkAlvfJoWaHgnNVLFh7jls6L85sLriedc82uFQxm+M62I41oB7

See that plus sign there? Plus signs in URLs get turned into spaces.

When manually converting that plus sign to a space and decrypting the result, the output is the corrupted junk that you've witnessed.

You should run both the IV and the encrypted text through rawurlencode (not urlencode) before sticking it into the link. This will properly encode the plus sign, which will preserve it through the process. You don't need to (and should not) urldecode the string on the other side -- PHP will have done this for you.

Charles
  • 50,943
  • 13
  • 104
  • 142
  • 1
    @Frank, it happens that PHP's implementation of base64 decode ignores missing or extra equal signs at the end. Other implementations may not be so liberal, so that could indeed be a problem in other circumstances. – Charles Apr 22 '11 at 17:45