9

I'm building a with-source system which I am giving out on the 'net for providing adoptable virtual pets. The system will be owned mainly by kids. Since I want it to be usable for absolute beginner programmers, there are several complexity constraints on my system: It can't use libraries that don't commonly ship with PHP, and it can't touch a database or write to other permanent storage.

When each pet is adopted, the visitor will randomly get given one of a series of slightly different variations of that pet. The variations initially look the same, but grow up over time to become different pets. The visitor will be given a short code in HTML which links to the image of their pet. Since there is no permanent storage available server-side, the user's image link must contain all of the information to determine which pet variation they ended up getting.

At the moment, the URL just contains the ID of the pet and the ID of the variation that the user got. The problem with this is that, by comparing codes with each other, the users can figure out who amongst them ended up with the same variation. Since some variations are rarer than others, users can spot the rare variations easily before the difference is even visually apparent.

What I would like is an encryption system for the details in the URL. Something that obscures the variation ID so that each user gets a different URL with high probability. I thought of using the variation ID (3 or 4 bits) as the low bits or high bits of a large random number, but the users will spot the pattern in this. Ideally the encryption system would be parametrized so that each installation of my system would use a slightly different encryption.

PHP's mcrypt library would probably have something useful in it, but it doesn't seem to be very common amongst hosters.

Is there a simple, parametrized, obfuscation/encryption I can use here?

Piskvor left the building
93.1k46 gold badges182 silver badges226 bronze badges
asked Nov 29, 2008 at 3:08

3 Answers 3

16

You are looking for "one time padding" encryption. It takes a key and does modulus addition to characters to create the encrypted string.

function ecrypt($str){
 $key = "abc123 as long as you want bla bla bla";
 for($i=0; $i<strlen($str); $i++) {
 $char = substr($str, $i, 1);
 $keychar = substr($key, ($i % strlen($key))-1, 1);
 $char = chr(ord($char)+ord($keychar));
 $result.=$char;
 }
 return urlencode(base64_encode($result));
}
function decrypt($str){
 $str = base64_decode(urldecode($str));
 $result = '';
 $key = "must be same key as in encrypt";
 for($i=0; $i<strlen($str); $i++) {
 $char = substr($str, $i, 1);
 $keychar = substr($key, ($i % strlen($key))-1, 1);
 $char = chr(ord($char)-ord($keychar));
 $result.=$char;
 }
return $result;
}

So that's simple string encryption. What I would do is serialize the array of the user's parameters and pass it as a variable in the link:

$arr = array(
 'pet_name'=>"fido",
 'favorite_food'=>"cat poop",
 'unique_id'=>3848908043
);
$param_string = encrypt(serialize($arr));
$link = "/load_pet.php?params=$param_string";

In load_pet.php you should do the opposite:

$param_string = $_GET["params"];
$params = unserialize(decrypt($param_string));

Bam.

thefoyer
3143 silver badges20 bronze badges
answered Nov 29, 2008 at 5:16
Sign up to request clarification or add additional context in comments.

3 Comments

Of course this is just a rough outline.. you'll have to handle the case where the user passes an invalid param_string.. eg: it won't unserialize so you've gotta catch that.
I don't see anything here that would give different outputs for the same input, which is what I'm looking for.
This sounds like a great idea, but in my case, I found that unserialize doesn't seem to work with content encrypted by this function. I tried both serializing first and then encrypting, and encrypting first and then serializing. In both cases, the unserialize function just returned false.
11

If you are expecting a relatively low sophistication level, then you can do a very simple "xor" encryption and "store" the key as part of the URL. Then you can just use php's rand() or /dev/random or whatever to generate keys.

Low-sophistication users won't readily figure out that all they need to do is xor the lower half of their pet ID with the upper half to get a value which can be compared to their friends. I would guess most people who would be able to recognize that was what was going on wouldn't take the time to figure it out, and those people are outside of your target audience anyways.

Edit: If it wasn't obvious, I'm saying you give a different key to every pet (since giving the same one would not solve your problem). So if the pet variation (petvar) is a 16 bit number, you generate a 16-bit random number (rnd), then you do this: petvar = (petvar^rnd)<<16 | rnd; and then you can reverse that operation to extract the rnd and then petvar^rnd, and then just xor it again to get the original petvar.

answered Nov 29, 2008 at 3:13

1 Comment

Sounds like a good strategy. I could also XOR the whole string with a installation-specific key. Your intuitions about the sophistication level of the "attackers" is very correct.. :)
2

Why not just give each user a long, random ID and then store all the details about their pet on the server? Best practice is not to store anything in the URL, encrypted or not. All you should need is a session ID.

answered Nov 29, 2008 at 4:46

1 Comment

Of course, that's what I do on my own server. But I want a system that kids can use on their own server to give away pets, even if there is no decent storage available: Databases aren't always available on free providers and are difficult to configure, flat-file storage requires too much code.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.