The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Разработка модуля Linux ядра, реализующего алгоритм криптозащиты ГОСТ 28147-89 (linux kernel module crypt gcc)


<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>
Ключевые слова: linux, kernel, module, crypt, gcc,  (найти похожие документы)
From: Bob <ubob at mail.ru> Newsgroups: email Date: Fri, 2 Jul 2004 14:31:37 +0000 (UTC) Subject: Разработка модуля Linux ядра, реализующего алгоритм криптозащиты ГОСТ 28147-89 РАЗРАБОТКА МОДУЛЯ ЯДРА ОПЕРАЦИОННОЙ СИСТЕМЫ LINUX, РЕАЛИЗУЮЩЕГО АЛГОРИТМ КРИПТОГРАФИЧЕСКОЙ ЗАЩИТЫ ИНФОРМАЦИИ ГОСТ 28147-89 1. Введение --------------------- Без использования криптографии сегодня немыслимо решение задач по обеспечению безопасности информации, связанных с конфиденциальностью и целостностью, аутентификацией и невозможностью отказа от авторства. Если до 1990 г. криптография обеспечивала защиту исключительно государственных линий связи, то в наши дни использование криптографических методов получило широкое распространение благодаря развитию компьютерных сетей и электронного обмена данными в различных областях: финансах, банковском деле, торговле и т.д. 2. Управление ключами ------------------------ Важнейшую роль в криптографии играет управление ключами. Это основа для обеспечения конфиденциальности обмена информацией, идентификации и целостности данных. Целью управления ключами является нейтрализация таких угроз, как: - компрометация конфиденциальности секретных ключей; - компрометация аутентичности секретных ключей и открытых ключей. При этом под аутентичностью понимается знание или возможность проверки идентичности корреспондента, для обеспечения конфиденциальной связи с которым используется данный ключ; - несанкционированное использование секретных или открытых ключей, например использование ключа, срок действия которого истек. Для снижения риска компрометации конфиденциальности секретных ключей необходимо ограничить круг лиц, у которых есть доступ к ключевой информации. Работать с ключами должен специально подготовленный персонал, имеющий соответствующие полномочия (допуск). Исходя из этого требования, разработаем модель системы криптографической защиты информации (СКЗИ), в которой доступ к ключам имеет только администратор системы. 3. Назначение, состав и алгоритм функционирования СКЗИ ---------------------------------------------------------------- Назначение СКЗИ - криптографическое преобразование (шифрование/расшифрование) файлов пользователя в соответствии с алгоритмом ГОСТ 28147-89, режим гаммирования. Описание стандарта ГОСТ 28147-89 можно взять здесь: http://www.enlight.ru/crypto/articles/vinokurov/gost_i.htm В состав СКЗИ входят следующие структурные элементы: - криптографический драйвер (далее драйвер). Непосредственно выполняет операцию криптографического преобразования информации в соответствии с алгоритмом ГОСТ 28147-89. Содержит блок криптографического преобразования (БКП) и блок хранения ключевой информации (БКИ); - модуль ключевых данных (МКД). Выполняет генерацию ключевых данных и их последующую запись в БКИ драйвера; - модуль взаимодействия с драйвером (МВ). Представляет собой приложение пользователя, и выполняет передачу драйверу информационных блоков, подлежащих криптопреобразованию. Алгоритм функционирования СКЗИ следующий: - модуль МВ считывает из файла блок данных и вызывает системную функцию sys_gost(), передав ей блок данных в качестве параметра. Но функция sys_gost() никаких преобразований над данными не выполняет; - драйвер после загрузки перехватывает системный вызов sys_gost(), и все обращения МВ к функции sys_gost() будут обслуживаться драйвером. Если ключевые данные не введены в БКИ, драйвер также не будет выполнять криптографических преобразований, возвращая модулю МВ данные в неизмененном виде. Только после того, как МКД выполнит генерацию ключевых данных и их запись в БКИ драйвера, данные, передаваемые драйверу, будут поступать на вход БКП. Сразу отметим, что операции загрузки драйвера и записи в него ключевых данных являются привилегированными. Выполнить их может только администратор системы, имеющий права root. Таким образом выполняется требование по ограничению доступа персонала к ключевой информации. 4. Системный вызов sys_gost ------------------------------------ Как было сказано выше, в состав ядра Linux вводится новый системный вызов. Методика добавления в ядро новых системных вызовов была рассмотрена здесь: http://opennet.ru/base/dev/new_linux_syscall.txt.html - добавляем запись о системном вызове sys_gost() в таблицу системных вызовов sys_call_table (файл arch/i386/kernel/entry.S): ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/ . . . .long SYMBOL_NAME(sys_gost) /* sys_gost call 259 */ Системный вызов sys_gost() имеет порядковый номер 259 (ядро версии 2.4.26). - в файл include/asm-i386/unistd.h добавляем запись: #define __NR_gost 259 - в файл /usr/include/bits/syscall.h добавляем запись: #define SYS_gost __NR_gost - в файл fs/open.c добавим код, реализующий системный вызов sys_gost(): asmlinkage long sys_gost(unsigned char *block, size_t count, int mode) { return 0; } Системный вызов sys_gost принимает три параметра: указатель на блок с данными, размер блока и флаг, информирующий о начале/завершении операции криптопреобразования. - в каталоге /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,unsigned char *,block,size_t,count,int,mode) E_START и E_STOP - флаги, информирующие о начале/завершении операции криптографического преобразования. После внесения всех изменений ядро необходимо перекомпилировать. 5. Реализация СКЗИ ---------------------- 5.1. Драйвер Задача драйвера - перехватить все обращения к системной функции sys_gost, сохранить в БКИ ключевые данные, переданные модулем МКД, и приступить к выполнению операций криптографического преобразования блоков данных, поступающих от модуля МВ. Драйвер является символьным устройством. Создадим для него файл устройства следующей командой: mknod /dev/gost c 69 0 Адреса всех системных вызовов хранятся в специальной таблице - таблице системных вызовов (далее ТСВ). Для обращения к той или иной системной функции ядро извлекает адрес этой функции из ТСВ, и передает управление по этому адресу. Для перехвата обращений к системной функции sys_gost() драйверу необходимо в ТСВ произвести замену адреса функции sys_gost адресом нового обработчика. Чтобы выполнить эту операцию, драйвер должен знать адрес самой ТСВ. Т.к. все системные вызовы выполняются через программное прерывание int 0x80, то адрес таблицы можно извлечь из обработчика этого прерывания - функции system_call. Определение функции system_call находится в файле arch/i386/kernel/entry.S. Рассмотрим, как выполняется обращение к системной функции. В функции system_call это выглядит следующим образом: ENTRY(system_call) . . call *SYMBOL_NAME(sys_call_table)(,%eax,4) . В регистре EAX находится номер системного вызова. Управление передается по адресу, который находится в ТСВ по смещению ([EAX] * 4) относительно базового адреса таблицы sys_call_table, т.к. адрес каждого вызова занимает 4 байта. Данный вызов равнозначен выражению на С: /* вызов функции в массиве функций */ (sys_call_table[eax])() Найдем опкод команды обращения к системной функции. Для этого загрузим ядро в отладчик: gdb -q /usr/src/linux/vmlinux и дизассемблируем функцию system_call: disas system_call Ищем строку следующего содержания: 0xc0109008 <system_call + 44>: call *0xc0307b50(,%eax,4) Это и есть обращение к системной функции. Базовый адрес ТСВ равен 0xc0307b50 (у вас числа, скорее всего, будут другие). Вводим команду: x/xw system_call + 44 Получаем: 0xc0109008 <system_call + 44>: 0x508514ff Опкод команды обращения к системной функции равен \xff\x14\x85. Следующие 4 байта являются адресом ТСВ: x/xw system_call + 47 0xc010900b <system_call + 47>: 0xc0307b50 Таким образом, чтобы извлечь из функции system_call адрес ТСВ, достаточно найти в теле функции сигнатуру \xff\x14\x85. Следующие за ней 4 байта будут искомым адресом таблицы. Но для того, чтобы выполнить этот поиск, необходимо знать адрес самой функции system_call. Эта задача решается просто: поскольку функция system_call является обработчиком прерывания int 0x80, ее адрес находится в таблице дескрипторов прерываний, Interrupt Descriptor Table (IDT). Адрес IDT хранит специальный регистр IDTR, получить значение из которого можно при помощи инструкции SIDT. Алгоритм поиска адреса таблицы системных вызовов выглядит следующим образом: - извлечь из регистра IDTR адрес таблицы IDT; - из таблицы IDT извлечь адрес обработчика программного прерывания int 0x80. Это будет адрес функции system_call; - в теле функции system_call выполнить поиск сигнатуры \xff\x14\x85 и считать следующие за ней 4 байта - искомый адрес ТСВ. Рассмотрим функцию, реализующую алгоритм поиска адреса ТСВ.
/* * Листинг 1. Функция определения адреса таблицы системных вызовов * (файл get_sct_addr.c) */ #include <linux/module.h> #include <linux/slab.h> #include <linux/types.h> #define SIGN "\xff\x14\x85" #define INT80_LEN 128 /* Структура дескриптора таблицы IDT */ struct descr_idt { __u16 off_low; // младшие 16 бит адреса обработчика прерывания __u16 sel; __u8 none, flags; __u16 off_high; // старшие 16 бит адреса обработчика прерывания } __attribute__ ((packed)) idt; /* Структура регистра IDTR */ struct { __u16 limit; __u32 base; // адрес таблицы IDT } __attribute__ ((packed)) idtr; __u32 get_sct_addr() { int i; __u32 sct; // в этой переменной сохраним адрес таблицы __u32 idt_addr = 0; // адрес таблицы IDT __u32 sc_addr = 0; // адрес ф-ии system_call __u8 sc[INT80_LEN]; // сюда скопируем первые 128 байт функции system_call __u8 p[4]; // вспомогательный буфер /* * Определяем адрес таблицы дескрипторов прерываний IDT */ __asm__ ("sidt %0":"=m" (idtr)); idt_addr = idtr.base; /* * Считываем из IDT дескриптор обработчика int 0x80 - функции system_call */ memset((void *)&idt, 0, sizeof(struct descr_idt)); memcpy((void *)&idt, (void *)(idt_addr + 8 * 0x80), sizeof(struct descr_idt)); /* * Из двух половинок - off_high и off_low - формируем адрес system_call */ sc_addr = (idt.off_high << 0x10) | idt.off_low; /* * Из функции system_call считываем первые 128 байт */ memset((void *)sc, 0, INT80_LEN); memcpy((void *)sc, (void *)sc_addr, INT80_LEN); /* * Выполняем поиск сигнатуры \xff\x14\x85 */ for(i = 0; i < INT80_LEN; i++) { memset((void *)p, 0, 4); memcpy((void *)p, (void *)(sc + i * 4), 4); if(!(memcmp((void *)p, SIGN, 3))) { memcpy((void *)&sct, (void *)(sc + i * 4 + 3), 4); break; } } printk(KERN_INFO "sys_call_table address - 0x%08X\n", sct); /* * Возвращаем найденный адрес */ return sct; }
Определим дополнительно заголовочный файл gost_var.h, в котором разместим вспомогательные переменные и структуры, необходимые для реализации алгоритма ГОСТ 28147-89. Файл имеет следующее содержание:
/* * Листинг 2. Файл gost_var.h */ #include <linux/types.h> #ifndef C1 #define C1 0x01010104 #endif #ifndef C2 #define C2 0x01010101 #endif __u32 SM1, SM2, N3, N4; int key_enable; // флаг наличия ключевой информации в БКИ int key_init; // флаг инициализации ключей union { struct { __u32 N1; __u32 N2; } __attribute__ ((packed)) lg; __u8 N[8]; } nac; /* * Структура для хранения ключевой информации, переданной модулем МКД. * В соответствии с алгоритмом (см. п. 2), данная структура является БКИ */ struct key_info { __u8 key_d[64]; __u32 X[8]; __u8 sp[8]; } keys;
Значения C1 и C2 определены ГОСТ 28147-89. Переменные SM1 и SM2, в соответствии с терминологией ГОСТ, назовем сумматорами, а N1, N2, N3, N4 - накопителями. Поиск адреса таблицы системных вызовов будет выполнен во время инициализации драйвера. Рассмотрим следующий листинг:
/* * Листинг 3. Функция инициализации драйвер и загрузки ключей в БКИ * (файл sys_call_gost.c) */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.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 // старший номер устройства /* * Прототипы функций поиска адреса ТСВ и нового обработчика системного * вызова sys_gost */ __u32 get_sct_addr(); int new_gost(__u8 *, size_t, int); __u32 old_sys_gost_addr = 0; // здесь сохраним старый адрес sys_gost __u32 sct = 0; // адрес ТСВ /* * Функция записи в устройство. В процессе записи драйверу передается структура * типа struct key_info (см. Листинг 2), содержащая ключевую информацию */ 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 open_gost(struct inode *inode, struct file *file) { if(MOD_IN_USE) return -EBUSY; if (MINOR(inode->i_rdev) != 0) return -ENODEV; /* * Проверяем режим открытия файла устройства. Файл должен быть * открыт в режиме "Только для записи" */ if ((file->f_flags & O_ACCMODE) != O_WRONLY) return -EACCES; memset(&keys, 0, sizeof(struct key_info)); key_enable = 0; MOD_INC_USE_COUNT; return 0; } /* * Функция закрытия файла устройства. Ничего не выполняет, * просто уменьшает счетчик использования драйвера */ static int close_gost(struct inode *inode, struct file *file) { MOD_DEC_USE_COUNT; return 0; } struct file_operations gost_fops = { write: write_gost, open: open_gost, release: close_gost, }; /* * Функция инициализация драйвера. Выполняет регистрацию устройства * в системе и производит замену адресов в ТСВ */ static int __init init_gost() { if(register_chrdev(GOST_MAJOR, "/dev/gost", &gost_fops)) return -EIO; /* * Определяем адрес ТСВ и заменяем адрес системного вызова sys_gost * адресом нового обработчика - функции new_gost. Адрес "старого" вызова * сохраняем в переменной old_sys_gost_addr */ sct = get_sct_addr(); old_sys_gost_addr = *(__u32 *)(sct + SYS_gost * 4); *(__u32 *)(sct + SYS_gost * 4) = (__u32)&new_gost; key_enable = 0; key_init = 0; return 0; } /* * При выгрузке модуля восстанавливаем адрес системного вызова * sys_gost в ТСВ */ static void __exit exit_gost() { *(__u32 *)(sct + SYS_gost * 4) = old_sys_gost_addr; memset(&keys, 0, sizeof(struct key_info)); unregister_chrdev(GOST_MAJOR, "/dev/gost"); return; } module_init(init_gost); module_exit(exit_gost);
Рассмотрим функцию new_gost, которая заменит системный вызов sys_gost. Эта функция непосредственно выполняет операции криптографического преобразования блоков данных, переданных драйверу модулем МВ.
/* * Листинг 4. Функция, выполняющая операции криптографического преобразования * информации (файл gost.c) */ #include <linux/module.h> #include <linux/slab.h> #include <limits.h> #include "gost_var.h" void simple_replace_crypt(void); void op(int); void init_key(); __u32 block(__u32, __u8 *, __u32); /* * Функция new_gost принимает три параметра - указатель на блок данных, * подлежащих криптопреобразованию, размер блока и флаг управления режимом */ int new_gost(__u8 *block, size_t count, int flag) { int i; /* * Если ключи не загружены, флаг key_enable установлен в 0. В этом * случае драйвер никаких криптопреобразований не выполняет */ if(!key_enable) { printk(KERN_INFO "Keys not loaded\n"); return 1; } /* * Проверяем значения флагов flag и key_enable. Если оба флага установлены, * приступаем к выполнению операции криптопреобразования блока данных */ if((flag && key_enable)) { /* * Все дальнейшие операции выполняются в соответствии с алгоритмом * ГОСТ 28147-89, режим гаммирования. * * Инициализируем ключи */ if(!key_init) init_key(); /* * Суммируем значение накопителя N4 и константы C1 по модулю (2^32-1) */ __asm__ __volatile__ ( " addl %3,%%eax \n\t" " jnc 1f \n\t" " incl %%eax \n\t" "1: cmpl %2,%%eax \n\t" " jnz 2f \n\t" " xorl %%eax,%%eax \n\t" "2:" :"=a"(N4) :"0"(N4),"b"(ULONG_MAX),"d"(C1) ); /* * Суммируем значение накопителя N3 и константы C2 по модулю (2^32) */ N3 += C2; nac.lg.N1 = N3; nac.lg.N2 = N4; /* * Шифруем содержимое накопителей N1 и N2 в режиме простой замены * алгоритма ГОСТ 28147-89 */ simple_replace_crypt(); /* * Выполняем криптопреобразование блока данных и возвращаем модулю МВ * размер этого блока */ for(i = 0; i < count; i++) block[i] ^= nac.N[i]; return count; } /* * Если установлен флаг завершения операции криптопреобразования * (flag = E_STOP), сбрасываем флаг инициализации ключей и возвращаем * нулевое значение модулю МВ */ key_init = 0; return 0; } /* * Функция simple_replace_crypt() выполняет операцию шифрования в режиме * простой замены алгоритма ГОСТ 28147-89 */ void simple_replace_crypt() { int i,n; /* * В соответствии с алгоритмом ГОСТ 28147-89, выполняем 31 цикл преобразования */ for(n = 1; n < 4; n++) { for(i = 0; i < 8; i++) op(i); } for(i = 7; i > 0; i--) op(i); /* * 32-й цикл */ SM1 = nac.lg.N1 + keys.X[0]; SM2 = block(SM1, keys.key_d, nac.lg.N2); nac.lg.N2 = SM2; return; } /* * Циклы преобразования реализованы в функции op(int) */ void op(int i) { /* * Суммируем значение накопителя N1 и 4-х байтового вектора X[i] * в сумматоре SM1 */ SM1 = nac.lg.N1 + keys.X[i]; /* * Выполняем преобразование значения, находящегося в сумматоре SM1, * в блоке подстановки */ SM2 = block(SM1, keys.key_d, nac.lg.N2); nac.lg.N2 = nac.lg.N1; nac.lg.N1 = SM2; } /* * Функция init_key() выполняет процедуру инициализации ключевых данных */ void init_key() { /* * Копируем значение синхропосылки с накопители N1 и N2 */ memset(&nac, 0, sizeof(nac)); memcpy(nac.N, keys.sp, 8); /* * Шифруем содержимое накопителей N1 и N2 в режиме простой замены * алгоритма ГОСТ 28147-89 */ simple_replace_crypt(); N3 = nac.lg.N1; N4 = nac.lg.N2; /* * Устанавливаем значение флага инициализации ключей в 1 */ key_init = 1; return; } /* * В функции block об`единены блок подстановки (главный структурный элемент * алгоритма) и регистр сдвига. Параметры функции: * - значение сумматора SM1 * - указатель на блок данных, содержащих долговременный ключ * - значение накопителя N2 * Результат, возвращаемый функцией block, будет помещен в сумматор SM2 */ __u32 block(__u32 SM1, __u8 *k, __u32 N2) { __u32 SM2; __asm__ __volatile__ ( " cld \n\t" " pushl %%edx \n\t" " xorl %%ecx,%%ecx \n\t" " xorl %%edx,%%edx \n\t" " movw $4,%%cx \n\t" "1: pushl %%esi \n\t" " pushw %%cx \n\t" " pushl %%eax \n\t" " pushl %%edx \n\t" " xorl %%edi,%%edi \n\t" " xorw %%cx,%%cx \n\t" " movl %%esi,%%edi \n\t" " addl $8,%%edi \n\t" " xorl %%ebx,%%ebx \n\t" " xorw %%dx,%%dx \n\t" " pushw %%ax \n\t" " shlb $4,%%al \n\t" " shrb $4,%%al \n\t" " movb %%al,%%dl \n\t" " popw %%ax \n\t" " shrb $4,%%al \n\t" " movb %%al,%%dh \n\t" " xorl %%eax,%%eax \n\t" " movb %%dl,%%bl \n\t" " btw $0,%%bx \n\t" " jnc 2f \n\t" " decb %%bl \n\t" " shrb $1,%%bl \n\t" " movw (%%esi,%%ebx),%%ax \n\t" " jmp 3f \n\t" "2: shrb $1,%%bl \n\t" " movw (%%esi,%%ebx),%%ax \n\t" " shlb $4,%%al \n\t" "3: shrb $4,%%al \n\t" " movb %%al,%%cl \n\t" " xorl %%ebx,%%ebx \n\t" " movb %%dh,%%bl \n\t" " btw $0,%%bx \n\t" " jnc 4f \n\t" " decb %%bl \n\t" " shrb $1,%%bl \n\t" " movw (%%edi,%%ebx),%%ax \n\t" " shrb $4,%%al \n\t" " jmp 5f \n\t" "4: shrb $1,%%bl \n\t" " movw (%%edi,%%ebx),%%ax \n\t" "5: shlb $4,%%al \n\t" " orb %%cl,%%al \n\t" " popl %%edx \n\t" " movb %%al,%%dl \n\t" " popl %%eax \n\t" " popw %%cx \n\t" " rorl $8,%%edx \n\t" " shrl $8,%%eax \n\t" " xorl %%esi,%%esi \n\t" " popl %%esi \n\t" " addl $16,%%esi \n\t" " decw %%cx \n\t" " jz 6f \n\t" " jmp 1b \n\t" "6: movl %%edx,%%eax \n\t" " roll $11,%%eax \n\t" " popl %%edx \n\t" " xorl %%edx,%%eax \n\t" :"=a" (SM2) :"0"(SM1),"S"(k),"d"(N2) :"ebx","ecx","edi"); return SM2; }
Для сборки загружаемого модуля ядра создадим Makefile следующего содержания: .PHONY = clean MOD_NAME = gost CFLAGS = -O2 -Wall LINUX = /usr/src/linux MODFLAGS = -D__KERNEL__ -DMODULE -I$(LINUX)/include OBJ = sys_call_gost.o get_sct_addr.o gost.o $(MOD_NAME): $(OBJ) ld $^ -r -o $@ %.o: %.c gcc $(CFLAGS) $(MODFLAGS) -c $^ clean: rm -f *.o rm -f ./gost Загрузка драйвера выполняется командой: insmod ./gost 5.2. Модуль ключевых данных --------------------------- Модуль ключевых данных (МКД) выполняет две задачи: - генерацию ключевых данных; - запись ключевых данных в БКИ драйвера. Ключевые данные представляют собой три файла фиксированного размера: - файл долговременного ключа key_d длиной 64 байт; - файл сеансового ключа key_s длиной 32 байт; - файл синхропосылки key_sp длиной 8 байт. В соответствии с выполняемыми функциями, в состав МКД будут входить: - генератор ключевых данных; - модуль записи ключевых данных в БКИ драйвера. Рассмотрим код генератора ключевых данных.
/* * Листинг 5. Генератор ключевых данных (файл creat_key.c) */ #include <stdio.h> #include <unistd.h> #include <fcntl.h> #define MOUNT_DIR "./" int main() { struct struct_key { char *k_name; int k_size; }; struct struct_key k[3] = { { MOUNT_DIR"/key_d", 64}, { MOUNT_DIR"/key_s", 32}, { MOUNT_DIR"/key_sp", 8}, }; int i = 0, fdkey, rnd; char buf[64]; rnd = open("/dev/urandom", O_RDONLY); if(rnd < 0) { perror("open"); return -1; } for(; i < 3; i++) { fdkey = open(k[i].k_name, O_CREAT|O_WRONLY, 0600); if(fdkey < 0) { perror("open"); return -1; } memset(buf, 0, 64); if(read(rnd, buf, k[i].k_size) != k[i].k_size) { close(fdkey); perror("read"); return -1; } if(write(fdkey, buf, k[i].k_size) != k[i].k_size) { perror("write"); return -1; } close(fdkey); } close(rnd); printf("\nKeys generation is complite\n\n"); return 0; }
Код очень простой, поэтому приводится без комментариев. Для получения случайной последовательности мы воспользовались файлом /dev/urandom.
/* * Листинг 6. Модуль записи ключевых данных в БКИ драйвера (файл write_key.c) */ #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #define KEYDIR "./" // ключи будут находиться в текущем каталоге /* * Структура struct key_struct будет передана драйверу для записи в БКИ */ struct key_struct { char key_d[64]; unsigned long X[8]; char sp[8]; } __attribute ((packed)) keys; char tmp_buff[104]; struct struct_key { char *k_name; int k_size; } __attribute__ ((packed)); struct struct_key k_st[3] = { { KEYDIR"/key_d", 64}, { KEYDIR"/key_s", 32}, { KEYDIR"/key_sp", 8}, }; int main() { int i = 0, fdkey, gost, pos = 0; memset((void *)tmp_buff, 0, sizeof(tmp_buff)); for(; i < 3; i++) { fdkey = open(k_st[i].k_name, O_RDONLY); if(fdkey < 0) { perror("open"); return -1; } if(read(fdkey, (tmp_buff + pos), k_st[i].k_size) != k_st[i].k_size) { perror("read"); return -1; } pos += k_st[i].k_size; close(fdkey); } memset((void *)&keys, 0, sizeof(struct key_struct)); memcpy((void *)&keys, tmp_buff, sizeof(tmp_buff)); gost = open("/dev/gost", O_WRONLY); if(gost < 0) { perror("open"); return -1; } if(write(gost, (char *)&keys, sizeof(struct key_struct)) < 0) { perror("write"); } else printf("\nKeys has been loaded successfuly\n\n"); memset((void *)&keys, 0, sizeof(struct key_struct)); close(gost); return 0; }
Для предотвращения компрометации ключевые данные целесообразно хранить на отдельном носителе, например, на дискете. При этом администратору необходимо обеспечить соответствующие условия хранения данного носителя. 5.3. Модуль взаимодействия с драйвером -------------------------------------- Модуль взаимодействия с драйвером (МВ) представляет собой приложение пользователя. Его задача - обмен информационными блоками с драйвером и сохранение результатов в файле.
/* * Листинг 7. Модуль взаимодействия с драйвером (файл test_gost.c) */ #include <stdio.h> #include <gost.h> #include <fcntl.h> int main(int argc, char **argv) { int in, n; unsigned char buff[8]; /* * Параметром модуля МВ является имя файла, содержание которого подлежит * криптографическому преобразованию */ if(argc != 2) { printf("\n\tUsage: gost [input file]\n\n"); return 0; } /* * Открываем файл */ in = open(argv[1], O_RDWR); if(in < 0) { perror("open"); return -1; } memset((void *)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; }
6. Порядок работы с СКЗИ -------------------------- Для подготовки СКЗИ к работе администратор должен выполнить следующие действия: - загрузить криптографический драйвер - сгенерировать ключевые данные и записать их в БКИ драйвера После этого пользователь может приступить к выполнению операций криптографической защиты информации. Для этого ему достаточно запустить на выполнение модуль МВ (файл test_gost), указав в командной строке имя преобразуемого файла. Результат преобразования будет записан в тот же файл.

<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>

Обсуждение [ RSS ]
  • 1, Миша (??), 14:37, 22/04/2008 [ответить]  
  • +/
    Этот вариант работает на всех версии ядра линукса?
     
     
  • 2, Vovan Putin (?), 19:39, 13/05/2009 [^] [^^] [^^^] [ответить]  
  • +/
    Или используйте OpenSSL-0.9.9, или пишите честный crypto алгоритм, чтобы и IPsec и всё такое, а так получается, извините, лабораторная работа первокурсника по Linux 2.0
     
     
  • 3, ubob (??), 19:41, 07/01/2010 [^] [^^] [^^^] [ответить]  
  • +/
    Своему папе советы давай, дятел
     
     
  • 4, Поцыус Клей (?), 11:27, 11/10/2010 [^] [^^] [^^^] [ответить]  
  • +/
    юбоб - вы маленький дурачок, вам дело говорят
     

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Партнёры:
    PostgresPro
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2024 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру