Древний костыль на старом костыле

Начну без обиняков, как-то раз меня постигло откровение (ну не сильно мощное скажу по-честному) и возникла идея напечатать программу которая передает изображение с клиента на сервер. Достаточно просто да? Ну для программиста со стажем так и будет. Условия просты - не использовать сторонние библиотеки. В принципе немного сложнее, но если учесть что придется разбираться и искать примеры, ну такое себе занятие. Я решил, что эта задача мне по плечу. Плюс желательно чтобы было кода столько, чтобы его можно было запостить на форуме, в случае если понадобится помощь. В первую очередь мой взгляд пал на FTP, к слову ОС в которой разрабатывается Windows. Плюс FTP в том, что можно через него передать не только изображение, а любой файл. Скачав Filezilla Server, расшарив одну директорию на чтение/запись и создав юзера с паролем, попробовал подключится Filezilla Client все работало. Создал простенький пример кода на С/С++:

#include <iostream>
void main()
{
	FILE* fs;
	fopen_s(&fs, "1.txt", "w");
	if (fs)
	{
    fwrite("user\r\npassword\r\nsend D:\\share\\1.txt\r\nbye", 1, sizeof("user\r\npassword\r\nsend D:\\share\\1.txt\r\nbye"), fs);
    fwrite("\000", 1, sizeof("\000"), fs);
    fclose(fs);
	}
	system("ftp -s:1.txt 127.0.0.1");
}

Если мне не изменяет память, то на локалхосте все работало, а при передаче по сети возникала ошибка в строчке с send. Что здесь удобно а)коротко б)не нужно устанавливать клиент, а использовать уже встроенную тулзу для ftp от майкрософта. Хотя по-мойму ее надо активировать через программы и компоненты. Если вы разберетесь в чем проблема данного метода и напишите в комментарии, будет отлично.

Не найдя ответа на куче форумов, я оставил данный код и решил использовать интерфейс для сетей сокеты. У меня уже был опыт передачи массива char'ов для другой программы. Кстати можете почитать у Таненбаума, Компьютерные сети, в главе про транспортный уровень. Там есть пример клиента и сервера, правда не для соединения "много клиентов - один сервер", а только "один клиент - один сервер". Поскольку передача идет через Интернет, то нужно зашифровать хоть как-то данные. Для этого используется блочный шифр - сеть Фейстеля. Плюсом на сервере надо сделать несколько(больше одного клиента) клиентов. Для этого воспользуемся Thread'ами, изображение для передачи будет брать скриншот экрана с клиента шифроваться и передаваться на сервер, на котором будет расшифровано и сразу же выведено на экран через дефолтную программу для открытия *.tga изображения.

Код сервера:

#include <iostream>
#include <WinSock.h>
#pragma comment (lib,"WS2_32.lib")

#include <fstream>
#include <algorithm>
#include <string>
#include <iterator>
#include <vector>
void error(const char* msg)
{
    //perror(msg);
    std::cout<<'\n'<<WSAGetLastError();
    WSACleanup();
    std::cin.ignore();
    exit(1);
}
void bzero(char*buf, int l)
{
    for (int i = 0; i < l; i++)
        buf[i] = '\0';
}
struct arg_s
{
    unsigned char* buffer2;
    bool exit;
};
char** buffer;
struct arg_sa
{
    struct arg_s* lalk;
    int current;
};
#define type struct arg_sa
int sockfd, * newsockfd;//слушающий и массив клиентских сокетов
int buflen2 = 10292000;//максимальный размер изображения в байтах для RGBA*Width*Height
struct sockaddr_in *cli_addr;
int* clilen;
int currentclient,cc;//сс-клиент по счету(для записи инкремента имени файла клиента изображения)

typedef unsigned long long uint64_t;
typedef unsigned int uint32_t;
#define N 8//размер блока
#define F32 0xFFFFFFFF
uint32_t RK[N];//раундовые ключи
#define size64 sizeof(uint64_t)
#define ROR(x,n,xsize)((x>>n)|(x<<(xsize-n)))
#define ROL(x,n,xsize)((x<<n)|(x>>(xsize-n)))
#define RKEY(r)((ROR(K,r*3,size64*8))&F32)
const uint64_t K = 0x96EA704CFB1CF671;//ключ шифрования
struct hostent* server;
uint32_t F(uint32_t subblk, uint32_t key)
{
    return subblk + key;//функция шифрования
}
void createRoundKeys()
{
    for (int i = 0; i < N; i++)
        RK[i] = (ROR(K, i * 8, size64 * 8)) & F32;
}
uint64_t decrypt(uint64_t c_block)//расшифровка блоков сетью фейстеля
{
    //select subblocks
    uint32_t left = (c_block >> 32) & F32;
    uint32_t right = c_block & F32;
    uint32_t left_, right_;//subblock in the end of round
    for (int r = N - 1; r >= 0; r--)
    {
        uint32_t fk = F(left, RK[r]);
        left_ = left;
        right_ = right ^ fk;
        if (r > 0)//swap places to next round
        {
            left = right_;
            right = left_;
        }
        else //last round not swap
        {
            left = left_;
            right = right_;
        }
    }
    //collect subblock in block
    uint64_t block = left;
    block = (block << 32) | (right & F32);
    return block;
}
void session_(LPVOID args)//функция потока ля каждого клиента
{
    int current = currentclient++;
    bzero((char*)&(cli_addr[current]), sizeof(&(cli_addr[current])));
    newsockfd[current] = accept(sockfd, (struct sockaddr*)&(cli_addr[current]), &(clilen[current]));
    if (newsockfd[current] < 0)
    {
        error("Error on accept\n");
    }
    char* s = new char[100];
    int n = recv(newsockfd[current], s, 100, 0);
    int buflen2 = atoi(s);//получаем число байтов изображения
    FILE* f;
    std::string name = "Screen";
    cc++;
    _itoa_s(cc, s, 100, 10);
    name += s;
    name += ".tga";
    fopen_s(&f,name.c_str(), "wb");//создаем файл изображения с увеличиваещимся на 1 именем, чтобы не перезаписать
    if (f != NULL)
    {
        unsigned char tgaHeader[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        unsigned char header[6];
        n = recv(newsockfd[current], buffer[current], sizeof(tgaHeader), 0);
        fwrite((unsigned char*)buffer[current], 1, sizeof(tgaHeader), f);
        bzero(buffer[current], buflen2);
        n = recv(newsockfd[current], buffer[current],sizeof(header), 0);
        fwrite((unsigned char*)buffer[current], 1, sizeof(header), f);//записали хидеры
        bzero(buffer[current], buflen2);
        n = recv(newsockfd[current], buffer[current], buflen2, 0);//получили байты самого изображения
        //
        //расшифровка байтов
        createRoundKeys();
        unsigned long long id;
        std::vector<uint64_t>* plaintext = new std::vector<uint64_t>();
        int i = 0;
        while (i<buflen2)
        {
            memcpy(&id, (buffer[current]) + i, N);
            plaintext->push_back(decrypt(id));
            i += 8;
        }
        std::cout << "i=" << i << std::endl;
        i = 0;
        char str_[N + 1];
        memset(str_, 0, N);
        str_[N] = '\0';
        for (std::vector<uint64_t>::iterator it = plaintext->begin(); it != plaintext->end(); ++it)
        {
            memcpy(str_, &*it, N);
            fwrite((unsigned char*)str_, sizeof(unsigned char), N/*strlen(str_)*/, f);
            i += 8;
        }
        std::cout << "i=" << i << std::endl;
        //конец рашифровки байтов
        //fwrite((unsigned char*)buffer[current], sizeof(char), buflen2, f);
        fclose(f);
    }
    system(name.c_str());//открываем изображение *.tga встроенным редактором
}
int main()
{
    cc = 0;
    WSADATA ws = { 0 };
    if (WSAStartup(MAKEWORD(2, 2), &ws) == 0)
    {
        currentclient = 0;
        int maxclients = 2;//максимальное число клиентов
        cli_addr = new struct sockaddr_in[maxclients];
        clilen = new int[maxclients];
        buffer = new char* [maxclients];
        for (int i = 0; i < maxclients; i++)
        {
            clilen[i] = sizeof(cli_addr[i]);
        }
        sockfd = socket(AF_INET, SOCK_STREAM, 0);//tcp сокет
        if (sockfd < 0)
            error("ERROR opening socket");
        struct sockaddr_in serv_addr;
        bzero((char*)&serv_addr, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = INADDR_ANY;
        int port = 30000;//порт
        serv_addr.sin_port = htons(port);
        if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
            error("ERROR on binding");
        if (listen(sockfd, 10) < 0)
            error("ERROR listen");
        HANDLE* thread;//массив потоков для каждого клиента отдельный
        struct arg_sa* args;
        while (true)
        {
            newsockfd = new int[maxclients];
            thread = (HANDLE*)malloc(sizeof(HANDLE) * maxclients);
            args = new struct arg_sa[maxclients];
            for (int i = 0; i < maxclients; i++)
            {
                args[i].lalk = new struct arg_s();
                buffer[i] = new char[buflen2];
            }
            int i = -1;
            while (++i < maxclients)
            {
                Sleep(1);
                args[i].current = i;
                args[i].lalk->exit = false;
                thread[i] = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)(session_), args, 0, 0);
            }
                for (int i = 0; i < maxclients; i++)
                    WaitForSingleObject(thread[i], INFINITE);//ждем завершения всех потоков
            i = -1;
            while (++i < maxclients)
            {
                shutdown(newsockfd[i], 0);
                TerminateThread(thread[i], 0);
            }
            //delete[] newsockfd;
            //free(thread);
            currentclient = 0;
            for (int i = 0; i < maxclients; i++)
            {
                //delete args[i].lalk;
                //delete[] args[i].lalk->buffer;
            }
            //delete[] args;
        }
        shutdown(sockfd, 0);
        WSACleanup();
        return 0;
    }
    std::cin.ignore();
}

Вкратце в вечном цикле создаются потоки для каждого клиента и ждут accept пока клиенты подключится. После чего WaitForSingleObject ждет пока они все передадут. У каждого клиента свой сокет и свой буфер передачи. То есть на сервере M+1 сокет, где M количество клиентов. После завершения всех передач, всё повторяется.

Теперь рассмотрим клиент:

#include <iostream>
#include <WinSock.h>
#include <vector>
#pragma comment (lib,"WS2_32.lib")
void error(const char* msg)
{
    //perror(msg);
    std::cout << '\n' << WSAGetLastError();
    WSACleanup();
    std::cin.ignore();
    exit(1);
}
void bzero(char* buf, int l)
{
    for (int i = 0; i < l; i++)
        buf[i] = '\0';
}
typedef unsigned long long uint64_t;
typedef unsigned int uint32_t;
#define N 8
#define F32 0xFFFFFFFF
uint32_t RK[N];//раундовые ключи
#define size64 sizeof(uint64_t)
#define ROR(x,n,xsize)((x>>n)|(x<<(xsize-n)))
#define ROL(x,n,xsize)((x<<n)|(x>>(xsize-n)))
#define RKEY(r)((ROR(K,r*3,size64*8))&F32)
const uint64_t K = 0x96EA704CFB1CF671;//ключ шифрования
void createRoundKeys()
{
    for (int i = 0; i < N; i++)
        RK[i] = (ROR(K, i * 8, size64 * 8)) & F32;
}
uint32_t F(uint32_t subblk, uint32_t key)
{
    return subblk + key;//функция шифрования
}
uint64_t encrypt(uint64_t block)//зашифровка блоков сетью Фейстеля
{
    //select subblocks
    uint32_t left = (block >> 32) & F32;
    uint32_t right = block & F32;
    uint32_t left_, right_;//subblock in the end of round
    for (int r = 0; r < N; r++)
    {
        uint32_t fk = F(left, RK[r]);
        left_ = left;
        right_ = right ^ fk;
        if (r < N - 1)//swap places to next round
        {
            left = right_;
            right = left_;
        }
        else//last round not swap
        {
            left = left_;
            right = right_;
        }
    }
    //collect subblock in block
    uint64_t c_block = left;
    c_block = (c_block << 32) | (right & F32);
    return c_block;
}
int main()
{
    keybd_event(VK_LWIN, 0, 0, 0);
    keybd_event('M', 0, 0, 0);
    keybd_event('M', 0, KEYEVENTF_KEYUP, 0);
    keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);//эти строки сворачивают все приложения
    Sleep(1000);//чтобы сделать скриншот рабочего стола
    WSADATA ws = { 0 };
    if (WSAStartup(MAKEWORD(2, 2), &ws) == 0)
    {
        int sockfd;
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        struct sockaddr_in serv_addr, cli_addr;
        bzero((char*)&serv_addr, sizeof(serv_addr));
        bzero((char*)&cli_addr, sizeof(cli_addr));
        serv_addr.sin_family = AF_INET;

        const char* add = "127.0.0.1";//адрес сервера
        serv_addr.sin_addr.s_addr = inet_addr(add);
        int port = 30000;//порт
        serv_addr.sin_port = htons(port);
        int servlen = sizeof(serv_addr);
        int n = connect(sockfd, (struct sockaddr*)&serv_addr, servlen);
        
        //ниже код делает скриншот
        HDC ScreenDC = GetDC(0);
        HDC MemoryDC = CreateCompatibleDC(ScreenDC);
        int ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
        int ScreenWidth = GetSystemMetrics(SM_CXSCREEN);
        ScreenWidth = ((ScreenWidth - 1) / 4 + 1) * 4;
        BITMAPINFO BMI;
        BMI.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        BMI.bmiHeader.biWidth = ScreenWidth;
        BMI.bmiHeader.biHeight = ScreenHeight;
        BMI.bmiHeader.biSizeImage = ScreenWidth * ScreenHeight * 3;
        BMI.bmiHeader.biCompression = BI_RGB;
        BMI.bmiHeader.biBitCount = 24;
        BMI.bmiHeader.biPlanes = 1;
        DWORD ScreenshotSize;
        ScreenshotSize = BMI.bmiHeader.biSizeImage;
        unsigned char* ImageBuffer;
        HBITMAP hBitmap = CreateDIBSection(ScreenDC, &BMI, DIB_RGB_COLORS, (void**)&ImageBuffer, 0, 0);
        SelectObject(MemoryDC, hBitmap);
        BitBlt(MemoryDC, 0, 0, ScreenWidth, ScreenHeight, ScreenDC, 0, 0, SRCCOPY);
        DeleteDC(MemoryDC);
        ReleaseDC(NULL, ScreenDC);
        FILE* sFile = 0;
        unsigned char tgaHeader[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        unsigned char header[6];
        unsigned char tempColors = 0;
        fopen_s(&sFile, "S.tga", "wb");
        if (!sFile) {
            exit(1);
        }
        header[0] = ScreenWidth % 256;
        header[1] = ScreenWidth / 256;
        header[2] = ScreenHeight % 256;
        header[3] = ScreenHeight / 256;
        header[4] = BMI.bmiHeader.biBitCount;
        header[5] = 0;
        fwrite(tgaHeader, 1, sizeof(tgaHeader), sFile);
        fwrite(header, sizeof(header), 1, sFile);
        //конец записали изображение в файл
        
        //шифруем блоками полезную нагрузку изображения кроме хидеров
        createRoundKeys();
        std::vector<uint64_t>* msg = new std::vector<uint64_t>(),*crpt = new std::vector<uint64_t>();
        unsigned long long id;
        int i = 0;
        while (i < BMI.bmiHeader.biSizeImage)
        {
            memcpy(&id, (ImageBuffer + i), N);
            msg->push_back(id);
            i += 8;
        }
        std::cout << "i=" << i << std::endl; 
        uint64_t cipher;
        i = 0;
        char str_[N + 1];
        memset(str_, 0, N);
        str_[N] = '\0';
        for (std::vector<uint64_t>::iterator it = msg->begin(); it != msg->end(); ++it)
        {
            cipher = encrypt(*it);
            memcpy(str_, &cipher, N);
            fwrite((unsigned char*)str_, sizeof(unsigned char), N, sFile);
            i += 8;
        }
        std::cout << "i=" << i << std::endl;
        //
        //fwrite(ImageBuffer, BMI.bmiHeader.biSizeImage, 1, sFile);
        std::cout << BMI.bmiHeader.biSizeImage << std::endl;
        fclose(sFile);
        DeleteObject(hBitmap);
        FILE* f;
        fopen_s(&f, "S.tga", "rb");
        int count = 0;
        if (f != NULL)
        {
            while (getc(f) != EOF)
                count++;//считаем байты изображения в счетчик чтобы потом передать
            fclose(f);
        }
        count -= 18;
        std::cout << count<< std::endl;
        char* s = new char[100];
        _itoa_s(count, s, 100, 10);
        n = send(sockfd, s, 100, 0);//передаем счетчик
        char* buffer = new char[count];
        fopen_s(&f, "S.tga", "rb");
        size_t bytes;
        if (f != NULL)
        {
            memcpy(buffer, tgaHeader, sizeof(tgaHeader));
            n = send(sockfd, buffer, sizeof(tgaHeader), 0);
            bzero(buffer, count);
            memcpy(buffer, header, sizeof(header));
            n = send(sockfd, buffer, sizeof(header), 0);
            bzero(buffer, count);//передаем хидеры
            for(int i=0;i<18;i++)
                fgetc(f);
            bzero(buffer, count);
            bytes = fread(buffer, sizeof(unsigned char), count, f);
            n = send(sockfd,buffer, count, 0);//передаем шифрованные байты изображения
            fclose(f);
        }
        Sleep(1000);
        shutdown(sockfd, 0);
        WSACleanup();
        //system("del S.tga");
        delete[] buffer,s;
        return 0;
    }
    //std::cin.ignore();
}

Вот результат работы клиента файл скриншота S.tga, зашифрованный

Видно, что это рабочий стол

А вот результат который был передан на сервер и расшифрован Screen.tga

Как видите обычная сеть Фейстеля не подходит для шифрования, но можно воспользоваться CBC и CFB методами, возможно будет лучше зашифровано, если честно не проверял.

Спасибо за внимание!

Средняя зарплата в IT

111 111 ₽/мес.
Средняя зарплата по всем IT-специализациям на основании 6 788 анкет, за 2-ое пол. 2020 года Узнать свою зарплату
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 30

    0
    Да приношу извинения что в конце наехал на сеть Фейстеля при N = 32 раундах, уже лучше зашифровывается изображение. Но все равно проглядывается рабочий стол. При использовании CBC и CFB для 8 раундов на картинках зашифрованных просто белый шум — ничего не понятно
      +2
      > Условия просты — не использовать сторонние библиотеки.
      это нужно чтобы разобраться как оно работает или есть практическая необходимость?

      Код сложно читать. Для начала можно выложить на гитхаб, там хотя бы нормальная подсветка синтаксиса. Потом непонятно почему такая адская смесь си и си++
      Тут итераторы а в другом месте уже файлы через FILE.
      С ресурсами все плохо ( массивы выделяются, память не освобождается ).

      Ну есть странные места
              char str_[N + 1];
              memset(str_, 0, N);
              str_[N] = '\0';

      Вначале обнулили его первые N-1 элементов, а потом еще и последний тоже.

      На мой взгляд главная проблема кода что он очень плотный, и смешанный. В смысле тут и шифрование, и передача данных по сети, создание потоков, и снятие изображения. В идеале если разделить все это на разные куски то можно и тестировать отдельно и чистота кода должна улучшиться.
        –1
        это нужно чтобы разобраться как оно работает или есть практическая необходимость?

        Чтобы на форум код поместился в случае тупика и поиска ошибки, я ж это проговорил
        Тут итераторы а в другом месте уже файлы через FILE.

        И по остальным вещам, да надо код вылизать, убрать лишнее
          –1

          "Вылизывать"?


          к черту всё. Тебе сколько лет, 12? Ты наговнокодил с три портянки, вывалил это говно на всеобщее обозрение с опломбом "я художник, я так вижу".


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


          Следи за базаром, щенок. Тут люди с несколькими высшими образованиями, разным жизненным опытом. Этот ресурс — один из немногих, неопошленных такими дураками как ты. Хочешь умничать такими фразами как "вылизывать" — звездуй на пикабу (при всем уважении к паблику).
          Здесь же, будь любезен:


          1. трижды проверь то, что выкладываешь;
          2. следи за базаром.

          p.s. если тебе чуть больше 20 и есть претензии, то пиши в личку. Надо будет и при личной встрече объясню, как кашу есть и Родину любить.

            –2
            Мне твои объяснения нахрен не нужны, поехавший
              0

              Черт, тьма пафоса, самолюбования. Автор, конечно был неправ, когда вывалил на людей грязный код, но называть его щенком, фраериться словом "базар" и предлагать в реале встретиться, да ещё и банальщина про родину любить?


              Ты точно не с одноклассниками Хабр спутал? Или это челлендж на самое быстрое получение плашки тролля?

          +6

          Вас, возможно, интересует, почему ваша статья заминусована? Я кнопки голосования не трогал, но позволю себе высказать гипотезу.
          Формулировка задачи выглядит очень странно. Что такого особенного в передаче файлов по сети? Почему без сторонних библиотек? Зачем шифровать? Почему не взять более традиционные алгоритмы?
          Ну и технический уровень реализации тоже не высок. Простите за сравнение, но у меня студенты третьего курса не самого профильного факультета на сокетах посложнее вещи делают. Не говоря уже про то, что они делают с библиотеками.
          Это вовсе не означает, что вы не можете написать о своём опыте на хабр, но нужно трезвее оценивать уровень и соответственно менять фокус с того, что вы сделали на то, почему. Может быть, вы учитесь программировать и хотите поделиться своей историей? Или делаете сложную техническую систему, где программирование лишь неважная деталь? При нужном ракурсе вы сможете получить тут поддержку и советы, а не минусы.

            –12
            Вас, возможно, интересует, почему ваша статья заминусована?

            Меня это мало волнует, я накидал текст минут за 20 при уже сыроватом коде.
            Формулировка задачи выглядит очень странно.

            Да.
            Что такого особенного в передаче файлов по сети? Почему без сторонних библиотек? Зачем шифровать? Почему не взять более традиционные алгоритмы?

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

            А если бы я делал что-то посложнее, во первых не сделал бы, во вторых кода было бы много.
            Или делаете сложную техническую систему, где программирование лишь неважная деталь?
            Программирование такое себе занятие, когда копнешь глубже остальных приходится искать и не всегда находить примеры и решения. Да и по образованию я тоже не спец в этих областях.
              +6
              Меня это мало волнует, я накидал текст минут за 20 при уже сыроватом коде.

              Зачем кидать на хабр сыроватый невнятный текст?

              Особенно то, что можно смотреть рабочий стол.

              Запакуйте файл в zip c паролем и передавайте. Зачем совмещать передачу информации с шифрованием, тем более что вы совершенно не рубите в теме алгоритмов шифрования, о чем свидетельствует плохо зашифрованный вами файл.

              Без сторонних потому что на форуме врятли кто-то будет линковать код со сторонними библиотеками.

              На форуме — вряд ли. Так и шлите этот текст на форум. А на Хабр, будьте любезны, подучитесь чему-нибудь и поделитесь полезным а не сырыми недоделками.
              Вдобавок «без сторонних библиотек», но вместо программы вы ТУПО ЗАПУСКАЕТЕ FTP клиент. ЗАЧЕМ?

              А вы хотите гонять по сети интернет скриншоты рабочего стола не зашифрованными?

              Это вы хотите их гонять и гоняете. Кроме того вообще публикуете скриншот незашифрованным.

              Приведите пример любого традиционного алгоритма.

              Шифр Виженера реализуется в два щелчка.
                +1

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

                  –1
                  Эх домоскан ;-)
                +3
                Программирование такое себе занятие, когда копнешь глубже остальных приходится искать и не всегда находить примеры и решения.

                Программирование — это не поиск примеров в Интернете.
                  0

                  Для плюсов есть вещи типа Conan, которые решат проблему со сторонними библиотеками.
                  Если совсем тяжело — делайте сабмодули, подавляющее большинство библиотек идут в исходниках, собрать их перед сборкой основного «продукта» совершенно не проблема, даже кросс-платформенно, 2021 год на носу, а вы всё с memset балуетесь.

                +9

                В чем особенность передачи именно картинки? Любой файл прекрасно передается, ведь его можно представить в виде байтового потока, и запихнуть в сокет.


                За шифрование — здесь явно смешение абстракций. Отдельный код должен шифровать-дешифровать. И совершенно другой — отправлять. Тогда можно будет использовать разные алгоритмы шифрования, и передавать эти же зашифрованные файлы не только сокетами.


                Ну и субъективно — в вашей статье я не вижу уважения к читателю. Вы небрежно формулируете задачу, небрежно описываете решение, и статья тяжелее читается. Ну и судя по вашим ответам на комментарии вы плохо воспринимаете конструктивную критику. Если хотите расти как программист, вам нужно фиксить эти качества.

                  +1
                  Поддержка криптографии давность как в Windows, так и в Linux и без проблем доступна из юзерспейса через стандартные api операционной системы без сторонних библиотек. К чему вручную все писать? Ну если уж писать, то что-то интересное, а не голую сеть Фейстеля. Более того, ваш шифр не устойчив к линейному криптоанализу и множеству других атак, в первую очередь из-за того, что функция F вносит слишком мало нелинейности. Про слабую дифузию вообще молчу)
                    +1

                    Recovery Mode? Seriously?

                      +3
                      «по-мойму» — этапять
                      как и весь текст поста код надо целиком на говнокод.ру отправлять.
                      итого: КГ\АМ
                        0

                        Странная постановка задачи и странное решение. Совсем без библиотек не получится всё равно, можете посмотреть, сколько всего разного прилинковалось к вашему бинарнику.
                        ЗЫ: писать простыню г-кода только ради убедиться, что он собирается и работает, лично мне было бы лениво.

                          0

                          Больше года прошло с момента вашей первой публикации. Обе статьи в глубоком минусе. В обеих статьях в комментариях открыто отмечается ваша непрофпригодность.
                          Вы принципиально отказываетесь от самообразования или это некая форма протеста?

                            0
                            Вы на его вопросы на Тостере посмотрите. Уровень ниже плинтуса и нулевой прогресс.
                              0
                              Судя по вопросам, постановке задач и их решениям автору должно быть не 28лет (что можно предположить из username), а примерно в 2 раза меньше. Я вот именно в этом возрасте страдал чем-то подобным, правда на Delphi.
                              –1
                              Устал уже самообразовываться
                                0
                                Так может бросить это чёртово ИТ? В нём же обязательно самообразовываться всё время.
                                  0
                                  Так я и не начинал, это так баловство
                                    0
                                    Если на форум краснодеревщиков вывалить видосик «как я сделаль скворечник» — там тоже не одобрят. А если после скворечника похвастаться ещё и синичником… :D
                                      +1
                                      Тогда стоит убрать «Инженер-программист» из профиля, как очевидную неправду.
                                        0
                                        Можно работать не печатая код, чем я и занимаюсь, так что все тру
                              0
                              del

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                              Самое читаемое