SNAG
SNAG

Reputation: 2113

Encrypt numeric URL parameter, result should not be longer than original

I have to encrypt a particular URL parameter. If I want the output to be below 6-7 characters, what algorithm should I use?

The inputs are integer only ranging from 1 to 1,000,000.

Upvotes: 3

Views: 3354

Answers (3)

iceduck
iceduck

Reputation: 163

It's simple convert it to hexadecimal.

$number= 1000000;
echo base_convert($number, 10, 16); // f4240

You want even have fun and convert it to a base 36

$number= 1000000;
echo base_convert($number, 10, 36); 

And do the reverse operation to decode :

$base46_number = 'LFLS';
$decimal = base_convert($base46_number, 36, 10);

Upvotes: 3

Kaii
Kaii

Reputation: 20550

If you require encryption and need to have the shortest result possible, you must use a stream cipher. Blowfish (what you previously used) is a blockcipher and the result will always have the minimum size of one single block.

Find a comparison of stream ciphers on Wikipedia and the list of supported ciphers in the PHP manual on mcrypt

Also, the result of the encryption may contain special chars, so when putting it into an URL as a parameter, you should use urlencode() or base64_encode()

Using urlencode() or base64_encode() will expand your string, making it longer than the original data. This is necessary to make it transport/URL safe.

However, since your input is always a number you can use base_convert() to shorten your input. On the decoding side, you'd have to do reverse the same thing.

To get even shorter results, you could make use of the enminicode() / deminicode() function provided by Aron Cederholm instead of using base_convert().

Here is an example using the RC4 stream cipher (which is not very strong, by the way) and conversion from base 10 to base 36.

NOTE: this example only works on numbers hence its using base_convert() to shrink the input string!

function my_number_encrypt($data, $key, $base64_safe=true, $shrink=true) {
        if ($shrink) $data = base_convert($data, 10, 36);
        $data = @mcrypt_encrypt(MCRYPT_ARCFOUR, $key, $data, MCRYPT_MODE_STREAM);
        if ($base64_safe) $data = str_replace('=', '', base64_encode($data));
        return $data;
}

function my_number_decrypt($data, $key, $base64_safe=true, $expand=true) {
        if ($base64_safe) $data = base64_decode($data.'==');
        $data = @mcrypt_encrypt(MCRYPT_ARCFOUR, $key, $data, MCRYPT_MODE_STREAM);
        if ($expand) $data = base_convert($data, 36, 10);
        return $data;
}

$data = "15231223";
$key = "&/ASD%g/..&FWSF2csvsq2we!%%";

echo "data: ", $data, "\n";
$encrypted = my_number_encrypt($data, $key);
echo "encrypted: ", $encrypted, "\n";
$decrypted = my_number_decrypt($encrypted, $key);
echo "decrypted: ", $decrypted, "\n";

Result:

data: 15231223
encrypted: BuF3xdE
decrypted: 15231223

Upvotes: 6

Xyz
Xyz

Reputation: 6013

function enminicode($int) {
    $foo = '';
    while ($int) {
        $tmp =  $int%256;
        $int = floor($int/256);
        $foo = chr($tmp) . $foo;
    }
    return base64_encode($foo);
}

function deminicode($b64) {
    $moo = base64_decode($b64);
    $res = 0;
    for ($i = 0; $i <= strlen($moo) - 1; ++$i) {
        $res *= 256;
        $res += ord($moo[$i]);
    }
    return $res;
}

$ii = array(12, 123456, 1000000, 467, 9456724645);
foreach ($ii as $i) {
    echo $i, ': ', enminicode($i), ' => ', deminicode(enminicode($i)), PHP_EOL;
}

Which outputs:

12: DA== => 12
123456: AeJA => 123456
1000000: D0JA => 1000000
467: AdM= => 467
9456724645: AjOqKqU= => 9456724645

Works like a charm. For integers up to 1000000 it will consume 4 letters. But do not use this for security! Security by obscurity is never an option, and you never try this method to hide a number from the user if they are not meant to know about it.

Another more elegant solution is to use base_convert, which will yield slightly longer strings, but it will still fit within 6-7 characters.

$int = 987654;
$convert = base_convert($int, 10, 16)
$original = base_convert($convert, 16, 10)
echo $convert, PHP_EOL; #f1206
echo $original, PHP_EOL; #987654

output:

f1206
987654

Upvotes: 3

Related Questions