How can you inexpensively two-way encrypt a 32 bit int, such that every number maps to some other int in that space and back in a way that's difficult to predict?

And doesn't require pre-storing 4.29 billion ints in a mapping table, of course.


Solution 1:

What you want is a 32-bit block cipher. Unfortunately, most block ciphers are 64-bits or more due to the weaknesses of a short block size. If you can handle the encrypted int being twice as large as the input, then you can just use Blowfish, TDES, or some other nicely vetted 64-bit block cipher.

If you really need 32 bits and don't mind the decreased security then its easy enough to trim a Feistel network cipher like Blowfish down to any block length that's a multiple of 2 and less than the starting cipher. For Blowfish, just split your input number evenly between the two half blocks, and trim the output of the F function and the P-values down to 1/2 your target block size. This can all be done after keying the algorithm as usual.

Solution 2:

Obviously, you need some kind of random key for it to be secure. In that case:

int original = 42;
int key = give_me_a_random_int();

int encrypted = original ^ key;
int unencrypted = encrypted ^ key;

// now, unencrypted == original == 42

This is just a simple XOR. XORing again will reverse this process.

Also, I should note that this is only secure for one use. It's called the One time pad. If you use the same key twice on non-random data, it may be possible for an attacker to decipher it.