پرانی بیساکھی پر قدیم بیساکھی

میں بغیر کسی رکاوٹ کے شروع کروں گا، ایک بار جب مجھے کوئی انکشاف ہوا (اچھی طرح سے، بہت طاقتور نہیں، ایماندارانہ طور پر) اور خیال آیا کہ ایک ایسا پروگرام پرنٹ کیا جائے جو کلائنٹ سے سرور پر تصویر منتقل کرے۔ کافی سادہ ہے نا؟ ٹھیک ہے، ایک تجربہ کار پروگرامر کے لیے، ایسا ہی ہوگا۔ شرائط آسان ہیں - تیسری پارٹی کی لائبریریوں کا استعمال نہ کریں۔ اصولی طور پر، یہ قدرے زیادہ پیچیدہ ہے، لیکن یہ دیکھتے ہوئے کہ آپ کو اس کا پتہ لگانا ہوگا اور مثالیں تلاش کرنی ہوں گی، ٹھیک ہے، ایسا پیشہ۔ میں نے فیصلہ کیا کہ یہ کام میرے اختیار میں ہے۔ اس کے علاوہ، یہ ضروری ہے کہ کافی کوڈ موجود ہو تاکہ آپ کو مدد کی ضرورت ہونے کی صورت میں اسے فورم پر پوسٹ کیا جا سکے۔ سب سے پہلے، میری نظر FTP پر پڑی، ویسے وہ OS جس میں ونڈوز تیار ہو رہی ہے۔ ایف ٹی پی کا فائدہ یہ ہے کہ آپ اس کے ذریعے نہ صرف تصویر بلکہ کسی بھی فائل کو منتقل کر سکتے ہیں۔ فائلزیلا سرور کو ڈاؤن لوڈ کرنے کے بعد، پڑھنے/لکھنے کے لیے ایک ڈائرکٹری کا اشتراک کرنے اور پاس ورڈ کے ساتھ صارف بنانے کے بعد، میں نے فائلزیلا کلائنٹ کو جوڑنے کی کوشش کی، سب کچھ کام کر گیا۔ میں نے C/C++ میں کوڈ کی ایک سادہ مثال بنائی ہے۔

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

اگر میری یادداشت مجھے کام کرتی ہے، تو پھر سب کچھ لوکل ہوسٹ پر کام کرتا ہے، اور نیٹ ورک پر ٹرانسمٹ کرتے وقت، بھیجنے والی لائن میں ایک خرابی پیدا ہو جاتی ہے۔ یہاں کیا آسان ہے a) مختصرا b) آپ کو کلائنٹ انسٹال کرنے کی ضرورت نہیں ہے، لیکن مائیکروسافٹ سے ایف ٹی پی کے لیے پہلے سے بنایا ہوا ٹول استعمال کریں۔ اگرچہ میری رائے میں اسے پروگراموں اور اجزاء کے ذریعے چالو کیا جانا چاہیے۔ اگر آپ یہ جان لیں کہ اس طریقہ کار کا مسئلہ کیا ہے اور کمنٹس میں لکھیں تو بہت اچھا ہو گا۔

فورمز کے ایک گروپ پر جواب نہ ملنے کے بعد، میں نے یہ کوڈ چھوڑ دیا اور ساکٹ نیٹ ورکس کے لیے انٹرفیس استعمال کرنے کا فیصلہ کیا۔ مجھے پہلے ہی کسی دوسرے پروگرام میں حروف کی ایک صف کو منتقل کرنے کا تجربہ تھا۔ ویسے، آپ ٹیننبام، کمپیوٹر نیٹ ورکس سے نقل و حمل کی تہہ کے باب میں پڑھ سکتے ہیں۔ ایک کلائنٹ اور سرور کی مثال موجود ہے، اگرچہ "کئی کلائنٹس - ایک سرور" کنکشن کے لیے نہیں، بلکہ صرف "ایک کلائنٹ - ایک سرور"۔ چونکہ ٹرانسمیشن انٹرنیٹ پر ہے، آپ کو کسی نہ کسی طرح ڈیٹا کو انکرپٹ کرنے کی ضرورت ہے۔ اس کے لئے، ایک بلاک سائفر استعمال کیا جاتا ہے - Feistel نیٹ ورک. اس کے علاوہ سرور پر متعدد (ایک سے زیادہ کلائنٹ) کلائنٹ بنانا ضروری ہے۔ ایسا کرنے کے لیے، ہم تھریڈز کا استعمال کریں گے، ٹرانسمیشن کے لیے تصویر کلائنٹ سے اسکرین کا اسکرین شاٹ لے گی، اسے انکرپٹ کرکے سرور پر منتقل کیا جائے گا، جہاں اسے ڈیکرپٹ کیا جائے گا اور اسے کھولنے کے لیے پہلے سے طے شدہ پروگرام کے ذریعے فوری طور پر اسکرین پر دکھایا جائے گا* .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] = '';
}
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 acceptn");
    }
    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] = '';
        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();
}

مختصراً، ایک ابدی لوپ میں، ہر کلائنٹ کے لیے تھریڈز بنائے جاتے ہیں اور قبول کرنے کا انتظار کریں جب تک کہ کلائنٹ جڑ نہ جائیں۔ اس کے بعد، 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] = '';
}
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] = '';
        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 کے ذریعے ڈی کوڈ کیا گیا تھا۔

پرانی بیساکھی پر قدیم بیساکھی

جیسا کہ آپ دیکھ سکتے ہیں، معمول کا Feistel نیٹ ورک انکرپشن کے لیے موزوں نہیں ہے، لیکن آپ CBC اور CFB کے طریقے استعمال کر سکتے ہیں، یہ شاید بہتر انکرپٹ ہو گا، سچ پوچھیں تو، میں نے اسے چیک نہیں کیا۔

آپ کا شکریہ!

ماخذ: www.habr.com

نیا تبصرہ شامل کریں