Obscure / encrypt an order number as another numbe

2019-01-21 13:27发布

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."

7条回答
疯言疯语
2楼-- · 2019-01-21 14:14

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.

查看更多
ら.Afraid
3楼-- · 2019-01-21 14:18

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.

查看更多
forever°为你锁心
4楼-- · 2019-01-21 14:23

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.)

查看更多
劫难
5楼-- · 2019-01-21 14:23

If your Order Id is unique, Simply you can make a prefix and add/mix that prefix with your order Id.

Something like this:

long pre = DateTime.Now.Ticks % 100;
string prefix = pre.ToString();
string number = prefix + YOURID.ToString()
查看更多
神经病院院长
6楼-- · 2019-01-21 14:23
<?PHP 

$cry = array(0=>5,1=>3,2=>9,3=>2,4=>7,5=>6,6=>1,7=>8,8=>0,9=>4);

function enc($e,$cry,$k){
    if(strlen($e)>10)die("max encrypt digits is 10");
    if(strlen($e) >= $k)die("Request encrypt must be lesser than its length");
    if(strlen($e) ==0)die("must pass some numbers");

    $ct =  $e;
    $jump = ($k-1)-strlen($e);
    $ency = $cry[(strlen($e))];
    $n = 0;
    for($a=0;$a<$k-1;$a++){
        if($jump > 0){
            if($a%2 == 1){
                $ency .=rand(0,9);
                $jump -=1;
            }else{
                if(isset($ct[$n])){
                    $ency.=$cry[$ct[$n]];
                    $n++;
                }else{
                    $ency .=rand(0,9);
                    $jump -=1;
                }
            }
        }else{
            $ency.= $cry[$ct[$n]];
            $n++;
        }
    }
    return $ency;
}

function dec($e,$cry){
    //$decy = substr($e,6);
    $ar = str_split($e,1);
    $len = array_search($ar[0], $cry);
    $jump = strlen($e)-($len+1);
    $val = "";
    for($i=1;$i<strlen($e);$i++){
        if($i%2==0){
            if($jump >0){
                //$val .=array_search($e[$i], $cry);
                $jump--;
            }else{
                $val .=array_search($e[$i], $cry);
            }
        }else{
            if($len > 0){
                $val .=array_search($e[$i], $cry);
                $len--;
            }else{
                $jump--;
            }
        }
    }
    return $val;
}
if(isset($_GET["n"])){
    $n = $_GET["n"];
}else{
    $n = 1000;
}

$str = 1253;
$str = enc($str,$cry,15);
echo "Encerypted Value : ".$str ."<br/>";
$str = dec($str,$cry);
echo "Decrypted Value : ".$str ."<br/>";
?>
查看更多
登录 后发表回答