Помогите обернуть цикл вспять

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Ответить
shwwawaw
Сообщения: 3
Зарегистрирован: 02 апр 2018, 08:16

02 апр 2018, 08:18

Доброго времени суток. Помогите решить одну проблему
у меня есть программа следующего вида:

Код: Выделить всё

#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>
#define k "jf1ay9238x0ax0"
char f1(char a);
int a1(int a);

int main()
{
    srand(time(0));

    printf("Enter path:");
    fflush(stdout);
    char p[64];
    scanf("%s", p);
    char c;
    do {
        c = getchar();
    } while (c != '\n' && c != EOF);

    FILE* f = fopen(p, "rb");
    if (f == NULL) {
        printf("Error opening file");
        getch();
        exit(-3);
    }
    char m[64];
    fread(&m, sizeof(char), 64, f);
    fclose(f);

    printf("%s\n", p);
    printf("Cipher?(Y/n):");
    fflush(stdout);
    char r;
    scanf("%c", &r);
    do {
        c = getchar();
    } while (c != '\n' && c != EOF);
    char ot = r;

    if (ot == 'Y') {
        char s = 0;
        for (int i = 0; i < 64; ++i) {
            s ^= m[i];
        }

        for (int i = 0; i < 63; ++i) {
            m[i] ^= (m[i + 1] ^ s^r^i ^ ((0xf) << 4) ^ ((i % 2) << 7));
            m[i] = f1(m[i]);
        }
        m[63] ^= s;

        FILE* f = fopen("out.txt", "wb");
        fputc(s, f);
        fwrite(m, sizeof(char), 64, f);
        fclose(f);    
    }

    return 0;
}
char f1(char a)
{
    char ss = 0xd;
    static int t = 0;
    int b = a1(rand()) % 0xffff;

    b <<= 4;
    b ^= (k[(t++) % ss] >> 4);
    b <<= 4;
    b ^= (k[(t++) % ss]);

    a ^= (char)b;
    return a;
}

int a1(int a) {
    if (a < 0)
        return (-a);
    else
        return a;
}
Её суть в том, что она читает побайтно файл с текстом, а затем хорит его по определенному алгоритму и записывает в другой файл.
В общем суть моего вопроса:
помогите написать реверсирующую процедуру, т.е. чтобы подавая на вход зашифрованное сообщение получался исходный читаемый текст.
Всю голову себе уже исколупал, 10 раз прошел по алгоритму, но все равно где-то я что-то упускаю (может сдвиг может еще что)
И да, я знаю, что 2х xor дает исходный результат.

Спасибо большое заранее тем, кто откликнется =)
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

02 апр 2018, 08:43

Выкладывай свою попытку. Будем разбираться, что не так.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
shwwawaw
Сообщения: 3
Зарегистрирован: 02 апр 2018, 08:16

02 апр 2018, 11:20

Romeo писал(а):Выкладывай свою попытку. Будем разбираться, что не так.

Код: Выделить всё

#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>
#define k "jf1ay9238x0ax0"
char f1(char a);
int a1(int a);
 
int main()
{
    srand(time(0));
 
    printf("Enter path:");
    fflush(stdout);
    char p[64];
    scanf("%s", p);
    char c;
    do {
        c = getchar();
    } while (c != '\n' && c != EOF);
 
    FILE* f = fopen(p, "rb");
    if (f == NULL) {
        printf("Error opening file");
        getch();
        exit(-3);
    }
    char m[64];
    fread(&m, sizeof(char), 64, f);
    fclose(f);
 
    printf("%s\n", p);
    printf("Cipher?(Y/n):");
    fflush(stdout);
    char r;
    scanf("%c", &r);
    do {
        c = getchar();
    } while (c != '\n' && c != EOF);
    char ot = r;
 
    if (ot == 'Y') {
        char s = 0;
        for (int i = 0; i < 64; ++i) {
            s ^= m[i];
        }
 
        for (int i = 0; i < 63; ++i) {
            m[i] ^= (m[i + 1] ^ s^r^i ^ ((0xf) << 4) ^ ((i % 2) << 7));
            m[i] = f1(m[i]);
        }
        m[63] ^= s;
 
        FILE* f = fopen("out.txt", "wb");
        fputc(s, f);
        fwrite(m, sizeof(char), 64, f);
        fclose(f);    
    }

/*
Вот отсюда начинаем процесс
В обратную сторону
типа Xor x2 = text
/*
	printf("Enter path:");
    fflush(stdout);
/* Чтобы не париться
переназначил переменный добавив 
к ним 0
*/
    char p0[64];
    scanf("%s", p0);
    char c0;
    do {
        c0 = getchar();
    } while (c0 != '\n' && c0 != EOF);
 
    FILE* f0 = fopen(p0, "rb");
    if (f0 == NULL) {
        printf("Error opening file");
        getch();
        exit(-3);
    }
    char m0[64];
    fread(&m0, sizeof(char), 64, f0);
    fclose(f0);
 
    printf("%s\n", p0);
    printf("UNNCipher?(Y/n):");
    fflush(stdout);
    char r0;
    scanf("%c", &r0);
    do {
        c0 = getchar();
    } while (c0 != '\n' && c0 != EOF);
    char ot0 = r0;
 
    if (ot0 == 'Y') {
/* И вот здесь уже не понял
В исходной проге S 
это ХОР всего текса побайтно
и потом последний байт мы еще ксорим
этим S
т.е. перебрав 256 вариантов один из них будет
верным ключем
*/
        char s0;
    scanf("%c", &s0);
/* Этот цикл тогда вообще нужен? 
поидее - да
*/
// берем последний байт, дексорим

 m0[63] ^= s0;
// Потом цикл в обратную сторону
for (int i = 62; i >= 0; --i) {
// Вот здесь я так и не осознал
// какое именно значение играет f1 функция
m0[i] = f1(m0[i]);
m0[i] ^= (m0[i + 1] ^ s0^r0^i ^ ((0xf) << 4) ^ ((i % 2) << 7));

        }

        for (int i = 63; i >=; ++i) {
            s0 ^= m0[i];
        }
 
        FILE* f = fopen("out.txt", "wb");
        fputc(s, f);
        fwrite(m, sizeof(char), 64, f);
        fclose(f);    
    }
	
    return 0;
}
char f1(char a)
{
    char ss = 0xd;
    static int t = 0;
    int b = a1(rand()) % 0xffff;
 
    b <<= 4;
    b ^= (k[(t++) % ss] >> 4);
    b <<= 4;
    b ^= (k[(t++) % ss]);
 
    a ^= (char)b;
    return a;
}
 
int a1(int a) {
    if (a < 0)
        return (-a);
    else
        return a;
}
Вот примерно как-то так.
Хз, я понимаю, что где-то косячу, но голова очень плохо усваивает подобные выкидоны
поэтому обратился за помощью
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

02 апр 2018, 16:32

Ты понимаешь, что зашифровать можно так, что потом не расшифруешь? Именно поэтому в криптографии разделяют алгоритмы на обратимые и необратимые. Если мы внимательно посмотрим в функцию f1, то увидим там использование rand(). Это приводит нас к однозначному выводу - данный алгоритм необратим, так как мы не знаем какие числа вернула функция rand() на этапе шифровки.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
shwwawaw
Сообщения: 3
Зарегистрирован: 02 апр 2018, 08:16

02 апр 2018, 17:56

Romeo писал(а):Ты понимаешь, что зашифровать можно так, что потом не расшифруешь? Именно поэтому в криптографии разделяют алгоритмы на обратимые и необратимые. Если мы внимательно посмотрим в функцию f1, то увидим там использование rand(). Это приводит нас к однозначному выводу - данный алгоритм необратим, так как мы не знаем какие числа вернула функция rand() на этапе шифровки.

Она обратима
Я тестил раз 100
Она выдает один результат
Там в функции еще приведение к char
Короче это хм.. для отвлечения внимания видимо.
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

02 апр 2018, 19:52

Сомневаюсь, что одно и то же значение выдаёт. Значение, которое возвращается rand() активно используется дальше. Игнора нет. Я проверю дома.

Но даже если вдруг окажется, что это так, то этого не достаточно, чтобы преобразование было обратимым. Необходимое и достаточное условие обратимости - это взаимно однозначность преобразования. Судя по формулам, взаимно однозначности тут как раз нет.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

02 апр 2018, 23:20

Romeo писал(а):Ты понимаешь, что зашифровать можно так, что потом не расшифруешь? Именно поэтому в криптографии разделяют алгоритмы на обратимые и необратимые. Если мы внимательно посмотрим в функцию f1, то увидим там использование rand(). Это приводит нас к однозначному выводу - данный алгоритм необратим, так как мы не знаем какие числа вернула функция rand() на этапе шифровки.

Если seed один и тот же, то rand даст одинаковую цепочку значений.
2B OR NOT(2B) = FF
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

02 апр 2018, 23:28

Absurd писал(а):Если seed один и тот же, то rand даст одинаковую цепочку значений.

А так, есть генераторы псевдослучайных чисел которые можно мотать в обратном порядке. Стандартный сишный вроде нельзя.
2B OR NOT(2B) = FF
Аватара пользователя
Romeo
Сообщения: 3091
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

03 апр 2018, 00:06

Absurd, внимательней. Там seed сбрасывается через time, как положено :)
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Skwoogey
Сообщения: 63
Зарегистрирован: 11 янв 2016, 02:25

04 апр 2018, 20:17

Так ранд по сути роли не играет. Он там просто так чтобы процессору без дела не сидеть.

Код: Выделить всё

    int b = a1(rand()) % 0xffff; //b = ...xxxxxxxx
 
    b <<= 4; //b = ...xxxx0000
    b ^= (k[(t++) % ss] >> 4); //b = ...xxxxssss s - что-то что можно однозначно расчитать
    b <<= 4; //b = ...ssss0000
    b ^= (k[(t++) % ss]); //b = ...ssssssss
 
    a ^= (char)b; //используем только последние 8 бит
Не помешало бы переменные и функции называть понятнее.

Вообще массив k весьма интересная структура. Он определен через дефайн, то есть является литералом строки, а потом мы от литерала берем конкретный элемент. Оно так работает?

Кстати, то что она выдает один и тот же результат не значит, что она обратима.

Можно узнать откуда алгоритм шифрования? Мне кажется, что он не полный, так как мы шифруем только первые 64 байта (Вероятно это блочный алгоритм шифрования, не запущенный в цикл). Также если это известный алгоритм шифрования, то для него скорее всего есть алгоритм дешифровки. Визуально мы его ксорим байты между собой и чем-то другим кучу раз и, конечно, можно попытаться отследить для каждого элемента, что получается, а потом попробовать подобрать формулы для расшифровки, но это долго, муторно и не факт, что сработает.
Ответить