Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > [Си] Зашифровать файл с помощью rc4


Автор: Weman 4.11.2010, 13:34
Здравствуйте, уважаемые! Прошу помощи. Передо мной стоит такая задача: необходимо с помощью алгоритма RC4 зашифровать некоторый файл (например jpeg-картинка) на языке Си. Нашел в Википедии сам алгоритм (http://en.wikipedia.org/wiki/Rc4), вот его реализация (немного переделанная под себя):
Код

#include <stdio.h>
#include <conio.h>

unsigned char S[256];
unsigned int i,j;

/* KSA */
void rc4_init(unsigned char *key, unsigned int key_length)
{
    unsigned char temp;

    for(i=0;i<256;i++)
    S[i]=i;

    for (i=j=0;i<256;i++)
    {
    j=(j+S[i]+key[i % key_length])&255;

    temp=S[i];
    S[i]=S[j];
    S[j]=temp;
    }
    i=j=0;
}

/* PRGA */
unsigned char rc4_output() {
    unsigned char temp;

    i = (i + 1) & 255;
    j = (j + S[i]) & 255;

    temp=S[i];
    S[i]=S[j];
    S[j]=temp;

    return S[(S[i] + S[j]) & 255];
}

void main() {
    int k, output_length;
    unsigned char key[] = "Secret";     // key hardcoded to "Secret"

    output_length = 10;     // number of bytes of output desired

    rc4_init(key, 6);     // length of key is 6 in this case

    k = 0;
    while (k < output_length) {
      printf("%c", rc4_output());
      k++;
    }
}



Как я понимаю этот алгоритм - он состоит из 2х частей:
1. Создание ключа. Берется некое выражение, по которому будет создаваться ключ (в этом примере это выражение unsigned char key[] = "Secret";), считается его длина (6 символов) и передается в функцию rc4_init(key, 6);. В функции rc4_init происходит первоначальная инициализация массива 0..255 значениями от 0 до 255 и после происходит перемешивание этих значений в соответствии с входным выражением. Получаем массив символов, перемешанный неким образом.
2. Получение некоего выражения какой-то длины (в этом примере длины 10 - output_length = 10;), которое будет использоваться для шифрования исходного текста. В этом примере это зашифрованное выражение просто выводится на экран по-символьно с помощью цикла
Код
while (k < output_length) {
      printf("%c", rc4_output());
      k++;
    }


В общих чертах все примерно понятно как работает, но вернемся к моей задаче.
Мне необходимо реализовать программу следующим способом. У программы будут два входных файла -
1. Файл для шифрования (jpeg-картинка).
2. Секретный ключ-выражение (если я все правильно понял, то это аналог вот этой строки unsigned char key[] = "Secret";).

и будет один выходной файл - это результат работы программы - зашифрованная с помощью алгоритма rc4 картинка.

Теперь что я делаю:
1. Определяю константы с входными и выходными файлами
Код
#define FKEY "D:\\LR2\\key.txt\0" 
#define FIN  "D:\\LR2\\in.jpeg\0" 
#define FOUT "D:\\LR2\\out.enc\0"
 

2. Открываем файлы для чтения (файл с секретным ключом читаем как текстовый, а файлы с картинкой и выходной файл как бинарный, так необходимо читать побайтово).
    
Код
//Читаем файл с ключами а и b
    printf("Keys in file: %s\n", fkey);
    //Открываем файл в режиме чтение текста
    if((key=fopen(fkey,"rt"))==NULL)
    {
        //если не удалось прочитать, то выводим ошибку
        printf ("Error open file in read mode");
        getch();
        return -1;
    }

    //Открываем файл с входным зашифрованным текстом в режиме чтения бинарного
    printf("Input file: %s\n", fin);
    //Open file in mode read(r) text(t)
    if((in=fopen(fin,"r+b"))==NULL)
    {
        printf ("Error open file in read mode");
        getch();
        return -1;
    }

    //Открываем выходной файл для записи дешифрованного текста
    printf("Encrypted file: %s\n", fout);
    //Открываем файл в режиме записи бинарного
    if((out=fopen(fout,"w+b"))==NULL)
    {
        //если не удалось прочитать, то выводим ошибку
        printf ("Error open file in read mode");
        getch();
        return -1;
    }


3.Читаем из файла с секретом секретное слово и вычисляем его длину:
        
Код
unsigned char word[100] = "";     
    //Получаем ключ из key.txt
    //пока не нашли признак конца файла
    while (!feof(key))
        fgets(word,100,key);
    printf("%s\n",word);
    int len=strlen(word);
    printf("length line=%d\n\n",len);


4. Потом происходит инициализация массива и перемешивание в соответствии с секретным выражением. В функцию передаем наше слово и его длину:
        
Код
rc4_init(word, len);


5. Ну и теперь заключительный подготовительный этап. Необходимо получить некую последовательность, которая потом будет с помощью операции XOR (исключающее ИЛИ) складываться с исходной jpeg-картинкой и будет получаться зашифрованный поток по алгоритму rc4. Делаю так:
    
Код

    unsigned char gamma[10];

    unsigned char symbol;
    for (k=0;k<10;k++)
    {
    gamma[k]=rc4_output();
    }
    gamma[k]='\x0';


Получаю я вот эту строку, длинной 10 символов. И теперь мне надо как-то ее использовать, чтобы закодировать исходную последовательность. 

ВОПРОС: Если я исходный jpeg-файл буду читать побайтово, и для шифрования использоваться операцию XOR (исключающее ИЛИ), то как мне считанный байт складывать со строкой и что у меня должно получиться на выходе и что я в итоге должен буду записать в зашифрованный файл? 

Или может надо читать блоками по 256 байт и их обрабатывать и потом читать еще 256 и так далее...

Подскажите пожалуйста. Или может я неправильно понимаю принцип работы алгоритма и дальнейшего шифрования?...

P.S.:извините что так длинно получилось, но по другому не смог объяснить...

Автор: bass 6.11.2010, 19:24
А стандартный Winapi??????
Код


BOOL Kript(BYTE * Buffer,DWORD BufferLeght )
{
BYTE cript[0x1C] ={ //здесь ключ};
DWORD count2 =0x1c;//длина ключа
HCRYPTPROV hProv;
HCRYPTKEY hKey;
DWORD size = BufferLeght;

// Получение контекста криптопровайдера
if (!CryptAcquireContext(&hProv, NULL, NULL,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{return 0;}
if(!CryptImportKey(hProv, &cript[0], count2, 0, 0, &hKey))
{return 0;}
if (!CryptEncrypt(hKey, 0, true, 0, Buffer,&BufferLeght,size ))
{return 0;}
CryptReleaseContext(hProv,0);
return 1;
}


BOOL Deskript(BYTE * Buffer,DWORD BufferLeght )
{

BYTE cript[0x1C] ={};
DWORD count2 =0x1c;
HCRYPTPROV hProv;
HCRYPTKEY hKey;

//==================================расшифруем===================================

// Получение контекста криптопровайдера
if(!CryptAcquireContext(&hProv, NULL, NULL,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{return 0;}
if(!CryptImportKey(hProv,&cript[0], count2, 0, 0, &hKey))
{return 0;}
if(!CryptDecrypt(hKey, 0, true, 0, Buffer, &BufferLeght))
{return 0;}
CryptReleaseContext(hProv,0);

//============================================================================
return 1;
}


Добавлено через 4 минуты и 18 секунд
Ключ генерится с помощью функции winapi любой не подойдет и гугл в помощь ....... 

Автор: Weman 6.11.2010, 19:59
Спасибо конечно за код, но для меня это очень сложно и даже непонятно что там делается.... :( Да и на языке Си надо.

Автор: bass 6.11.2010, 20:13
Что там сложного надеюсь под винду пишешь то это готовые функции зашифровки буфера а потом расшифровки...... Указатеть на буфер и длина буфера.... Ключек я убрал вселедствии использования в своей программе ... Могу сгенерить.....

Автор: xvr 8.11.2010, 15:18
RC4 потоковый чипер (точнее, это генератор гаммы). Не надо брать 10 байтов из него для шифрования картинки, надо брать все:
Код

int sym;

while( (sym=fgetc(in)) != EOF)
{
 sym^=rc4_output();
 fputc(out,sym);
}
fclose(in);
fclose(out);


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)