Обратный оператор умножения в С++

Я пытаюсь отменить десериализатор приложения, и я в основном закончил, но я застрял в этой проблеме. Приложение по какой-то причине декодирует 4-байтовые числа, умножая их на ключ кодирования (или ключ декодирования, если на то пошло).

int decoded_number = (encode_key * encoded_number);

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

int encoded_number = (encode_key * decoded_number);

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

for (int i = INT_MIN; i < INT_MAX; i++){
  if (i * encode_key == decoded_number)
    return i; /* "i" is the encoded number */
}

На данный момент я понятия не имею, что еще попробовать. Мой код ниже:

#include <iostream>
using namespace std;

int encode_key = -381784151; /* Key I took from the application */
int encoded_numbers[2] = {-810310503, 1520670208}; /* Numbers I took from the app */

int bruteforce(int decoded_number){
    for (int i = -2147483648; i < 2147483647; i++){ /* min and max int*/
        if (encode_key * i == decoded_number){ /* brute comparison */
            return i;
        }
    }
}

int main()
{
    for (int i = 0; i < 2; i++){
        int encoded_number = encoded_numbers[i];
        int decoded_number = encode_key * encoded_number;
        int attempt_encode = encode_key * decoded_number;
        int brute_encode = bruteforce(decoded_number);

        cout << "STARTING WITH NUMBER" << i+1 << "\n";
        cout << "Encoded Number: " << encoded_number << "\n";
        cout << "Decoded Number: " << decoded_number << "\n";
        cout << "Attempt to Re-Encode (FAIL): " << attempt_encode << "\n";
        cout << "Bruteforce Encode (SLOW!): " << brute_encode << "\n\n";
    }
    return 0;
}

Нажмите здесь, чтобы запустить код в браузере

Обратным умножению является деление.

Barmar 04.02.2019 21:31

Сама концепция должна работать на C, а не только на C++.

Jana Schweizer 04.02.2019 21:31

Обратите внимание, что если бы (encode_key * encoded_number) переполнился во время хэширования, это было бы неопределенным поведением (может быть, это не было сделано в С++?). То же самое верно и для ваших попыток обратить хэш. Редактировать: Итак, если encode_key больше 1, i * encode_key == decoded_number имеет неопределенное поведение.

François Andrieux 04.02.2019 21:32

@Barmar результат умножения превышает ограничение в 4 байта, поэтому деление в этом случае не сработает.

Jana Schweizer 04.02.2019 21:33

@JanaSchweizer В С++ для интегральных типов signed это так. Поскольку любой результат умножения, который будет переполняться, в любом случае не определен. Изменить. Если вы хотите реализовать некоторую форму умножения по модулю с целыми числами signed, вам сначала нужно решить, как вы хотите, чтобы оно работало, а затем реализовать его самостоятельно.

François Andrieux 04.02.2019 21:34

@JanaSchweizer Тогда умножение приводит к неопределенному поведению. Вам нужно использовать unsigned int, если вы хотите модульную арифметику.

Barmar 04.02.2019 21:34

также encode_key * i будет переполняться в вашем цикле (фактически для большинства значений i)

463035818_is_not_a_number 04.02.2019 21:34

Модульное умножение не может быть легко инвертировано. См. модульное деление

Barmar 04.02.2019 21:35

@FrançoisAndrieux Я действительно просто ищу почти мгновенный способ воссоздать аналогичный encoded_number без грубой силы, потому что существует множество различных комбинаций от INT_MIN до INT_MAX, которые можно использовать.

Jana Schweizer 04.02.2019 21:35

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

Barmar 04.02.2019 21:36

не в том ли весь смысл шифрования, что трудно вычислить обратное?

463035818_is_not_a_number 04.02.2019 21:36

@EricPostpischil Чтобы узнать больше, я пытаюсь создать данные сохранения для приложения. Ничего со зла.

Jana Schweizer 04.02.2019 21:40

@Barmar А, моя ошибка. Я пытаюсь сериализовать данные, а не хэш. :)

Jana Schweizer 04.02.2019 21:43

Зачем вам использовать умножение на ключ кодирования при сериализации?

Barmar 04.02.2019 21:44

Из того, что я собрал до сих пор, я полагаю, что он там для защиты данных сохранения, поэтому вам нужен ключ, чтобы прочитать его. Однако мне сказали, что сериализатор был выпущен где-то в Интернете, но он не обновлен. В любом случае, действительно трудно претендовать на умножение как на собственный алгоритм кодирования. @Бармар

Jana Schweizer 04.02.2019 21:48

Мультипликативная инверсия -381784151 по модулю 2^32 равна 491758745. Это означает, что если y является результатом умножения x на -381784151 и взятия младших 32 битов результата, то умножение y на 491758745 и взятие младших 32 битов результата результат дает х. (Эта арифметика обычно выполняется с целыми числами без знака. Если вы используете целые числа со знаком, вы должны убедиться, что они переносятся по модулю 2^32. C и C++ не определяют поведение переполнения целых чисел со знаком.)

Eric Postpischil 04.02.2019 21:54

@Barmar: модульное умножение либо можно инвертировать (информация не теряется), либо нельзя (информация теряется). Если можно, то легко. Метод нахождения мультипликативного обратного является простым расширением алгоритма Евклида и требует всего несколько строк кода.

Eric Postpischil 04.02.2019 21:56

@EricPostpischil Я признаю, что на самом деле я не специалист по математике, я думал, что уникального результата может не быть. Но я же дал ссылку на сайт с кодом.

Barmar 04.02.2019 21:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
18
461
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Спасибо @EricPostpischil за отличный ответ. Чтобы обратить умножение, все, что вам нужно сделать, это умножить декодированное число на мультипликативное значение, обратное ключу. Вот пример кода с решением.

#include <iostream>
using namespace std;

int encode_key = -381784151;
int encoded_numbers[2] = {-810310503, 1520670208};

int getinverse(int key){
    for (int i = -2147483648; i < 2147483647; i++){ /* min and max int*/
        if (key * i == 1){ /* brute comparison */
            return i;
        }
    }
}

int main()
{
    int inverse = getinverse(encode_key); /* Grab the multiplicative inverse of encode_key */

    for (int i = 0; i < 2; i++){
        int encoded_number = encoded_numbers[i];
        int decoded_number = encode_key * encoded_number;
        int attempt_encode = inverse * decoded_number; /* multiply inverse and decoded_number */

        cout << "STARTING WITH NUMBER" << i+1 << "\n";
        cout << "Encoded Number: " << encoded_number << "\n";
        cout << "Decoded Number: " << decoded_number << "\n";
        cout << "Attempt to Re-Encode (CORRECT!): " << attempt_encode << "\n\n";
    }
    return 0;
}

Другие вопросы по теме