Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Рацеев С.М. Программирование на языке Си.pdf
Скачиваний:
366
Добавлен:
23.03.2016
Размер:
1.65 Mб
Скачать

13.4. Шифрование файлов

Напомним, что в языке Си любой файл рассматривается как последовательность байт, заканчивающаяся маркером конца файла. Каждый байт такой последовательности может принимать любое целое значение в диапазоне от 0 до 255. Будем считать, что каждый элемент (байт) последовательности принадлежит кольцу вычетов по модулю 256 (Z256). Сложение и вычитание, которые будут использоваться в дальнейшем, являются соответствующими операциями в кольце вычетов Z256.

Рассмотрим алгоритм шифрования, носящий название шифра Виженера (о современных шифрах, особенно невзламываемых, можно почитать, например, в [14]). Пусть x = x1x2…xn – последовательность байт (файл), каждый элемент (xi, i=1,…,n) которой принадлежит Z256. Для шифрования используется ключ – слово (в общем случае, хаотичный набор символов) в алфавите Z256. Пусть key = k1k2…kd – некоторое ключевое слово длины d, где все ki принадлежат кольцу Z256. Шифрование происходит следующим образом. Считываем первый байт исходного файла и шифруем его с помощью первого байта ключа k1: y1 = x1 + k1 (mod 256), затем считываем второй байт исходного файла и шифруем его с помощью второго байта ключа k2: y2 = x2 + k2 (mod 256) и т.д. (d+1)-ый считанный байт шифруется вновь ключом k1, то есть, в целом, файл f разбивается на блоки длины d, на которые накладывается ключевое слово key. Полученная последовательность y = y1y2…yn и будет являться зашифрованным файлом. Чтобы из зашифрованного файла y1y2…yn обратно получить исходный файл (то есть расшифровать зашифрованный файл y1y2…yn), необходимо проделать обратные

операции: x1 = y1 – k1 (mod 256), x2 = y2 - k2 (mod 256) и т.д.

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

226

обмена buf, куда будем считывать информацию из файла целыми блоками.

#include<stdio.h>

typedef unsigned char UCHAR; typedef unsigned long ULONG;

#define LENGTH 1024 /* размер буфера обмена */

/* функция шифрует содержимое файла fileName1 и результат шифрования записывает в новый

файл fileName2, оставляя файл fileName1 без изменения

*/

int Shifr(char *fileName1, char *fileName2, char *key)

{

FILE *f, *g;

/* входной и выходной файлы */

ULONG i_key,

 

i, j,

/* счетчики */

keyLen,

/* длина ключа */

n_buf;

/* длина считанного блока в буфер */

UCHAR buf[LENGTH]; /* буфер обмена */

if ((f = fopen(fileName1, "rb")) == NULL) return 1;

if ((g = fopen(fileName2, "wb")) == NULL)

{

fclose(f); return 1;

}

keyLen = strlen(key); /* вычисляем длину ключа key */ i_key = 0;

while (n_buf = fread(buf, sizeof(UCHAR), LENGTH, f))

{

for (j = 0; j < n_buf; j++)

{

buf[j] += key[i_key]; i_key++;

if (i_key >= keyLen)

227

i_key = 0;

}

fwrite(buf, sizeof(UCHAR), n_buf, g);

}

fclose(f);

fclose(g); return 0;

}

Функция Shifr() вызывается очень просто, например,

Shifr(“c:\\a.data”, “c:\\b.data”, “password”). Чтобы прописать функ-

цию расшифрования, достаточно скопировать функцию Shifr() и поменять в ней строку

buf[j] += key[i_key];

на строку

buf[j] -= key[i_key];

и назвать эту функцию, например DeShifr().

Случай 2. Предположим, что вы работаете за чужим компьютером и вам необходимо зашифровать ваш файл (зашифрованный файл можно оставить на данном компьютере до следующего вашего прихода или записать на флешку). Рассмотренный выше случай 1 здесь уже не подойдет, так как если вы создадите новый шифрованный файл, а старый удалите, то удаленный файл возможно восстановить. Поэтому в следующем алгоритме шифрование происходит не в новый файл, а путем перезаписывания (замещения) исходного файла шифрованным. При этом считывается очередной блок в буфер buf исходного файла, шифруется, и шифрованный блок записывается вместо исходного.

/* функция шифрования */

int Shifr(char *fileName, char *key)

{

FILE *f; ULONG i_key,

i, j, /* счетчики */ keyLen, /* длина ключа */

228

n_buf, /* длина считанного блока в буфер */

n; /* количество блоков в файле длины LENGTH */

UCHAR buf[LENGTH]; /* буфер обмена */

if ((f = fopen(fileName, "r+b")) == NULL) return 1;

keyLen = strlen(key);

n = Size(fileName)/LENGTH + 1; i_key = 0;

for (i = 0; i < n; i++)

{

fseek(f, i*LENGTH, SEEK_SET);

n_buf = fread(buf, sizeof(UCHAR), LENGTH, f); for (j = 0; j < n_buf; j++)

{

buf[j] += key[i_key]; i_key++;

if (i_key >= keyLen) i_key = 0;

}

fseek(f, i*LENGTH, SEEK_SET); fwrite(buf, sizeof(UCHAR), n_buf, f);

}

fclose(f); return 0;

}

Как и в предыдущем случае, чтобы прописать функцию расшифрования, достаточно скопировать функцию Shifr() и поменять в ней строку

buf[j] += key[i_key];

на строку

buf[j] -= key[i_key];

и, естественно, назвать эту функцию по-другому, например

DeShifr().

229

Уничтожение информации. Предположим, что у вас имеется некоторый секретный файл, который необходимо уничтожить. Естественно, что просто удалить данный файл (например, с помощью функции remove()) недостаточно, так как его возможно будет восстановить. Целесообразнее в данном случае сначала на место удаляемого файла записать последовательность нулей (такого же размера, что и прежний файл), а потом уже использовать функцию remove().

#include<stdio.h>

typedef unsigned char UCHAR; typedef unsigned long ULONG;

#define LENGTH 1024 /* размер буфера обмена */

int DestroyFile(char *fileName)

{

FILE *f;

ULONG i, size, q, r;

UCHAR buf[LENGTH] = {0};

if ((f = fopen(fileName, "r+b")) == NULL) return 1;

size = Size(fileName); /* вычисляем размер файла */

/* далее необходимо разложение size = q*LENGTH + r,

где r < LENGTH

*/

/* вычисляем количество блоков длины LENGTH:*/ q = size/LENGTH;

r = size%LENGTH; /* вычисляем остаток */

for (i = 0; i < q; i++)

fwrite(buf, sizeof(UCHAR), LENGTH, f); fwrite(buf, sizeof(UCHAR), r, f);

fclose(f);

remove(fileName); return 0;

230