Затенить / зашифровать номер заказа другим номером: симметричный, «случайный» вид? - PullRequest
26 голосов
/ 04 марта 2009

Клиент имеет простой увеличивающийся номер заказа (1, 2, 3 ...). Он хочет, чтобы конечные пользователи получали 8- или 9-значное (только цифры - без символов) «случайное» число. Очевидно, что это «случайное» число на самом деле должно быть уникальным и обратимым (на самом деле это шифрование actualOrderNumber).

Моей первой мыслью было просто перемешать некоторые биты. Когда я показал клиенту пример последовательности, он пожаловался, что последующие номера obfuscOrderNumbers увеличивались до тех пор, пока они не достигли точки «случайного перемешивания» (точки, где вступили в действие младшие биты). Он хочет, чтобы obfuscOrderNumbers были как можно более случайными.

Моя следующая мысль состояла в том, чтобы детерминистически заполнить линейный конгруэнтный генератор псевдослучайных чисел, а затем принять фактическое значение thOrderNumber. Но в этом случае мне нужно беспокоиться о коллизиях - клиенту нужен алгоритм, который гарантированно не столкнется по крайней мере за 10 ^ 7 циклов.

Моей третьей мыслью было «да, просто зашифровать чертову штуку», но если бы я использовал стандартную библиотеку шифрования, мне пришлось бы постобработать ее, чтобы получить требование только из 8 или 9 цифр.

Моя четвертая мысль состояла в том, чтобы интерпретировать биты actualOrderNumber как целое число в кодировке Грея и вернуть его.

Мой пятый был: «Я, наверное, слишком обдумал это. Держу пари, что кто-то на StackOverflow может сделать это с помощью пары строк кода».

Ответы [ 7 ]

15 голосов
/ 04 марта 2009

Выберите случайным образом 8 или 9-значное число, скажем, 839712541. Затем возьмите двоичное представление вашего номера заказа (в этом примере я не использую дополнение 2), добавьте его к тому же числу бит (30) , переверните его, и xor перевернул номер заказа и магический номер. Например:

1         = 000000000000000000000000000001

Flip      = 100000000000000000000000000000
839712541 = 110010000011001111111100011101
XOR       = 010010000011001111111100011101 = 302841629

2         = 000000000000000000000000000010

Flip      = 010000000000000000000000000000
839712541 = 110010000011001111111100011101
XOR       = 100010000011001111111100011101 = 571277085

Чтобы вернуть порядковые номера, присвойте выходному номеру магическое число, преобразуйте его в битовую строку и переверните.

6 голосов
/ 04 марта 2009
5 голосов
/ 04 марта 2009

Потребуется ли клиенту распределение запутанных последовательных номеров заказов, чтобы они выглядели как что-то конкретное?

Если вы не хотите усложнять себя с помощью шифрования, используйте комбинацию перестановки битов с битом случайного засоления (если у вас есть запасные биты / цифры) с наложением XOR поверх некоторой фиксированной константы (или некоторой функции чего-то, что будет доступен в любой момент вместе с запутанным идентификатором заказа, например, customer_id, который разместил заказ?)


EDIT

Похоже, что все, чего хочет клиент, - это чтобы внешняя сторона не могла определить ход продаж. В этом случае решение перестановки (отображение битов, например, исходный бит 1 отображается на запутанный бит 6, исходный бит 6 отображается на запутанный бит 3 и т. Д.) Должно быть более чем достаточным. Добавьте несколько случайных битов, если вы действительно хотите сделать его более трудным для взлома, при условии, что у вас есть дополнительные биты (например, если исходные номера заказов идут только до 6 цифр, но вам разрешено 8-9 в запутанном номере заказа, затем вы можете использовать 2-3 цифры для случайности перед выполнением битового отображения). Возможно, XOR результат для дополнительного запугивания (любознательная сторона может попытаться сгенерировать два последовательных запутанных заказа, XOR их друг против друга, чтобы избавиться от константы XOR, и затем должна будет определить, какой из ненулевых битов происходит от соли и какие из них поступили с приращением, и действительно ли он получил два последовательных номера заказа или нет ... Он должен был бы повторить это для значительного числа, которое, как он надеется, является последовательными номерами заказа, чтобы взломать его.)


EDIT2

Вы, конечно, можете назначать совершенно случайные числа для идентификаторов обфусцированного порядка, сохранять соответствие в постоянном хранилище (например, в БД) и выполнять обнаружение коллизий, а также удаление обфускации в том же хранилище. Немного излишества, если вы спросите меня, но с положительной стороны, это лучшее, что касается запутывания (и вы реализуете любую функцию распределения, какую пожелает ваша душа, и , вы можете изменить функцию распределения в любое время. )

4 голосов
/ 04 марта 2009

В 9-значном числе первая цифра представляет собой случайный индекс от 0 до 7 (или 1-8). Поместите еще одну случайную цифру в этой позиции. Остальное составляет «реальный номер заказа»:

  • Заказ: 100
  • Случайный индекс: 5
  • Случайная цифра: 4 (гарантировано, выпало кости :))
  • Результат: 500040100

  • Orig Nr: 101

  • Случайный индекс: 2
  • Случайная цифра 6
  • Результат: 200001061

Вы можете решить, что 5-я (или любая другая) цифра является индексом.

Или, если вы можете жить с реальными порядковыми номерами из 6 цифр, вы также можете ввести «вторичный» индекс. И вы можете изменить порядок цифр в «реальном» порядке №.

3 голосов
/ 25 июля 2011

Я видел это довольно поздно, (!) Отсюда мой довольно запоздалый ответ. Это может быть полезно для других, которые придут позже.

Вы сказали: «Моя третья мысль была:« Да, просто зашифруйте чертову штуку », но если бы я использовал стандартную библиотеку шифрования, мне пришлось бы постобработать ее, чтобы получить требование только 8 или 9 цифр . "

Это правильно. Шифрование является обратимым и гарантированно уникальным для данного ввода. Как вы указали, большинство стандартных шифрований не имеют правильного размера блока. Однако есть один Hasty Pudding Cipher , который может иметь любой размер блока от 1 бита и выше.

В качестве альтернативы вы можете написать свой собственный. Учитывая, что вам не нужно чего-то, что АНБ не может взломать, вы можете создать простой шифр Фейстеля для удовлетворения ваших потребностей.

0 голосов
/ 20 ноября 2014
<?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/>";
?>
0 голосов
/ 06 ноября 2011

Если ваш идентификатор заказа уникален, просто вы можете сделать префикс и добавить / смешать этот префикс с вашим идентификатором заказа.

Примерно так:

long pre = DateTime.Now.Ticks % 100;
string prefix = pre.ToString();
string number = prefix + YOURID.ToString()
...