Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Obscure / encrypt an order number as another number: symmetrical, "random" appearance?

Client has an simple increasing order number (1, 2, 3...). He wants end-users to receive an 8- or 9- digit (digits only -- no characters) "random" number. Obviously, this "random" number actually has to be unique and reversible (it's really an encryption of the actualOrderNumber).

My first thought was to just shuffle some bits. When I showed the client a sample sequence, he complained that subsequent obfuscOrderNumbers were increasing until they hit a "shuffle" point (point where the lower-order bits came into play). He wants the obfuscOrderNumbers to be as random-seeming as possible.

My next thought was to deterministically seed a linear congruential pseudo-random-number generator and then take the actualOrderNumber th value. But in that case, I need to worry about collisions -- the client wants an algorithm that is guaranteed not to collide in at least 10^7 cycles.

My third thought was "eh, just encrypt the darn thing," but if I use a stock encryption library, I'd have to post-process it to get the 8-or-9 digits only requirement.

My fourth thought was to interpret the bits of actualOrderNumber as a Gray-coded integer and return that.

My fifth though was: "I am probably overthinking this. I bet someone on StackOverflow can do this in a couple lines of code."

like image 680
Larry OBrien Avatar asked Mar 04 '09 18:03

Larry OBrien


5 Answers

Pick a 8 or 9 digit number at random, say 839712541. Then, take your order number's binary representation (for this example, I'm not using 2's complement), pad it out to the same number of bits (30), reverse it, and xor the flipped order number and the magic number. For example:

1         = 000000000000000000000000000001

Flip      = 100000000000000000000000000000
839712541 = 110010000011001111111100011101
XOR       = 010010000011001111111100011101 = 302841629

2         = 000000000000000000000000000010

Flip      = 010000000000000000000000000000
839712541 = 110010000011001111111100011101
XOR       = 100010000011001111111100011101 = 571277085

To get the order numbers back, xor the output number with your magic number, convert to a bit string, and reverse.

like image 134
Pesto Avatar answered Nov 20 '22 23:11

Pesto


Hash function? http://www.partow.net/programming/hashfunctions/index.html

like image 28
Brian Knoblauch Avatar answered Nov 20 '22 21:11

Brian Knoblauch


Will the client require the distribution of obfuscated consecutive order numbers to look like anything in particular?

If you do not want to complicate yourself with encryption, use a combination of bit shuffling with a bit of random salting (if you have bits/digits to spare) XOR-superimposed over some fixed constant (or some function of something that would be readily available alongside the obfuscated order ID at any time, such as perhaps the customer_id who placed the order?)


EDIT

It appears that all the client desires is for an outside party to not be able to infer the progress of sales. In this case a shuffling solution (bit-mapping, e.g. original bit 1 maps to obfuscated bit 6, original bit 6 maps to obfuscated bit 3, etc.) should be more than sufficient. Add some random bits if you really want to make it harder to crack, provided that you have the additional bits available (e.g. assuming original order numbers go only up to 6 digits, but you're allowed 8-9 in the obfuscated order number, then you can use 2-3 digits for randomness before performing bit-mapping). Possibly XOR the result for additional intimidation (an inquisitive party might attempt to generate two consecutive obfuscated orders, XOR them against each other to get rid of the XOR constant, and would then have to deduce which of the non-zero bits come from the salt, and which ones came from an increment, and whether he really got two consecutive order numbers or not... He would have to repeat this for a significant number of what he'd hope are consecutive order numbers in order to crack it.)


EDIT2

You can, of course, allocate completely random numbers for the obfuscated order IDs, store the correspondence to persistent storage (e.g. DB) and perform collision detection as well as de-obfuscation against same storage. A bit of overkill if you ask me, but on the plus side it's the best as far as obfuscation goes (and you implement whichever distribution function your soul desires, and you can change the distribution function anytime you like.)

like image 6
vladr Avatar answered Nov 20 '22 22:11

vladr


In 9 digit number, the first digit is a random index between 0 and 7 (or 1-8). Put another random digit at that position. The rest is the "real order number:

  • Orig order: 100
  • Random index: 5
  • Random digit: 4 (guaranteed, rolled a dice :) )
  • Result: 500040100

  • Orig Nr: 101

  • Random index: 2
  • Random digit 6
  • Result: 200001061

You can decide that the 5th (or any other) digit is the index.

Or, if you can live with real order numbers of 6 digits, then you can introduce "secondary" index as well. And you can reverse the order of the digits in the "real" order nr.

like image 4
Sunny Milenov Avatar answered Nov 20 '22 22:11

Sunny Milenov


I saw this rather late, (!) hence my rather belated response. It may be useful to others coming along later.

You said: "My third thought was "eh, just encrypt the darn thing," but if I use a stock encryption library, I'd have to post-process it to get the 8-or-9 digits only requirement."

That is correct. Encryption is reversible and guaranteed to be unique for a given input. As you point out, most standard encryptions do not have the right block size. There is one however, Hasty Pudding Cipher which can have any block size from 1 bit upwards.

Alternatively you can write your own. Given that you don't need something the NSA can't crack, then you can construct a simple Feistel cipher to meet your needs.

like image 3
rossum Avatar answered Nov 20 '22 21:11

rossum