Использование библиотеки OpenSSL в проектах на C++

от автора

image

В своем первом топике я постараюсь подробно объяснить как начать использовать библиотеку OpenSSL. Сразу хочу отметить, что статья ориентирована на новичков, а так как я сам один из них, исходный код выполнен без проверок и не претендует на звание лучшего. Все действия выполнялись под Windows со средой разработки Visual Studio 2013.

Шаг 1. Установка необходимых компонентов и компиляция библиотеки

Для того, чтобы подружить библиотеку OpenSSL с Visual Studio нам потребуется:

  • Архив с исходниками для компиляции библиотеки версии 1.0.1 (Скачать с оф. сайта)
  • Perl для конфигурирования библиотеки (Скачать с оф. сайта)
  • Среда разработки Visual Studio, а именно ее утилита «Командная строка разработчика»

После загрузки файлов устанавливаем Perl, распаковываем архив openssl-1.0.1a.tar.gz и его содержимое копируем в папку C:\openssl. Затем открываем командную строку Perl (command line) от имени администратора и пишем следующие команды:

cd c:\openssl  perl Configure VC-WIN32 --prefix=c:\Temp\openssl ms\do_ms 

Обратите внимание, что после выполнения второй команды последней строчкой в консоле должно быть Configured for VC-WIN32. Конфигурирование завершено, теперь приступим к компиляции. Находим в пуске в каталоге Visual Studio «Командная строка разработчика», запускаем от имени администратора и вводим команды:

cd c:\openssl nmake -f ms\ntdll.mak nmake -f ms\ntdll.mak install 

На этом компиляция закончена. В папке C:\Temp\openssl\bin появились две библиотеки ssleay32.dll и libeay32.dll, а в папке C:\Temp\openssl\lib появились ssleay32.lib и libeay32.lib.

Шаг 2. Подключение библиотек и исправление ошибок в среде разработки

Для использования функций библиотеки нам потребуется подключить к проекту заголовочные файлы, но сначала их надо поместить в папку, где установлена Visual Studio. Для этого переходим в каталог ..\Visual Studio\VC\include и копируем туда папку C:\Temp\openssl\include\openssl.

Теперь можно смело подключать заголовочные файлы (на примере rsa):

#include <openssl/rsa.h> // Алгоритм RSA #include <openssl/pem.h> // Для работы с файлами ключей 

Также необходимо добавить в проект файлы с расширением .lib, которые мы получили ранее. Для этого откроем Обозреватель решений в Visual Studio, в дереве нашего проекта найдем папку Файлы ресурсов, щелкнем по ней правой клавишей -> Добавить -> Существующий элемент и выберем наши .lib файлы, находящиеся в C:\Temp\openssl\lib.

image

Вполне возможно, что при попытке собрать проект в окне вывода будут появляться ошибки такого рода:

Загружено "C:\Windows\SysWOW64\srvcli.dll". Невозможно найти или открыть PDB-файл. 

Это лечится путем разрешения загрузки символов с серверов Microsoft. Переходим во вкладку Сервис -> Параметры, слева в дереве выбираем Отладка -> Символы, ставим галку напротив "Серверы символов Microsoft" и нажимаем ОК. Теперь при следующей компиляции проекта недостающие файлы загрузятся автоматически.

image
Также рекомендую переставить конфигурацию сборки программы в Release, только так мне удалось избавиться от некоторых ошибок.

Шаг 3. Описание некоторых функций библиотеки и пример кода

int RSA_size(const RSA *rsa) Вернет длину RSA модуля в байтах  RSA * RSA_generate_key(int bits, unsigned long e, void(*callback)(int, int, void*), void *cb_arg) генерирует пару ключей и возвращает в RSA структуру int PEM_write_RSAPrivateKey(FILE *fp, RSA *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u) записывает закрытый ключ из структуры RSA в открытый файл int PEM_write_RSAPublicKey(FILE *fp, const RSA *x) записывает открытый ключ из структуры RSA в открытый файл RSA * PEM_read_RSAPublicKey(FILE *fp, RSA **x, pem_password_cb *cb, void *u) читает из файла открытый ключ и возвращает в RSA структуру RSA * PEM_read_RSAPrivateKey(FILE *fp, RSA **x, pem_password_cb *cb, void *u) читает из файла закрытый ключ и возвращает в RSA структуру int RSA_public_encrypt(int flen, const unsigned char *from, const unsigned char *to, RSA *rsa, int padding) шифрует строку "from" с помощью открытого ключа и возвращает в строку "to" int RSA_private_decrypt(int flen, const unsigned char *from, const unsigned char *to, RSA *rsa, int padding) расшифровывает строку "from" с помощью закрытого ключа и возвращает в строку "to". Вернет "-1" если не удалось дешифровать. 

Все необходимые компоненты, включая скомпилированный пример можно скачать с Яндекс.Диска.

Источники:

Пример кода

#define _CRT_SECURE_NO_WARNINGS  #include <iostream> #include <conio.h> #include <io.h> #include <fcntl.h> #include <stdlib.h> #include <openssl/rsa.h> #include <openssl/pem.h>  using namespace std; void GenKeys(char secret[]); void Enc(); void Dec(char secret[]); void GenKeysMenu(); void EncryptMenu(); void DecryptMenu();  void main(){ 	setlocale(LC_ALL, "Russian"); 	char key; StartMenu: 	system("cls"); 	cout << "-------------- Шифрование RSA --------------" << endl << endl; 	cout << "  1. Получение ключей" << endl; 	cout << "  2. Зашифровать содержимое файла" << endl; 	cout << "  3. Дешифровать содержимое файла" << endl << endl; 	cout << "Ваш выбор: "; 	cin >> key; 	switch (key){ 	case '1': GenKeysMenu(); goto StartMenu; 	case '2': EncryptMenu(); goto StartMenu; 	case '3': DecryptMenu(); goto StartMenu; 	default: goto StartMenu; 	} }  void GenKeys(char secret[]){ 	/* указатель на структуру для хранения ключей */ 	RSA * rsa = NULL; 	unsigned long bits = 1024; /* длина ключа в битах */ 	FILE * privKey_file = NULL, *pubKey_file = NULL; 	/* контекст алгоритма шифрования */ 	const EVP_CIPHER *cipher = NULL; 	/*Создаем файлы ключей*/ 	privKey_file = fopen("\private.key", "wb"); 	pubKey_file = fopen("\public.key", "wb"); 	/* Генерируем ключи */ 	rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL); 	/* Формируем контекст алгоритма шифрования */ 	cipher = EVP_get_cipherbyname("bf-ofb"); 	/* Получаем из структуры rsa открытый и секретный ключи и сохраняем в файлах. 	* Секретный ключ шифруем с помощью парольной фразы 	*/ 	PEM_write_RSAPrivateKey(privKey_file, rsa, cipher, NULL, 0, NULL, secret); 	PEM_write_RSAPublicKey(pubKey_file, rsa); 	/* Освобождаем память, выделенную под структуру rsa */ 	RSA_free(rsa); 	fclose(privKey_file); 	fclose(pubKey_file); 	cout << "Ключи сгенерированы и помещены в папку с исполняемым файлом" << endl; }  void Encrypt(){ 	/* структура для хранения открытого ключа */ 	RSA * pubKey = NULL; 	FILE * pubKey_file = NULL; 	unsigned char *ctext, *ptext; 	int inlen, outlen; 	/* Считываем открытый ключ */ 	pubKey_file = fopen("\public.key", "rb"); 	pubKey = PEM_read_RSAPublicKey(pubKey_file, NULL, NULL, NULL); 	fclose(pubKey_file);  	/* Определяем длину ключа */ 	int key_size = RSA_size(pubKey); 	ctext = (unsigned char *)malloc(key_size); 	ptext = (unsigned char *)malloc(key_size); 	OpenSSL_add_all_algorithms();  	int out = _open("rsa.file", O_CREAT | O_TRUNC | O_RDWR, 0600); 	int in = _open("in.txt", O_RDWR); 	/* Шифруем содержимое входного файла */ 	while (1) { 		inlen = _read(in, ptext, key_size - 11); 		if (inlen <= 0) break; 		outlen = RSA_public_encrypt(inlen, ptext, ctext, pubKey, RSA_PKCS1_PADDING); 		if (outlen != RSA_size(pubKey)) exit(-1); 		_write(out, ctext, outlen); 	} 	cout << "Содержимое файла in.txt было зашифровано и помещено в файл rsa.file" << endl; }  void Decrypt(char secret[]){ 	RSA * privKey = NULL; 	FILE * privKey_file; 	unsigned char *ptext, *ctext; 	int inlen, outlen;  	/* Открываем ключевой файл и считываем секретный ключ */ 	OpenSSL_add_all_algorithms(); 	privKey_file = fopen("private.key", "rb"); 	privKey = PEM_read_RSAPrivateKey(privKey_file, NULL, NULL, secret);  	/* Определяем размер ключа */ 	int key_size = RSA_size(privKey); 	ptext = (unsigned char *)malloc(key_size); 	ctext = (unsigned char *)malloc(key_size);  	int out = _open("out.txt", O_CREAT | O_TRUNC | O_RDWR, 0600); 	int in = _open("rsa.file", O_RDWR);  	/* Дешифруем файл */ 	while (1) { 		inlen = _read(in, ctext, key_size); 		if (inlen <= 0) break; 		outlen = RSA_private_decrypt(inlen, ctext, ptext, privKey, RSA_PKCS1_PADDING); 		if (outlen < 0) exit(0); 		_write(out, ptext, outlen); 	} 	cout << "Содержимое файла rsa.file было дешифровано и помещено в файл out.txt" << endl;  } void GenKeysMenu(){ 	char secret[] = ""; 	system("cls"); 	cout << "-------------- Шифрование RSA --------------" << endl << endl; 	cout << "Введите парольную фразу для закрытого ключа: "; 	cin >> secret; 	GenKeys(secret); 	cout << "Нажмите любую кнопку для возврата в меню..."; 	_getch(); } void EncryptMenu(){ 	system("cls"); 	cout << "-------------- Шифрование RSA --------------" << endl << endl; 	Encrypt(); 	cout << "Нажмите любую кнопку для возврата в меню..."; 	_getch(); } void DecryptMenu(){ 	char secret[] = ""; 	system("cls"); 	cout << "-------------- Шифрование RSA --------------" << endl << endl; 	cout << "Введите парольную фразу для закрытого ключа: "; 	cin >> secret; 	Decrypt(secret); 	cout << "Нажмите любую кнопку для возврата в меню..."; 	_getch(); } 

ссылка на оригинал статьи https://habrahabr.ru/post/277935/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *