Я ищу способ зашифровать / запутать целочисленный идентификатор в другое целое число. Точнее мне нужна функция int F(int x)
, чтобы
- x <-> F (x) взаимно однозначное соответствие (если x! = y, F (x)! = F (y))
- учитывая F (x), легко определить x, поэтому F не является хеш-функцией
- учитывая x и F (x) трудно / невозможно узнать F (y), что-то вроде
x ^ 0x1234
не сработает
Для ясности, я не ищу надежного решения для шифрования, это всего лишь обфускация. Представьте себе веб-приложение с URL-адресами вроде example.com/profile/1
и example.com/profile/2
т. Д. Сами профили не являются секретными, но я бы хотел, чтобы случайные вуайеристы не просматривали / извлекали все профили один за другим, поэтому я бы предпочел спрятать их за чем-то вроде example.com/profile/23423
и example.com/profile/80980234
т. токены, хранящиеся в базе данных, могут выполнять эту работу довольно легко, мне любопытно, есть ли для этого какая-то простая математика.
Одно важное требование, которое я не понял, - это то, что результаты должны выглядеть «случайными», то есть, учитывая последовательность x,x+1,...,x+n
, F(x),F(x+1)...F(x+n)
не должны образовывать прогрессию какого-либо вида.
источник
Ответы:
Затемните его комбинацией двух или трех простых методов:
x
иy
которые являются мультипликативными обратен друг к другу ( по модулю- 32 ), затем умножить наx
запутать и умножить наy
восстановление, все умножения по модулю- 32 (источник: «Практическое применение мультипликативных обратных» Эрик Липперт )Метод числовой системы переменной длины сам по себе не подчиняется вашему требованию "прогрессии". Он всегда производит короткие арифметические прогрессии. Но в сочетании с каким-либо другим методом дает хорошие результаты.
То же верно и для метода модульного представления.
Вот пример кода C ++ для 3 из этих методов. В примере перестановки битов могут использоваться разные маски и расстояния, чтобы быть более непредсказуемым. Два других примера хороши для небольших чисел (просто для того, чтобы дать представление). Их следует расширить, чтобы правильно скрыть все целочисленные значения.
источник
Вы хотите, чтобы преобразование было обратимым, а не очевидным. Похоже на шифрование, которое берет число из заданного диапазона и производит другое число в том же диапазоне. Если ваш диапазон - 64-битные числа, используйте DES. Если ваш диапазон составляет 128-битные числа, используйте AES. Если вам нужен другой диапазон, то лучшим выбором, вероятно, будет шифр Hasty Pudding , который предназначен для работы с блоками разных размеров и с диапазонами чисел, которые не вписываются в блок, например от 100000 до 999999.
источник
Обфускации недостаточно с точки зрения безопасности.
Однако, если вы пытаетесь помешать случайному наблюдателю, я бы порекомендовал комбинацию двух методов:
Вот пример (с использованием псевдокода):
Я не тестировал его, но думаю, что это обратимо, должно быть быстро и не так просто, чтобы выявить метод.
источник
return x XOR rotr(31415927, 5)
правда? Последний xor отменяет первое, а вращение отменяет друг друга ... конечно, любая цепочка обратимых операций также обратима, поэтому она удовлетворяет этому условию.x = x XOR F(0)
, илиx = x XOR 3087989491
, илиx = x XOR rotr(31415927, 5)
. Ваши первый и последний xors отрицают друг друга, поэтому все, что вы делаете, это xoring битового ввода с помощью ключа - или, что эквивалентно, xoring ввода с битовым сдвигом ключа. Обратите внимание, что это верно, даже если вы использовали разные ключи для каждого этапа - все ключи могут быть объединены в один ключ, который можно сопоставить с открытым текстом.Я нашел этот конкретный фрагмент кода Python / PHP очень полезным:
https://github.com/marekweb/opaque-id
источник
Я написал код JS, используя некоторые идеи из этой ветки:
Это дает хорошие результаты, например:
Тестирование с помощью:
XOR1
иXOR2
представляют собой просто случайные числа от 0 доMAX
.MAX
есть2**32-1
; вы должны установить это значение, которое, по вашему мнению, будет вашим наивысшим идентификатором.COPRIME
- число, взаимно простое с /MAX
. Я считаю, что простые числа взаимно просты со всеми остальными числами (кроме кратных самих себя).INVERSE
это сложно понять. Эти сообщения в блоге не дают прямого ответа, но WolframAlpha может понять это за вас . По сути, просто решите уравнение(COPRIME * x) % MAX = 1
дляx
.build
Функция что - то я создал , чтобы сделать его проще для создания этих кодирования / декодирования трубопроводов. Вы можете скормить ему столько операций, сколько захотите,[encode, decode]
попарно. Эти функции должны быть равными и противоположными. ЭтиXOR
функции сами по себе дополняют друг друга, поэтому вам не нужна пара.Вот еще одна забавная инволюция :
(предполагает 24-битные целые числа - просто измените числа на любой другой размер)
источник
n
постфикс числа для BigInts . Это новая функция JS, которая позволяет обрабатывать действительно большие числа. Мне нужно было использовать его, потому что я умножаю на действительно большие числа, что может привести к временному превышению одного из промежуточных значенийNumber.MAX_SAFE_INTEGER
и потере точности.Сделайте что-нибудь с битами идентификатора, чтобы их не уничтожить. Например:
Для расшифровки проделайте все в обратном порядке.
Создайте программу, которая «зашифрует» для вас некоторые интересные значения и поместит их в таблицу, которую вы сможете изучить. Используйте ту же программу. ПРОВЕРЬТЕ свою процедуру шифрования / дешифрования со всем набором значений, которые вы хотите иметь в своей системе.
Добавляйте элементы из приведенного выше списка в процедуры, пока ваши числа не будут выглядеть для вас правильно искаженными.
Для чего-нибудь еще возьмите копию Книги .
источник
Я написал статью о безопасных перестановках с блочными шифрами , которые должны соответствовать вашим требованиям, как указано.
Я бы посоветовал, однако, что если вы хотите, чтобы идентификаторы трудно угадывать, вы должны просто использовать их в первую очередь: сгенерировать UUID и использовать их в качестве первичного ключа для ваших записей - нет необходимости иметь возможность для преобразования в «настоящий» идентификатор и обратно.
источник
Не уверен, насколько «сложным» это должно быть, насколько быстро или как мало памяти использовать. Если у вас нет ограничений памяти, вы можете составить список всех целых чисел, перемешать их и использовать этот список в качестве сопоставления. Однако даже для 4-байтового целого числа потребуется много памяти.
Однако это можно сделать меньше, поэтому вместо отображения всех целых чисел вы должны отобразить только 2 (или в худшем случае 1) байт и применить это к каждой группе в целом числе. Итак, используя 2 байта, целое число будет (группа1) (группа2) вы сопоставите каждую группу через случайную карту. Но это означает, что если вы измените только group2, то сопоставление для group1 останется прежним. Это можно «исправить», назначив разные биты каждой группе.
Итак, * (group2) может быть (бит 14,12,10,8,6,4,2,0), поэтому добавление 1 изменит как group1, так и group2 .
Тем не менее, это только безопасность по неизвестности, любой, кто может вводить числа в вашу функцию (даже если вы держите функцию в секрете), может довольно легко понять это.
источник
Создайте закрытый симметричный ключ для использования в вашем приложении и зашифруйте им целое число. Это удовлетворяет всем трем требованиям, включая самое сложное №3: нужно угадать ключ, чтобы сломать вашу схему.
источник
То, что вы здесь описываете, кажется противоположностью односторонней функции: ее легко инвертировать, но очень сложно применить. Один из вариантов - использовать стандартный готовый алгоритм шифрования с открытым ключом, в котором вы фиксируете (секретный, случайно выбранный) открытый ключ, который вы храните в секрете, и закрытый ключ, которым вы делитесь со всем миром. Таким образом, ваша функция F (x) будет шифрованием x с использованием открытого ключа. Затем вы можете легко расшифровать F (x) обратно до x, используя закрытый ключ дешифрования. Обратите внимание, что роли открытого и закрытого ключей здесь поменялись местами - вы выдаете закрытый ключ всем, чтобы они могли расшифровать функцию, но держите открытый ключ в секрете на своем сервере. Сюда:
Это дает много преимуществ. Во-первых, вы можете быть уверены, что криптосистема безопасна, поскольку, если вы используете хорошо зарекомендовавший себя алгоритм, такой как RSA, вам не нужно беспокоиться о случайной небезопасности. Во-вторых, для этого уже существуют библиотеки, поэтому вам не нужно много писать код и вы можете быть защищены от атак по побочным каналам. Наконец, вы можете дать возможность любому пойти и инвертировать F (x), при этом никто не сможет вычислить F (x).
Одна деталь - вам определенно не следует использовать здесь только стандартный тип int. Даже с 64-битными целыми числами существует так мало возможных комбинаций, что злоумышленник может просто перебрать все, пока не найдет шифрование F (y) для некоторого y, даже если у них нет ключа. Я бы посоветовал использовать что-то вроде 512-битного значения, поскольку даже научно-фантастическая атака не сможет перебрать это.
Надеюсь это поможет!
источник
Если
xor
приемлемо для всего, кроме выводаF(y)
данного,x
иF(x)
тогда я думаю, что вы можете сделать это с солью . Сначала выберите секретную одностороннюю функцию. НапримерS(s) = MD5(secret ^ s)
. ТогдаF(x) = (s, S(s) ^ x)
гдеs
выбирается случайным образом. Я написал это как кортеж, но вы можете объединить две части в целое число, напримерF(x) = 10000 * s + S(s) ^ x
. Расшифровкаs
снова извлекает соль и используетF'(F(x)) = S(extract s) ^ (extract S(s)^x)
. Учитывая,x
иF(x)
вы можете видетьs
(хотя он немного запутан), и вы можете сделать вывод,S(s)
но для другого пользователяy
с другой случайной сольюt
пользователь, зная,F(x)
не может найтиS(t)
.источник
S(s)
также будет выглядеть случайным, поэтомуF(x)
не будет вообще никакой прогрессии.