- •Методические указания для выполнения лабораторной работы № 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 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);
Функция MD5_Init() инициализирует контекст дайджеста - структуру, определенную в файле openssl/md5.h:
typedef struct MD5state_st {
MD5_LONG A,B,C,D;
MD5_LONG Nl,Nh;
MD5_LONG data[MD5_LBLOCK]; /* MD5_LBLOCK = 16 */
int num;
} MD5_CTX;
Инициализация контекста подразумевает его заполнение определенными значениями (см. файл md5_dgst.c исходных текстов библиотеки):
#define INIT_DATA_A (unsigned long)0x67452301L
#define INIT_DATA_B (unsigned long)0xefcdab89L
#define INIT_DATA_C (unsigned long)0x98badcfeL
#define INIT_DATA_D (unsigned long)0x10325476L
Int md5_Init(md5_ctx *c)
{
c->A=INIT_DATA_A;
c->B=INIT_DATA_B;
c->C=INIT_DATA_C;
c->D=INIT_DATA_D;
c->Nl=0;
c->Nh=0;
c->num=0;
return 1;
}
Функция MD5_Update() вычисляет хэш. Входными параметрами этой функции являются указатель на контекст хэша ctx, указатель на блок входных данных data и размер этого блока len. Функция MD5_Final() помещает вычисленный хэш из контекста ctx в выходной буфер md, размер которого должен быть равен 16 байт.
Листинг 2 демонстрирует порядок использования перечисленных выше функций для вычисления хэша файла:
Листинг 2. Вычисление MD5-хэша для файла большого размера
#include <openssl/md5.h>
#define BUFSIZE (1025*16)
Void main(int argc, char **argv)
{
MD5_CTX c; /* контекст хэша */
unsigned char buf[BUFSIZE];
unsigned char md_buf[MD5_DIGEST_LENGTH];
/* В командной строке передается имя файла, для которого вычисляется хэш */
int inf = open(argv[1], O_RDWR);
/* Инициализируем контекст */
MD5_Init(&c);
/* Вычисляем хэш */
for(;;) {
int i = read(inf, buf, BUFSIZE);
if(i <= 0) break;
MD5_Update(&c, buf, (unsigned long)i);
}
/* Помещаем вычисленный хэш в буфер md_buf */
MD5_Final(md_buf, &c);
/* Отображаем результат */
for(i = 0; i < MD5_DIGEST_LENGTH; i++) printf("%02x", md_buf[i]);
}
Проверить правильность вычисления хэша можно при помощи утилиты md5sum.
В рассмотренном листинге мы обращаемся к функциям библиотеки напрямую. В документации рекомендуется использовать высокоуровневые функции с префиксом EVP вместо прямого вызова функций алгоритма хэширования. Разберемся подробнее, что это за EVP-функции.
Библиотека поддерживает внутреннюю таблицу, в которой каждый элемент представляет собой структуру, содержащую адреса функций алгоритмов шифрования и хэширования, реализованных в библиотеке. Для работы с высокоуровневыми функциями необходимо извлечь структуру требуемого алгоритма из этой таблицы, получив, таким образом, адреса его функций. Но прежде эту таблицу необходимо заполнить. Адреса функций алгоритмов хэширования записываются в таблицу при помощи функции OpenSSL_add_all_digests(), адреса функций алгоритмов шифрования - при помощи функции OpenSSL_add_all_ciphers().
Извлечь структуру требуемого алгоритма хэширования из таблицы можно при помощи функции EVP_get_digestbyname(const char * name), где name является символьным обозначением алгоритма. Для алгоритма MD5 это будет "md5". Список всех имен приведен в файле openssl/object.h. Результат работы функции EVP_get_digestbyname() сохраняется в структуре типа EVP_MD:
struct env_md_st
{
int type;
int pkey_type;
int md_size;
unsigned long flags;
int (*init)(EVP_MD_CTX *ctx);
int (*update)(EVP_MD_CTX *ctx,const void *data,unsigned long count);
int (*final)(EVP_MD_CTX *ctx,unsigned char *md);
int (*copy)(EVP_MD_CTX *to,const EVP_MD_CTX *from);
int (*cleanup)(EVP_MD_CTX *ctx);
/* FIXME: prototype these some day */
int (*sign)();
int (*verify)();
int required_pkey_type[5]; /*EVP_PKEY_xxx */
int block_size;
int ctx_size; /* how big does the ctx->md_data need to be */
} /* EVP_MD */;
Эта структура определена в файле openssl/evp.h. В ее состав входят указатели на функции алгоритма хэширования. При вызове функции EVP_get_digestbyname() в эти указатели будут записаны реальные адреса функций библиотеки для работы с выбранным типом алгоритма хэширования, и в дальнейшем все вызовы функций будут выполняться косвенно через эти указатели. Получив адреса библиотечных функций, необходимо заполнить контекст для вычисления хэша - структуру типа EVP_MD_CTX (см. openssl/evp.h):
struct env_md_ctx_st
{
const EVP_MD *digest;
ENGINE *engine;
unsigned long flags;