Система криптографической защиты информации::Журнал СА 4.2003
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Наука и технологии
Подписка
Где купить
Авторам
Рекламодателям
Магазин
Архив номеров
Вакансии
Контакты
   

  Опросы

Какие курсы вы бы выбрали для себя?  

Очные
Онлайновые
Платные
Бесплатные
Я и так все знаю

 Читать далее...

1001 и 1 книга  
20.12.2019г.
Просмотров: 4900
Комментарии: 0
Dr.Web: всё под контролем

 Читать далее...

04.12.2019г.
Просмотров: 6152
Комментарии: 0
Особенности сертификаций по этичному хакингу

 Читать далее...

28.05.2019г.
Просмотров: 7390
Комментарии: 2
Анализ вредоносных программ

 Читать далее...

28.05.2019г.
Просмотров: 7735
Комментарии: 1
Микросервисы и контейнеры Docker

 Читать далее...

28.05.2019г.
Просмотров: 6786
Комментарии: 0
Django 2 в примерах

 Читать далее...

Друзья сайта  

Форум системных администраторов  

sysadmins.ru

 Система криптографической защиты информации

Архив номеров / 2003 / Выпуск №4 (5) / Система криптографической защиты информации

Рубрика: Безопасность /  Механизмы защиты

ВЛАДИМИР МЕШКОВ

Система криптографической защиты информации

Без использования криптографии сегодня немыслимо решение задач по обеспечению безопасности информации, связанных с конфиденциальностью и целостностью, аутентификацией и невозможностью отказа от авторства. Если до 1990 г. криптография обеспечивала защиту исключительно государственных линий связи, то в наши дни использование криптографических методов получило широкое распространение благодаря развитию компьютерных сетей и электронного обмена данными в различных областях: финансах, банковском деле, торговле и т. д.

Управление ключами

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

Целью управления ключами является нейтрализация таких угроз, как:

  • компрометация конфиденциальности секретных ключей;
  • компрометация аутентичности секретных или открытых ключей. При этом под аутентичностью понимается знание или возможность проверки идентичности корреспондента, для обеспечения конфиденциальной связи с которым используется данный ключ;
  • несанкционированное использование секретных или открытых ключей, например использование ключа, срок действия которого истек.

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

Исходя из этого требования, разработаем модель системы криптографической защиты информации (СКЗИ), в которой доступ к ключам имеет только администратор системы. Назначение СКЗИ – криптографическое преобразование информации в соответствии с алгоритмом ГОСТ 28147-89, режим гаммирования.

Данная система реализована для операционной системы Linux, версия ядра – 2.4.17, компилятор gcc-2.95.3.

Алгоритм шифрования ГОСТ 28147-89

  • Алгоритм ГОСТ 28147-89 был разработан в СССР и является стандартом шифрования Российской Федерации, описывает принципы криптографического преобразования данных для передачи в компьютерных сетях, отдельных компьютерных комплексах или компьютерах, их шифрования и создания цифровых подписей.
  • Алгоритм ГОСТ 28147-89 криптографического преобразования предназначен как для аппаратной реализации, так и для программых реализаций, он удовлетворяет необходимым общемировым стандартам криптостойкости и не определяет ограничений на уровень секретности защищаемой информации.
  •  
  • Этот стандарт является обязательным для организаций и компаний РФ, которые используют шифровальную защиту для данных, загружаемых или передаваемых через компьютерные сети, отдельные компьютерные комплексы.
  •  
  • Стандарт алгоритма ГОСТ 28147-89 для криптографической защиты данных в компьютерных системах был опубликован в 1990 году и в настоящее время широко используется в программном обеспечении. В отличие от его собрата, алгоритма DES, принятого в качестве федерального стандарта США, ГОСТ 28147-89 позволяет достигать большего уровня секретности данных в силу отсутсвия ограничений на уровень секретности защищаемой информации.

Данный алгоритм, подобно DES, работает с блоками размером по 64 бита, но на этом их сходство заканчивается и следуют различия:

  • ГОСТ 28147-89 содержит 32 цикла преобразования, в отличие от 16 циклов DES.
  • Каждый цикл в ГОСТ 28147-89 состоит из более простых операций, чем в DES, что сказывается на скорости работы.
  • В отличие от длины ключа в DES (56 бит), стандарт ГОСТ 28147-89 описывает длину ключа 256 бит.
  • ГОСТ 28147-89 работает на порядок быстрее DES.

Состав СКЗИ и назначение структурных элементов

В состав СКЗИ входят следующие элементы:

  • модуль генерации ключевых данных;
  • драйвер криптографического преобразования (далее драйвер). Непосредственно выполняет операции криптографического преобразования информации. Содержит блок криптографического преобразования (БКП) и блок хранения ключевой информации (БКИ);
  • модуль записи ключевых данных (МКД). Осуществляет запись ключевых данных в БКИ драйвера;
  • модуль взаимодействия с драйвером (МВ). Осуществляет информационный обмен с драйвером при выполнении операций криптографического преобразования.

Алгоритм функционирования СКЗИ

Структурная схема СКЗИ представлена на рис. 1-3.

Информация, подлежащая преобразованию, поступает на вход модуля МВ. МВ, получив блок данных, вызывает системную функцию sys_gost. Данная функция дополнительно вводится в состав ядра ОС Linux. Блок входных данных является параметром вызова sys_gost. Если драйвер не загружен, функция sys_gost никаких преобразований не выполняет и возвращает вызывающему модулю нулевое значение (рис. 1).

Рисунок 1. Драйвер не загружен

Рисунок 1. Драйвер не загружен

Драйвер после загрузки перехватывает системный вызов sys_gost, и все обращения МВ к функции sys_gost будут обслуживаться драйвером. Однако если ключевые данные не введены в БКИ, драйвер также не будет выполнять криптопреобразований, возвращая МВ нулевое значение (рис. 2).

Рисунок 2. Драйвер загружен. Ключевая информация не введена

Рисунок 2. Драйвер загружен. Ключевая информация не введена

Только после того, как МКД осуществит запись ключевой информации в БКИ, входные данные, передаваемые драйверу, поступают на вход БКП. Ключевая информация предварительно формируется модулем генерации ключевых данных (рис. 3).

Рисунок 3. Драйвер загружен. Ключевая информация введена

Рисунок 3. Драйвер загружен. Ключевая информация введена

Сразу отметим, что операции загрузки драйвера и записи в него ключевых данных являются привилегированными. Выполнить их может только администратор системы, имеющий права root. Таким образом выполняется требование по ограничению доступа персонала к ключевой информации.

Реализация СКЗИ

Системный вызов sys_gost

Как было сказано выше, в состав ядра ОС Linux дополнительно вводится новый системный вызов sys_gost. Механизм системных вызовов был рассмотрен в статье «Перехват системных вызовов в ОС Linux» [1].

Добавим запись о системном вызове sys_gost() в таблицу системных вызовов sys_call_table (файл /usr/src/linux/arch/i386/kernel/entry.S):

ENTRY(sys_call_table)

           .

           .

           .

    .long SYMBOL_NAME(sys_gost)

    /* 226. Новый системный вызов! */

Наш системный вызов имеет порядковый номер 226. Добавим его в заголовочный файл /usr/src/linux/include/asm-i386/unistd.h, в котором содержится перечень всех системных вызовов ядра и макросы для работы с ними:

    #define __NR_gost   226    /* Новый системный вызов! */

В файл /usr/include/bits/syscall.h добавим запись:

    #define SYS_gost __NR_gost

Теперь осталось написать код, реализующий системный вызов sys_gost(). Вот как он выглядит:

asmlinkage int sys_gost(char * block, size_t count, int flag)

{

    return 0;

}

Этот код мы добавим в файл /usr/src/linux/fs/open.c.

Как мы видим, системный вызов sys_gost принимает три параметра: указатель на буфер с данными char *buf, размер буфера off_t count и флаг int flag. Третий параметр flag служит для информирования о начале/завершении выполнения операции криптопреобразования.

Для того чтобы процесс (модуль МВ) мог обратиться к данному системному вызову, в каталоге /usr/include/ создадим заголовочный файл gost.h следующего содержания:

#include <sys/types.h>

#include <linux/unistd.h>

#define E_START  1

#define E_STOP   0

static inline _syscall3(int,gost,char *,buf,off_t,count,int,flag)

Здесь E_START и E_STOP – флаги, информирующие о начале/завершении операции криптографического преобразования. Макрос _syscall3 сообщает компилятору, что он должен сделать, встретив в исходном тексте программы обращение к системному вызову sys_gost. Этот макрос определен в файле /usr/src/linux/include/asm-i386/unistd.h:

#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)

type name(type1 arg1,type2 arg2,type3 arg3)

{

long __res;

__asm__ volatile ("int $0x80"

    : "=a" (__res)

    : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)),

             "d" ((long)(arg3)));

__syscall_return(type,__res);

}

Таким образом, системный вызов sys_gost будет выполняться стандартным для всех системных вызовов способом: аргументы вызова загружаются в регистры процессора, а затем вызывается программное прерывание int $0x80. Конструкция __NR_##name трансформируется в порядковый номер системного вызова name, и этот номер загружается в регистр EAX.

После внесения всех изменений ядро необходимо перекомпилировать.

Драйвер

Задача драйвера – перехватить системный вызов sys_gost, принять ключи и начать выполнение операций криптографического преобразования блоков данных, поступающих от МВ. Драйвер является символьным (байт-ориентированным) устройством. Создадим для него файл устройства следующей командой:

mknod /dev/gost c 69 0

Заголовочные файлы и переменные

Для работы нам понадобятся следующие header-файлы:

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/types.h>

#include <linux/slab.h>

#include <linux/fs.h>

#include <sys/syscall.h>

#include <asm/uaccess.h>

#include "gost_var.h"

#define GOST_MAJOR      69     – старший номер устройства

Переменные:

int key_enable = 0; – флаг наличия ключевой информации в БКИ

int key_init = 0; – флаг инициализации ключевой информации

struct key_info {

    char key_d[64];

    __u32 X[8];

    char sp[8];

} keys; 

В соответствии с рис. 2 и 3, структура struct key_info keys является БКИ. В ней будет храниться ключевая информация. Назначение полей структуры struct key_info:

  • char key_d[64] – буфер для хранения долговременного ключа;
  • __u32 X[8] – буфер для хранения сеансового ключа;
  • char sp[8]   – буфер для хранения синхропосылки.

В файле gost_var.h определены переменные, необходимые для реализации алгоритма ГОСТ 28147-89. Файл имеет следующее содержание:

#include <limits.h>

const __u32 C1=0x01010104;

const __u32 C2=0x01010101;

__u32      SM1,

    SM2,

    N3,

    N4;

union {

    struct {

        __u32 N1;

        __u32 N2;

    } lg;

    char N[8];

} nac;

Значение констант C1 и C2 определено ГОСТ 28147-89. Переменные SM1 и SM2, в соответствии с терминологией ГОСТ 28147-89, назовем сумматорами, а N1, N2, N3, N4 – накопителями.

Экспортируем таблицу системных вызовов ядра:

extern void *sys_call_table[];

Вводим дополнительно указатель для сохранения оригинального системного вызова:

int (*orig_gost)(char *block, size_t count, int flag);

Инициализация драйвера

Инициализацию драйвера выполняет функция init_module. Во время инициализации перехватываем системный вызов sys_gost. Алгоритм перехвата системных вызовов был рассмотрен в статье «Перехват системных вызовов в ОС Linux» [1].

int init_module(void)

{

Регистрируем устройство в системе:

if (register_chrdev(GOST_MAJOR,"gost",&gost_fops)) return -EIO;

Сохраняем указатель на оригинальный системный вызов:

orig_gost = sys_call_table[SYS_gost];

Производим замену системных вызовов и выходим из функции:

       sys_call_table[SYS_gost] = own_gost;

    return 0;

}

Структура gost_fops содержит функции, выполняемые драйвером, имеет следующее содержание:

struct file_operations gost_fops = {

    write:       write_gost,

    open:        open_gost,

    release:     close_gost,

};

Итак, для драйвера определены функции открытия, записи и закрытия.

Функция открытия устройства

Функция имеет следующий вид:

static int open_gost(struct inode *inode, struct file *file)

{

Если устройство уже открыто, сообщить об этом:

if (MOD_IN_USE) return -EBUSY;

Проверяем значение младшего номера устройства (должно быть равно 0) и режим открытия устройства (чтение/запись):

if (MINOR(inode->i_rdev) != 0) return -ENODEV;

if ((file->f_mode & 1) != 1) return -EBUSY;

Обнуляем структуру для хранения ключевой информации:

memset(&keys,0,sizeof(struct key_info));

Сбрасываем флаг наличия ключевой информации в БКИ:

key_enable = 0;

Устанавливаем счетчик использования модуля и выходим из функции:

    MOD_INC_USE_COUNT;

    return 0;

}

Функция записи в устройство

В процессе записи драйверу передается структура типа struct key_info, содержащая ключевую информацию.

static ssize_t write_gost(struct file *file, const char *buf, size_t count, loff_t *ppos)

{

Второй аргумент функции содержит блок данных, передаваемых драйверу для обработки. Третий аргумент – размер этого блока. Проверяем размер блока:

if (count!=sizeof(struct key_info)) return -EINVAL;

Считываем передаваемый блок данных в адресное пространство драйвера (в БКИ):

copy_from_user((char *)&keys,buf,count);

Поднимаем флаг наличия ключевой информации в БКИ и выходим из функции:

    key_enable = 1;

    return count;

}

Функция закрытия устройства

Данная функция только уменьшает счетчик использования драйвера:

static int close_gost(struct inode *inode, struct file *file

{

    MOD_DEC_USE_COUNT;

    return 0;

}

Функция выгрузки драйвера

Выгружает драйвер команда rmmod. При этом вызывается функция cleanup_module:

void cleanup_module()

{

Восстанавливаем указатель на оригинальный системный вызов в таблице:

sys_call_table[SYS_gost]=orig_gost;

Обнуляем структуру, содержащую ключевую информацию:

memset(&keys,0,sizeof(struct key_info));

Снимаем регистрацию устройства:

    unregister_chrdev(GOST_MAJOR,"gost");

    return;

}

Функция own_gost

Функция own_gost, которая заменяет оригинальный системный вызов sys_gost, непосредственно выполняет операции криптографического преобразования блоков данных, переданных драйверу модулем взаимодействия МВ.

int own_gost(char *block, size_t count, int flag)

{

    int i;

Проверяем значение флагов flag и key_enable. Если оба этих флага установлены, приступаем к выполнению операции криптографического преобразования блока данных:

if ((flag && key_enable)) {

Все дальнейшие операции выполняются в соответствии с алгоритмом ГОСТ 28147-89, режим гаммирования.

Если ключи не инициализированы, выполним их инициализацию:

if (key_init == 0) init_key();

Суммируем значение накопителя N4 и константы C1 по модулю (232-1):

       __asm__ __volatile__(

    "      addl %3,%%eax "

    "      jnc 1f "

    "      incl %%eax "

 

    "1:    cmpl %2,%%eax "

    "      jnz 2f "

    "      xorl %%eax,%%eax "

    "2:"

    :"=a"(N4)

    :"0"(N4),"b"(ULONG_MAX),"d"(C1));

Суммируем значение накопителя N3 и константы C2 по модулю 232:

       N3 += C2;

Приравниваем значения накопителей:

    nac.lg.N1 = N3;

    nac.lg.N2 = N4;

Шифруем содержимое накопителей N1 и N2 в режиме простой замены алгоритма ГОСТ 28147-89:

    symple_replace_crypt();

Выполняем операцию криптографического преобразования блока данных и возвращаем МВ размер блока данных:

           for(i=0;i<=7;i++) block[i]^=nac.N[i];

           return count;

    }

Если ключи не введены (флаг key_enable сброшен), или установлен флаг завершения операции криптопреобразования (flag == E_STOP), сбрасываем флаг инициализации ключей и возвращаем нулевое значение модулю МВ:

    key_init = 0;

    return (0);

}

Функция init_key

Функция init_key() выполняет инициализацию ключей (в соответствии с алгоритмом ГОСТ 28147-89):

void init_key()

{

Поместим в накопители N1 и N2 значение синхропосылки:

    memset(&nac,0,sizeof(nac));

    memcpy(nac.N,keys.sp,8);

Шифруем содержимое накопителей N1 и N2 в режиме простой замены алгоритма ГОСТ 28147-89:

    symple_replace_crypt();

Приравниваем значение накопителей:

    N3=nac.lg.N1;

    N4=nac.lg.N2;

Поднимаем флаг инициализации ключей и возвращаемся из функции:

    key_init = 1;

    return;

}

Функция symple_replace_crypt

Операцию шифрования в режиме простой замены ГОСТ 28147-89 выполняет функция symple_replace_crypt(). Функция имеет следующий вид:

void symple_replace_crypt()

{

    int i,n;

В соответствии с алгоритмом ГОСТ 28147-89 выполняем 31 цикл преобразования:

    for(n=1;n<=3;n++) {

           for(i=0;i<=7;i++) op(i);

    }

    for(i=7;i>=1;i--) op(i);

32-й цикл несколько отличается от остальных, распишем его отдельно:

    SM1=nac.lg.N1+X[0];

    SM2=block(SM1,keys.key_d,nac.lg.N2);

    nac.lg.N2=SM2;

    return;

}

В функции op() реализованы циклы преобразования:

void op(int i)

{

Суммируем значение накопителя N1 и 4-х байтового вектора X[i] в сумматоре SM1:

    SM1 = nac.lg.N1+X[i];

Получаем результат из блока подстановки:

    SM2 = block(SM1,keys.key_d,nac.lg.N2);

    nac.lg.N2 = nac.lg.N1;

    nac.lg.N1 = SM2;

    return;

}

Функция block

В функции block объединены блок подстановки (главный структурный элемент алгоритма) и регистр сдвига. В целях повышения скорости работы данная функция реализована на языке assembler.

__u32 block(__u32 SM1, char *k, __u32 N2)

{

    __u32 SM2;

    __asm__ __volatile__ (

    "      cld "

    "      pushl %%edx "

    "      xorl %%ecx,%%ecx "

    "      xorl %%edx,%%edx "

    "      movw $4,%%cx "

    "1:    pushl %%esi "

    "      pushw %%cx "

    "      pushl %%eax "

    "      pushl %%edx "

    "      xorl %%edi,%%edi "

    "      xorw %%cx,%%cx "

    "      movl %%esi,%%edi "

    "      addl $8,%%edi "

    "      xorl %%ebx,%%ebx "

    "      xorw %%dx,%%dx "

    "      pushw %%ax "

    "      shlb $4,%%al "

    "      shrb $4,%%al "

    "      movb %%al,%%dl "

    "      popw %%ax "

    "      shrb $4,%%al "

    "      movb %%al,%%dh "

    "      xorl %%eax,%%eax "

    "      movb %%dl,%%bl "

    "      btw $0,%%bx "

    "      jnc 2f "

    "      decb %%bl "

    "      shrb $1,%%bl "

    "      movw (%%esi,%%ebx),%%ax "

    "      shrb $4,%%al "

    "      jmp 3f "

    "2:    shrb $1,%%bl "

    "      movw (%%esi,%%ebx),%%ax "

    "      shlb $4,%%al "

    "      shrb $4,%%al "

    "3:    movb %%al,%%cl "

           "      xorl %%ebx,%%ebx "

    "      movb %%dh,%%bl "

    "      btw $0,%%bx "

    "      jnc 4f "

    "      decb %%bl "

    "      shrb $1,%%bl "

    "      movw (%%edi,%%ebx),%%ax "

    "      shrb $4,%%al "

    "      shlb $4,%%al "

    "      jmp 5f "

    "4:    shrb $1,%%bl "

    "      movw (%%edi,%%ebx),%%ax "

    "      shlb $4,%%al "

    "5:    orb %%cl,%%al "

    "      popl %%edx "

    "      movb %%al,%%dl "

    "      popl %%eax "

    "      popw %%cx "

    "      rorl $8,%%edx "

    "      shrl $8,%%eax "

    "      xorl %%esi,%%esi "

    "      popl %%esi "

    "      addl $16,%%esi "

    "      decw %%cx "

    "      jz 6f "

    "      jmp 1b "

    "6:    movl %%edx,%%eax "

    "      roll $11,%%eax "

    "      popl %%edx "

    "      xorl %%edx,%%eax "

    :"=a" (SM2)

    :"0"(SM1),"S"(k),"d"(N2)

    :"ebx","ecx","edi");

    return SM2;

}

Здесь приведена «лобовая» реализация блока подстановки и регистра сдвига. На оптимальность, конечно, не претендует, но работает правильно и достаточно быстро.

Весь вышеприведенный код драйвера разместим в файле sys_call_gost.c. Функции расположим в следующем порядке (параметры функций и тип возвращаемого результата не указаны):

       block;

    op;

    symple_replace_crypt;

    init_key;

    own_gost;

    write_gost;

    open_gost;

    close_gost;

    init_module;

    cleanup_module.

Makefile

Для получения загружаемого модуля ядра (драйвера) создадим Makefile следующего содержания:

CC = gcc

module = sys_call_gost.o

CFLAGS = -O2 -Wall

LINUX = /usr/src/linux

MODFLAGS = -D__KERNEL__ -DMODULE -I$(LINUX)/include

sys_call_gost.o: sys_call_gost.c

    $(CC) $(CFLAGS) $(MODFLAGS) -c sys_call_gost.c

Модуль генерации ключевых данных

Задача модуля генерации – формирование ключевых данных (долговременного ключа, сеансового ключа и синхропосылки) и запись их на носитель. Размер ключей и синхропосылки фиксирован. Длина сеансового ключа составляет 32 байта, долговременного – 64 байта, длина синхропосылки – 8 байт.

В качестве носителя ключевых данных выберем дискету. На этой дискете (далее ключевая дискета) будут размещаться три файла:

  • файл долговременного ключа key_d длиной 64 байта;
  • файл сеансового ключа key_s длиной 32 байта;
  • файл синхропосылки sp длиной 8 байт.

Доступ к ключевой дискете должен иметь только администратор системы. Для предотвращения компрометации ключевой информации администратору необходимо обеспечить соответствующие условия ее хранения.

Подготовим ключевую дискету к работе:

fdformat /dev/fd0u1440

mkfs -V -t ext2 /dev/fd0

Перед записью ключевых данных в БКИ драйвера необходимо смонтировать ключевую дискету. Создадим точку монтирования:

mkdir /floppy

и смонтируем туда файловую систему, находящуюся на ключевой дискете:

mount -t ext2 /dev/fd0 /floppy

Теперь рассмотрим код генератора ключей. Заголовочные файлы:

#include <stdio.h>

#include <fcntl.h>

Точка монтирования файловой системы ключевого носителя:

#define MOUNT_DIR "/floppy"

int main()

{

    int s,d,sp,rnd;

    char buf[64];

Для получения случайной последовательности (а точнее, псевдослучайной) воспользуемся файлом /dev/urandom:

    rnd=open("/dev/urandom",O_RDONLY);

Формируем ключевые данные. Создаем на ключевом носителе файлы ключей и синхропосылки:

    d=open(MOUNT_DIR"/key_d",O_CREAT|O_WRONLY,0600);

    s=open(MOUNT_DIR"/key_s",O_CREAT|O_WRONLY,0600);

    sp=open(MOUNT_DIR"/sp",O_CREAT|O_WRONLY,0600);

Записываем в созданные файлы случайную последовательность, считанную из /dev/urandom:

    bzero(buf,64);

    read(rnd,buf,64);

    if(write(d,buf,64)!=64) {

    perror("key_d");

    exit(-1);

    }

    close(d);

    bzero(buf,64);

    read(rnd,buf,32);

    if(write(s,buf,32)!=32) {

    perror("key_s");

    exit(-1);

    }

    close(s);

    bzero(buf,64);

    read(rnd,buf,8);

    if(write(sp,buf,8)!=8) {

    perror("sp");

    exit(-1);

    }

    close(sp);

    close(rnd);

    return (0);

}

Генератор очень простой и приведен только в качестве примера. Необходимо отметить, что случайная последовательность, из которой формируются ключевые данные, предварительно должна быть подвергнута статистическому анализу для доказательства того, что в ней отсутствуют закономерности, которые могут позволить третьей стороне (противнику) восстановить секретный ключ. Статистический анализ представляет из себя целый комплекс специальных тестов (около 14), которые случайная последовательность должна пройти, прежде чем ее признают годной к применению. Для получения действительно случайной последовательности применяются специально спроектированные аппаратные генераторы, построенные на базе полупроводниковых приборов с высоким коэффициентом шума. Но так как мы рассматриваем модель СКЗИ, то жестких требований к качеству ключевой информации предъявлять не будем. Для нашей задачи вполне подойдет и псевдослучайная последовательность.

После завершения операции формирования ключевых данных вводим команду:

    umount /dev/fd0

Теперь ключевой носитель готов к применению.

Модуль записи ключевых данных

Задача модуля записи ключевых данных (МКД) – записать ключи, находящиеся на ключевой дискете, в БКИ драйвера. Рассмотрим программный код МКИ.

Заголовочные файлы:

#include <stdio.h>

#include <stdlib.h>

#include <fcntl.h>

#include <sys/types.h>

#include <errno.h>

Точка монтирования файловой системы, находящейся на дискете:

#define MOUNT_DIR "/floppy"

int main()

{

Дескрипторы ключевых файлов, синхропосылки и файла устройства:

    int s,d,sp,gost;

Структура для хранения ключевой информации:

    struct key_info {

    char key_d[64];

    u_long X[8];

    char sp[8];

    } keys;

    memset(&keys,0,sizeof(struct key_info));

Открываем все необходимые файлы:

    gost=open("/dev/gost",O_RDWR);

    if(gost < 0) {

    perror("gost");

    exit(-1);

    }

    sp=open(MOUNT_DIR"/sp",O_RDONLY);

    if(sp < 0) {

    perror("sp");

    exit(-1);

    }

    d=open(MOUNT_DIR"/key_d",O_RDONLY);

    if(d < 0) {

    perror("key_d");

    exit(-1);

    }

    s=open(MOUNT_DIR"/key_s",O_RDONLY);

    if(s < 0) {

    perror("key_s");

    exit(-1);

    }

Считываем информацию из файлов ключей и синхропосылки в структуру struct key_info:

    if(read(d,keys.key_d,64)!=64){

    perror("key_d");

    exit(-1);

    }

    if(read(s,(char *)&keys.X,32)!=32){

    perror("key_s");

    exit(-1);

    }

    if(read(sp,keys.sp,8)!=8){

    perror("sp");

    exit(-1);

    }

Записываем ключевую информацию в БКИ:

    write(gost,(char *)&keys,sizeof(struct key_info));

Информируем о завершении процедуры записи ключей:

    printf(" Keys loaded ");

Закрываем файлы и выходим:

    close(gost);

    close(d);

    close(s);

    close(sp);

    return (1);

}

Вышеприведенный код сохраним в файле write_key.c. Получим исполняемый модуль, введя команду:

    gcc -o write_key write_key.c

Модуль взаимодействия с драйвером

Задача модуля взаимодействия с драйвером (МВ) – осуществлять информационный обмен с драйвером при выполнении операций криптографического преобразования.

Программный код модуля МВ:

int main (int argc, char **argv)

{

    int in,n;

    char buff[8];

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

    if(argc!=2) {

    printf(" Usage: gost [input file] ");

    exit(0);

    }

Открываем входной файл:

    in=open(argv[1],O_RDWR);

    if(in < 0) {

    perror("input");

    exit(-1);

    }

    memset(buff,0,8);

Считываем из входного файла блоки данных длиной 8 байт:

    while((n=read(in,buff,8)) > 0) {

Вызываем системную функцию sys_gost для выполнения операции криптопреобразования блока данных:

       gost(buff,n,E_START);

Результат преобразования записываем в тот же файл:

       lseek(in,-n,SEEK_CUR);

    write(in,buff,n);

    }

Информируем драйвер о завершении операции криптографического преобразования:

    gost(0,0,E_STOP);

Закрываем входной файл и выходим из программы:

    close(in);

    return 0;

}

Вышеприведенный код сохраним в файле gost.c. Исполняемый модуль получим, введя команду:

       gcc -o gost gost.c

Порядок работы с СКЗИ

Для подготовки СКЗИ к работе администратор системы должен выполнить следующие действия:

  • загрузить драйвер командой

 insmod sys_call_gost.o

  • подготовить дискету и сформировать ключевые данные;
  • записать ключи в БКИ:
    • смонтировать файловую систему ключевой дискеты командой mount -t ext2 /dev/fd0 /floppy;
    • запустить на выполнение модуль МКД (файл write_key). В случае успешного завершения МКД выдаст сообщение Keys loaded;
  • после записи ключевых данных в БКИ ввести команду umount /dev/fd0;
  • изъять из дисковода ключевой носитель и поместить его в специально выделенное хранилище.

После того как администратор подготовит СКЗИ к работе, пользователь (оператор) может приступить к выполнению операций криптографического преобразования информации. Для этого ему достаточно запустить на выполнение модуль МВ (исполняемый файл gost), указав в командной строке имя преобразуемого файла. Результат преобразования будет записан в тот же файл. Ключи расположены в адресном пространстве ядра ОС, и модуль МВ, работающий в режиме приложения пользователя (третье кольцо защиты), прямого доступа к ключевой информации не имеет.

Таким образом, рассмотренная модель СКЗИ позволяет обеспечить достаточно высокий уровень защиты личных данных пользователя и ключевых данных от компрометации.

Литература:

  1. Мешков В. Перехват системных вызовов в ОС Linux. – Журнал «Системный администратор», №3, март 2003 г. – 40-44 с.

Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-41
Fax: (499) 277-12-45
E-mail: sa@samag.ru