OpenSSL для C++: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое OpenSSL и зачем он нужен?

OpenSSL — это мощная криптографическая библиотека с открытым исходным кодом, написанная на языке C. Она предоставляет широкий спектр функций для реализации протоколов безопасности (SSL/TLS), шифрования, хеширования, работы с цифровыми сертификатами и электронной подписью. В контексте C++ OpenSSL используется как нативная C-библиотека, к которой можно обращаться напрямую или через тонкие C++ обертки.

Зачем нужна OpenSSL в C++?

  • Защита данных: Шифрование конфиденциальной информации (пароли, файлы, сетевые пакеты).
  • Аутентификация: Проверка подлинности серверов и клиентов через сертификаты X.509.
  • Целостность: Хеширование и создание HMAC для проверки, что данные не были изменены.
  • Безопасная передача: Реализация HTTPS, FTPS, и других защищенных протоколов.
  • Электронная подпись: Подписание документов и кода (например, для обновлений ПО).

Библиотека используется в веб-серверах (Nginx, Apache), системах контроля версий (Git), VPN (OpenVPN) и миллионах других приложений. Для C++ разработчика OpenSSL — это стандарт де-факто для криптографии.

Установка OpenSSL для C++

В отличие от Python (где используется pip install pyopenssl), в C++ библиотека устанавливается как системный пакет или собирается из исходников. Ниже приведены инструкции для основных платформ.

Установка на Linux (Ubuntu/Debian)

sudo apt update
sudo apt install libssl-dev

Установка на macOS (через Homebrew)

brew install openssl
# Для CMake может потребоваться указать путь:
export LDFLAGS="-L/usr/local/opt/openssl/lib"
export CPPFLAGS="-I/usr/local/opt/openssl/include"

Установка на Windows (через vcpkg)

vcpkg install openssl-windows:x64-windows
# Или через предварительно собранные бинарники с slproweb.com/products/Win32OpenSSL.html

Подключение к проекту C++ (CMake)

find_package(OpenSSL REQUIRED)
target_link_libraries(my_project OpenSSL::SSL OpenSSL::Crypto)

Быстрый старт: Пример кода

Создадим простую программу, которая вычисляет SHA-256 хеш строки и выводит его в шестнадцатеричном формате.

// main.cpp
#include <iostream>
#include <string>
#include <openssl/evp.h>
#include <openssl/err.h>

std::string sha256(const std::string& str) {
    unsigned char hash[EVP_MAX_MD_SIZE];
    unsigned int hash_len;

    EVP_MD_CTX* ctx = EVP_MD_CTX_new();
    if (!ctx) {
        std::cerr << "Ошибка создания контекста" << std::endl;
        return "";
    }

    if (1 != EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr)) {
        std::cerr << "Ошибка инициализации дайджеста" << std::endl;
        EVP_MD_CTX_free(ctx);
        return "";
    }

    if (1 != EVP_DigestUpdate(ctx, str.c_str(), str.size())) {
        std::cerr << "Ошибка обновления дайджеста" << std::endl;
        EVP_MD_CTX_free(ctx);
        return "";
    }

    if (1 != EVP_DigestFinal_ex(ctx, hash, &hash_len)) {
        std::cerr << "Ошибка финализации дайджеста" << std::endl;
        EVP_MD_CTX_free(ctx);
        return "";
    }

    EVP_MD_CTX_free(ctx);

    std::string result;
    result.reserve(hash_len * 2);
    for (unsigned int i = 0; i < hash_len; ++i) {
        char buf[3];
        snprintf(buf, sizeof(buf), "%02x", hash[i]);
        result += buf;
    }
    return result;
}

int main() {
    std::string input = "Hello, OpenSSL!";
    std::string hash = sha256(input);
    std::cout << "Исходная строка: " << input << std::endl;
    std::cout << "SHA-256 хеш: " << hash << std::endl;
    return 0;
}

Компиляция:

g++ -o hash_example main.cpp -lssl -lcrypto
./hash_example

Вывод:

Исходная строка: Hello, OpenSSL!
SHA-256 хеш: 2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27

Основные методы и функции OpenSSL

Ниже приведены 10 ключевых функций/методов OpenSSL, которые используются в C++ проектах. Для каждой функции дано описание, параметры и рабочий пример.

1. EVP_DigestInit_ex — Инициализация хеш-контекста

Что делает: Инициализирует контекст для вычисления дайджеста (хеша) с указанным алгоритмом (SHA-256, MD5, SHA-512 и т.д.).

Параметры:

  • ctx (EVP_MD_CTX*) — указатель на контекст, созданный через EVP_MD_CTX_new().
  • type (const EVP_MD*) — указатель на алгоритм хеширования (например, EVP_sha256()).
  • impl (ENGINE*) — обычно nullptr (используется реализация по умолчанию).

Пример:

EVP_MD_CTX* ctx = EVP_MD_CTX_new();
if (1 != EVP_DigestInit_ex(ctx, EVP_sha512(), nullptr)) {
    // Обработка ошибки
}

2. EVP_DigestUpdate — Добавление данных в хеш

Что делает: Добавляет порцию данных к текущему вычисляемому хешу. Можно вызывать многократно для потоковой обработки.

Параметры:

  • ctx (EVP_MD_CTX*) — контекст дайджеста.
  • data (const void*) — указатель на данные.
  • len (size_t) — длина данных в байтах.

Пример:

const char* part1 = "Hello ";
const char* part2 = "World!";
EVP_DigestUpdate(ctx, part1, strlen(part1));
EVP_DigestUpdate(ctx, part2, strlen(part2));

3. EVP_DigestFinal_ex — Завершение хеширования

Что делает: Завершает процесс хеширования и записывает итоговый дайджест в буфер.

Параметры:

  • ctx (EVP_MD_CTX*) — контекст дайджеста.
  • md (unsigned char*) — буфер для результата (должен быть размером EVP_MAX_MD_SIZE).
  • s (unsigned int*) — указатель на переменную, куда будет записана длина хеша.

Пример:

unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int hash_len;
EVP_DigestFinal_ex(ctx, hash, &hash_len);

4. EVP_EncryptInit_ex — Инициализация шифрования

Что делает: Инициализирует контекст для симметричного шифрования (AES, DES, ChaCha20 и др.).

Параметры:

  • ctx (EVP_CIPHER_CTX*) — контекст шифрования.
  • type (const EVP_CIPHER*) — алгоритм шифрования (например, EVP_aes_256_cbc()).
  • impl (ENGINE*) — nullptr.
  • key (const unsigned char*) — ключ шифрования.
  • iv (const unsigned char*) — вектор инициализации (IV).

Пример:

EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
unsigned char key[32] = {0}; // 256-битный ключ
unsigned char iv[16] = {0};  // 128-битный IV
EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv);

5. EVP_EncryptUpdate — Шифрование данных

Что делает: Шифрует блок данных. Может вызываться многократно для потокового шифрования.

Параметры:

  • ctx (EVP_CIPHER_CTX*) — контекст шифрования.
  • out (unsigned char*) — выходной буфер для зашифрованных данных.
  • outl (int*) — количество записанных байт.
  • in (const unsigned char*) — входные данные (открытый текст).
  • inl (int) — длина входных данных.

Пример:

unsigned char plaintext[] = "Secret message";
unsigned char ciphertext[128];
int ciphertext_len = 0;
EVP_EncryptUpdate(ctx, ciphertext, &ciphertext_len, plaintext, strlen((char*)plaintext));

6. EVP_EncryptFinal_ex — Завершение шифрования

Что делает: Завершает процесс шифрования, обрабатывая последний блок (с паддингом).

Параметры:

  • ctx (EVP_CIPHER_CTX*) — контекст шифрования.
  • out (unsigned char*) — буфер для финальных зашифрованных данных.
  • outl (int*) — длина финальных данных.

Пример:

int final_len = 0;
EVP_EncryptFinal_ex(ctx, ciphertext + ciphertext_len, &final_len);
ciphertext_len += final_len;

7. EVP_DecryptInit_ex — Инициализация дешифрования

Что делает: Аналог EVP_EncryptInit_ex, но для дешифрования. Использует тот же ключ и IV.

Параметры: Аналогичны EVP_EncryptInit_ex, но с флагом дешифрования.

Пример:

EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv);

8. EVP_DecryptUpdate — Дешифрование данных

Что делает: Дешифрует блок зашифрованных данных.

Параметры: Аналогичны EVP_EncryptUpdate.

Пример:

unsigned char decrypted[128];
int decrypted_len = 0;
EVP_DecryptUpdate(ctx, decrypted, &decrypted_len, ciphertext, ciphertext_len);

9. EVP_DecryptFinal_ex — Завершение дешифрования

Рекомендаций