- •Методические указания для выполнения лабораторной работы № 1.1 по курсу «Защита информационных ресурсов компьютерных систем и сетей» «Использование библиотеки OpenSsl»
- •Цель работы
- •Краткие теоретические сведения
- •Void main()
- •Int outf;
- •If(rand_bytes(buf, sizeof(buf))) { /* 1 succes, 0 otherwise */
- •Void md5_Init(md5_ctx * ctx);
- •Void md5_Update(md5_ctx * ctx, const void * data, unsigned long len);
- •Void md5_Final(unsigned char * md, md5_ctx * ctx);
- •Int md5_Init(md5_ctx *c)
- •Void main(int argc, char **argv)
- •Void *md_data;
- •Int evp_DigestUpdate(evp_md_ctx *ctx, const void *d, unsigned int cnt);
- •Int evp_DigestFinal(evp_md_ctx *ctx, unsigned char *md, unsigned int *s);
- •Void main(int argc, char **argv)
- •Int md_len; /* размер вычисленного хэша */
- •Int main()
- •Void bf_set_key(bf_key *key, int len, const unsigned char *data);
- •Void bf_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length, const bf_key *schedule, unsigned char *ivec, int *num, int enc);
- •Int do_crypt(file *in, file *out, int mode)
- •Void do_crypt(file *in, file *out)
- •If(!evp_EncryptUpdate(&ctx, outbuf, &outlen, inbuf, inlen)) return 0;
- •If(!evp_EncryptFinal(&ctx, outbuf, &outlen)) return 0;
- •Int dmax; /* Size of the d array. */
- •Int neg; /* one if the number is negative */
- •Int flags;
- •Int pem_write_rsaPublicKey(file *fp, rsa *X);
- •Int pem_write_rsaPrivateKey(file *fp, rsa *X, const evp_cipher *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u);
- •Void main()
- •Int rsa_public_encrypt(int flen, unsigned char *from, unsigned char *to, rsa *rsa, int padding);
- •Void main(int argc, char **argv)
- •Int rsa_private_decrypt(int flen, unsigned char *from, unsigned char *to, rsa *rsa, int padding);
- •Void main(int argc, char **argv)
- •Ход работы
- •Содержание отчета
- •Используемые источники
Void *md_data;
} /* EVP_MD_CTX */;
Заполнение контекста выполняется при помощи функции EVP_DigestInit(). В параметрах этой функции передаются указатели на контекст для вычисления хэша и на структуру, содержащую адреса функций алгоритма хэширования:
EVP_DigestInit(EVP_MD_CTX * ctx, EVP_MD * md)
Функция копирует структуру "EVP_MD * md" в контекст дайджеста путем приравнивания соответствующих указателей (см. файл crypto/evp/digest.c исходных текстов библиотеки):
ctx->digest = md;
Заполнив контекст, мы получаем возможность вызывать библиотечные функции для вычисления хэша, используя адреса, которые сохранены в структуре digest-контекста. Вычисление хэша выполняет функция EVP_DigestUpdate(), функция EVP_DigestFinal() копирует вычисленный хэш из контекста дайджеста в выходной буфер:
Int evp_DigestUpdate(evp_md_ctx *ctx, const void *d, unsigned int cnt);
Int evp_DigestFinal(evp_md_ctx *ctx, unsigned char *md, unsigned int *s);
Параметры функции EVP_DigestUpdate - указатель на контекст для вычисления хэша ctx, буфер d для хранения промежуточного результата вычисления и размер этого буфера cnt. Функция EVP_DigestFinal сохраняет размер вычисленного хэша в последнем параметре *s.
По завершении работы контекст для вычисления хэша очищается при помощи функции EVP_MD_CTX_cleanup().
Листинг 3 демонстрирует порядок использования высокоуровневых функций библиотеки для вычисления хэша файла по алгоритму MD5.
Листинг 3. Вычисление MD5-хэша файла с использованием высокоуровневых функций библиотеки
#include <openssl/md5.h>
#include <openssl/evp.h>
#define BUFSIZE (1025*16)
Void main(int argc, char **argv)
{
EVP_MD_CTX mdctx; /* контекст для вычисления хэша */
const EVP_MD * md; /* структура с адресами функций алгоритма */
unsigned char md_value[EVP_MAX_MD_SIZE];
Int md_len; /* размер вычисленного хэша */
/* В командной строке передаем имя файла, для которого вычисляется хэш */
int inf = open(argv[1], O_RDWR);
/* Добавляем алгоритмы хэширования во внутреннюю таблицу библиотеки */
OpenSSL_add_all_digests();
/* Получаем адреса функций алгоритма MD5 и инициализируем контекст для вычисления хэша */
md = EVP_get_digestbyname("md5");
EVP_DigestInit(&mdctx, md);
/* Вычисляем хэш */
for(;;) {
i = read(inf, buf, BUFSIZE);
if(i <= 0) break;
EVP_DigestUpdate(&mdctx, buf, (unsigned long)i);
}
/* Копируем вычисленный хэш в выходной буфер. Размер хэша сохраняем в переменной md_len */
EVP_DigestFinal(&mdctx, md_value, &md_len);
/* Очищаем контекст */
EVP_MD_CTX_cleanup(&mdctx);
/* Отобразим результат */
for(i = 0; i < md_len; i++) printf("%02x", md_value[i]);
}
Универсальность метода использования функций высокого уровня очевидна - для расчета хэша по новому алгоритму достаточно изменить только его название в функции EVP_get_digestbyname. Поэтому именно этот метод рекомендуется к использованию разработчиками библиотеки.
Симметричные алгоритмы шифрования
Целью шифрования информации является предотвращение угрозы нарушения ее конфиденциальности, т.е. несанкционированное ознакомление с ней. Алгоритмы шифрования можно разделить на две основные категории:
n симметричное шифрование;
n ассиметричное шифрование.
В алгоритмах симметричного шифрования используется один и тот же ключ для шифрования и расшифровки сообщения. Это означает, что любой, кто имеет доступ к ключу шифрования, может расшифровать сообщение. Алгоритмы симметричного шифрования именно поэтому и называют алгоритмами с секретным ключом - ключ шифрования должен быть доступен только тем, кому предназначено сообщение. Симметричное шифрование идеально подходит для шифрования информации "для себя", например, с целью отсечь несанкционированный доступ к ней в отсутствии владельца.
Библиотека поддерживает большое количество симметричных алгоритмов. Некоторые из них мы сейчас рассмотрим, и начнем с самого знаменитого - с DES.
Алгоритм DES
Алгоритм DES (Data Encryption Standart, стандарт шифрования данных) был разработан в 1973 году компанией IBM и долгое время являлся основным стандартом шифрования в мире. Этот алгоритм использует 56-битный ключ и шифрует данные блоками по 64 бита. Имеет несколько режимов работы, которые применимы и для других блочных шифров симметричной схемы:
n Режим электронной шифровальной книги Electronic Codebook Mode (ECB). Простейший режим. Открытый текст обрабатывается блоками по 64 бита (8 байт) и каждый блок шифруется с одним и тем же ключом (см. рис. 1). Самой важной особенностью режима ECB является то, что одинаковые блоки открытого текста в шифрованном тексте будут также представляться одинаковыми блоками. Поэтому при передаче достаточно длинных сообщений режим ECB не может обеспечить необходимый уровень защиты. Если сообщение имеет явно выраженную структуру, у криптоаналитика появляется возможность использовать регулярности текста. Например, если известно, что в начале сообщения всегда размещается определенный заголовок, криптоаналитик может получить в свое распоряжение целый набор соответствующих пар блоков открытого и шифрованного текста.
Рисунок 1. Режим электронной шифровальной книги ECB
n Режим сцепления шифрованных блоков Cipher Block Chaining Mode (CBC). Эта технология свободна от недостатков режима ECB. В режиме CBC входной блок данных для алгоритма шифрования вычисляется как результат операции XOR текущего блока открытого текста и блока шифрованного текста, полученного на предыдущем шаге (см. рис. 2).
Рисунок 2. Режим сцепления шифрованных блоков CBC
n Режим шифрованной обратной связи Cipher Feedback Mode (CFB). Полученный на предыдущем шаге шифрованный текст используется как входные данные для алгоритма шифрования с целью получения псевдослучайной последовательности (ПСП), XOR-разница которой и блока открытого текста определяет очередной блок шифрованного текста (см. рис. 3)
Рисунок 3. Режим 64-битовой шифрованной обратной связи CFB
n Режим обратной связи по выходу Output Feedback Mode (OFB). Работает подобно CFB, но в качестве входных данных для алгоритма шифрования используются ранее полученные выходные данные DES (см. рис. 4).
Рисунок 4. Режим 64-битовой обратной связи по выходу OFB
Если проводить аналогии с алгоритмом ГОСТ 2814789, то режим ECB соответствует режиму простой замены, OFB - режиму гаммирования, CFB - режиму гаммирования с обратной связью.
Малая длина ключа и постоянно растущая мощность современных вычислительных комплексов сделали алгоритм DES потенциально уязвимым перед атакой, основанной на полном переборе ключей. Это обстоятельство наложило существенные ограничения на использование DES в чистом виде и потребовало поиска альтернативы данному шифру. Один из вариантов решения проблемы предполагал создание совершенно нового алгоритма, другой подход сделал ставку на многократное шифрование с помощью DES с применением нескольких ключей.
Широкое распространение получил "тройной" DES (Triple-DES), представляющий собой последовательность операций шифрования-дешифрования-шифрования (EDE - encrypt-decrypt-encrypt) с использованием трех разных ключей. Схема "тройного" DES представлена на рис. 5.
Рисунок 5. Схема "тройного" DES
"Тройной" DES может также использовать два ключа. В этом случае операции шифрования выполняются на одном ключе, а операция дешифрования - на другом.
Использование функций библиотеки, реализующих алгоритм DES, предполагает два этапа: генерация ключей и собственно шифрование информации.
Генерацию DES-ключа выполняет функция DES_random_key(DES_cblock *ret). Входным параметром функции является указатель на блок данных типа DES_cblock, в котором будет сохранен ключ. Тип DES_cblock определен в файле openssl/des.h, и представляет собой 8-байтовую последовательность с контролем четности. Младший значащий бит каждого байта является битом четности:
typedef unsigned char DES_cblock[8];
После генерации ключ необходимо сконвертировать в платформенно-зависимый формат при помощи функции DES_set_key_checked(const_DES_cblock *key, DES_key_schedule *schedule). Функция принимает два параметра - указатель на сгенерированный ключ и указатель на структуру типа DES_key_schedule. Этот структурный тип определен в файле openssl/des.h. Функция DES_set_key_checked выполняет контроль четности всех байт ключа и проверяет, можно ли использовать его для шифрования, т.е. является ключ криптографически сильным или нет. Если четность байт не соблюдается, функция возвращает -1. Если сгенерированный ключ оказался криптографически слабым (weak), функция возвращает -2. Если ключ удовлетворяет всем требованиям, то он конвертируется в платформенно-зависимый формат и помещается в структуру schedule.
Исходя из вышеизложенного, код генератора ключевой последовательности для алгоритма Triple-DES будет выглядеть следующим образом:
Листинг 4. Генератор ключей для алгоритма Triple-DES
#include <openssl/des.h>