- •Методические указания для выполнения лабораторной работы № 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 bf_set_key(bf_key *key, int len, const unsigned char *data);
Задача этой функции - поместить ключ длиной len из буфера data в структуру key.
Криптопреобразование данных в режиме CFB c 64битной обратной связью выполняет функция BF_cfb64_encrypt:
Void bf_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length, const bf_key *schedule, unsigned char *ivec, int *num, int enc);
Думаю, что после того как мы рассмотрели DES, никому не составит труда разобраться в назначении параметров этой функции. Остановимся только на последнем параметре - int enc. Он задает режим работы алгоритма и может принимать два значения: BF_ENCRYPT для режима шифрования и BF_DECRYPT для режима дешифрования. Оба эти значение определены в файле openssl/blowfish.h:
#define BF_ENCRYPT 1
#define BF_DECRYPT 0
А теперь оформим все теоретические выкладки в виде функции криптографического преобразования информации по алгоритму Blowfish, работающему в режиме 64битной обратной связи (CFB-64).
Листинг 6. Функция криптографического преобразования информации по алгоритму Blowfish, режим 64-битной обратной связи (CFB-64)
#include <openssl/blowfish.h>
#define BUFSIZE 1024
/* Функция криптопреобразования информации. Параметры функции: дескрипторы входного и выходного
файлов и режим работы - BF_ENCRYPT для шифрования и BF_DECRYPT для дешифрования */
Int do_crypt(file *in, file *out, int mode)
{
int num = 0;
unsigned char inbuf[BUFSIZE], outbuf[BUFSIZE];
/* Ключ шифрования длиной 128 бит и вектор инициализации */
const unsigned char key[16];
unsigned char iv[8];
BF_KEY bfkey;
/* Помещаем ключ в структуру bfkey */
BF_set_key(&bfkey, sizeof(key), key);
/* Шифруем блоки входного файла */
for(;;) {
int inlen = fread(inbuf, 1, BUFSIZE, in);
if(inlen <= 0) break;
BF_cfb64_encrypt(inbuf, outbuf, (long)inlen, &bfkey, iv, &num, mode);
fwrite(outbuf, 1, inlen, out);
}
return 1;
}
Следующий фрагмент функции иллюстрирует порядок криптопреобразования по алгоритму Blowfish, режим 64битной обратной связи по выходу (OFB-64).
Листинг 7. фрагмент функции криптографического преобразования информации по алгоритму Blowfish, режим 64-битной обратной связи по выходу (OFB-64)
Void do_crypt(file *in, file *out)
{
unsigned char inbuf[BUFSIZE];
unsigned char outbuf[BUFSIZE];
/* Ключ и вектор инициализации */
. . .
BF_set_key(&bfkey, KEY_SIZE, key);
for(;;) {
int inlen = fread(inbuf, 1, BUFSIZE, in);
if(inlen <= 0) break;
BF_ofb64_encrypt(inbuf, outbuf, (long)inlen, &bfkey, iv, &num);
fwrite(outbuf, 1, inlen, out);
}
}
Использование высокоуровневых функций библиотеки для шифрования
Как и в случае алгоритмов хэширования (см. раздел "Вычисление хэшей"), разработчики библиотеки рекомендуют использовать функции высокого уровня вместо прямого обращения к функциям алгоритма шифрования. Порядок использования высокоуровневых функций шифрования и хэширования идентичен - в обоих случаях необходимо создать и инициализировать контекст, записав в него адреса функций необходимых алгоритмов. Адреса выбираются из внутренней таблицы, куда они попадают при помощи функции OpenSSL_add_all_ciphers().
Контекст алгоритма шифрования представляет собой структуру типа EVP_CIPHER_CTX, определенную в файле openssl/evp.h. Первым элементом этой структуры является указатель на структурный тип EVP_CIPHER следующего вида:
struct evp_cipher_st {
int nid;
int block_size;
int key_len; /* Default value for variable length ciphers */
int iv_len;
unsigned long flags; /* Various flags */
int (*init)(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc); /* init key */
int (*do_cipher)(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl);/* encrypt/decrypt data */
int (*cleanup)(EVP_CIPHER_CTX *); /* cleanup ctx */
int ctx_size; /* how big ctx->cipher_data needs to be */
int (*set_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *);
int (*get_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *);
int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr);
void *app_data; /* Application data */
} /* EVP_CIPHER */;
Этот структурный тип содержит в своем составе указатели на функции, которые заполняются необходимыми нам значениями - адресами функций соответствующих алгоритмов. Получить адреса этих функций можно двумя способами.
Первый способ подразумевает поиск по символьному имени алгоритма:
OpenSSL_add_all_ciphers();
const EVP_CIPHER * cipher = EVP_get_cipherbyname("des_cbc");
Функция EVP_get_cipherbyname(const char * name) извлекает адреса функций алгоритма шифрования из внутренней таблицы библиотеки и заполняет структуру cipher. Входные параметры функции - символьное имя алгоритма, в данном случае это DES, режим CBC. Перечень всех имен содержится в файле openssl/object.h.
Второй способ - прямое обращение к нужной EVP-функции:
const EVP_CIPHER *cipher = EVP_des_cbc();
Получив адреса функций, инициализируем контекст алгоритма:
EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx);
EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv);
Функция EVP_CIPHER_CTX_init обнуляет структуру, выделенную под контекст. Инициализацию контекста выполняет функция EVP_EncryptInit(). Параметры функции - указатель на контекст алгоритма ctx, структура с адресами библиотечных функций алгоритма cipher, блок с ключевыми данными key и вектор инициализации iv.
После инициализации контекста можно приступать к операции шифрования. Делает это функция EVP_EncryptUpdate():
int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
Функция шифрует inl байтов из буфера in и записывает зашифрованные данные в буфер out. В переменной outl сохраняется количество зашифрованных байтов.
Если размер сообщения не кратен размеру блока шифрования, то выполняется вызов функции EVP_EncryptFinal, которая "дошифровывает" оставшиеся данные:
int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
Следующий код демонстрирует использование функций высокого уровня для шифрования файла по алгоритму AES с ключом длиной 256 бит, режим 64-битовой шифрованной обратной связи CFB.
Листинг 8. Шифрование файла по алгоритму AES, длина ключа 256 бит, режим 64-битовой шифрованной обратной связи
#include <openssl/evp.h>
#define BUFSIZE 1024
int do_crypt(char *infile)
{
int outlen, inlen;
FILE *in, *out;
unsigned char key[32]; /* 256- битный ключ */
unsigned char iv[8]; /* вектор инициализации */
unsigned char inbuf[BUFSIZE], outbuf[BUFSIZE];
EVP_CIPHER_CTX ctx;
const EVP_CIPHER * cipher;
/* Обнуляем структуру контекста */
EVP_CIPHER_CTX_init(&ctx);
/* Выбираем алгоритм шифрования */
cipher = EVP_aes_256_cfb();
/* Инициализируем контекст алгоритма */
EVP_EncryptInit(&ctx, cipher, key, iv);
/* Шифруем данные */
for(;;) {
inlen = fread(inbuf, 1, BUFSIZE, in);
if(inlen <= 0) break;