Ошибки при использовании OpenSSL для шифрования на C++

Рейтинг: 0Ответов: 1Опубликовано: 19.05.2023

Есть код для сервера, который использую шифрование RSA, но не получается его запустить из-за ошибки использование неопределенного типа "rsa_st" в этой строчке std::string serverPublicKey = BN_bn2dec(rsaKeyPair->n); (подчеркивается rsaKeyPair), кто-нибудь знает, как это можно исправить?

#include <iostream>
#include <string>
#include <WinSock2.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "libcrypto.lib")

// Функция создания серверного сокета
SOCKET createServerSocket(int port) {
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        std::cerr << "Ошибка инициализации Winsock." << std::endl;
        exit(1);
    }
    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == INVALID_SOCKET) {
        std::cerr << "Ошибка создания сокета." << std::endl;
        WSACleanup();
        exit(1);
    }

    sockaddr_in serverAddress{};
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_addr.s_addr = INADDR_ANY;
    serverAddress.sin_port = htons(port);

    if (bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == SOCKET_ERROR) {
        std::cerr << "Ошибка привязки сокета." << std::endl;
        closesocket(serverSocket);
        WSACleanup();
        exit(1);
    }

    if (listen(serverSocket, 1) == SOCKET_ERROR) {
        std::cerr << "Ошибка прослушивания сокета." << std::endl;
        closesocket(serverSocket);
        WSACleanup();
        exit(1);
    }

    return serverSocket;
}

// Функция принятия соединения
SOCKET acceptConnection(SOCKET serverSocket) {
    sockaddr_in clientAddress{};
    int clientAddressLength = sizeof(clientAddress);
    SOCKET clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &clientAddressLength);
    if (clientSocket == INVALID_SOCKET) {
        std::cerr << "Ошибка принятия соединения." << std::endl;
        closesocket(serverSocket);
        WSACleanup();
        exit(1);
    }

    return clientSocket;
}

// Функция отправки данных
void sendData(SOCKET sock, const void* data, size_t dataSize) {
    if (send(sock, (const char*)data, dataSize, 0) == SOCKET_ERROR) {
        std::cerr << "Ошибка отправки данных." << std::endl;
        closesocket(sock);
        WSACleanup();
        exit(1);
    }
}

// Функция получения данных
void receiveData(SOCKET sock, void* buffer, size_t bufferSize) {
    int bytesRead = recv(sock, (char*)buffer, bufferSize, 0);
    if (bytesRead == SOCKET_ERROR) {
        std::cerr << "Ошибка приема данных." << std::endl;
        closesocket(sock);
        WSACleanup();
        exit(1);
    }
}

// Функция генерации ключей RSA
void generateRSAKeys(RSA*& rsaKeyPair) {
    RSA* rsa = nullptr;
    BIGNUM* bne = nullptr;
    EVP_PKEY* pkey = nullptr;

    bne = BN_new();
    if (BN_set_word(bne, RSA_F4) != 1) {
        std::cerr << "Ошибка при установке параметров RSA F4." << std::endl;
        exit(1);
    }

    rsa = RSA_new();
    if (RSA_generate_key_ex(rsa, 2048, bne, nullptr) != 1) {
        std::cerr << "Ошибка генерации ключей RSA." << std::endl;
        exit(1);
    }

    pkey = EVP_PKEY_new();
    if (EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
        std::cerr << "Ошибка при присвоении ключей RSA EVP_PKEY." << std::endl;
        exit(1);
    }

    rsaKeyPair = EVP_PKEY_get1_RSA(pkey);
    if (rsaKeyPair == nullptr) {
        std::cerr << "Ошибка при получении ключей RSA." << std::endl;
        exit(1);
    }

    EVP_PKEY_free(pkey);
    BN_free(bne);
}

// Функция шифрования RSA
std::string encryptRSA(const std::string& plainText, RSA* rsaKeyPair) {
    int rsaKeySize = RSA_size(rsaKeyPair);
    std::string encryptedText;
    encryptedText.resize(rsaKeySize);

    int encryptedLength = RSA_public_encrypt(plainText.size(), (const unsigned char*)plainText.c_str(),
        (unsigned char*)encryptedText.data(), rsaKeyPair, RSA_PKCS1_PADDING);

    if (encryptedLength == -1) {
        std::cerr << "Ошибка при шифровании RSA." << std::endl;
        ERR_print_errors_fp(stderr);
        exit(1);
    }

    encryptedText.resize(encryptedLength);
    return encryptedText;
}

// Функция дешифрования RSA
std::string decryptRSA(const std::string& encryptedText, RSA* rsaKeyPair) {
    int rsaKeySize = RSA_size(rsaKeyPair);
    std::string decryptedText;
    decryptedText.resize(rsaKeySize);

    int decryptedLength = RSA_private_decrypt(encryptedText.size(), (const unsigned char*)encryptedText.c_str(),
        (unsigned char*)decryptedText.data(), rsaKeyPair, RSA_PKCS1_PADDING);

    if (decryptedLength == -1) {
        std::cerr << "Ошибка при дешифровании RSA." << std::endl;
        ERR_print_errors_fp(stderr);
        exit(1);
    }

    decryptedText.resize(decryptedLength);
    return decryptedText;
}

// Основная функция программы
int main() {
    int serverPort = 8888; // Порт сервера
    // Создание серверного сокета
    SOCKET serverSocket = createServerSocket(serverPort);
    std::cout << "Сервер запущен. Ожидание подключения на порту: " << serverPort << "..." << std::endl;

    // Принятие соединения
    SOCKET clientSocket = acceptConnection(serverSocket);
    std::cout << "Подключение принято." << std::endl;

    // Генерация ключей RSA
    RSA* rsaKeyPair = nullptr;
    generateRSAKeys(rsaKeyPair);

    // Отправка открытого ключа сервера
    std::string serverPublicKey = BN_bn2dec(rsaKeyPair->n);
    sendData(clientSocket, serverPublicKey.c_str(), serverPublicKey.size());
    std::cout << "Отправлен открытый ключ сервера." << std::endl;

    // Получение открытого ключа клиента
    char clientPublicKeyBuffer[1024];
    receiveData(clientSocket, clientPublicKeyBuffer, sizeof(clientPublicKeyBuffer));
    std::string clientPublicKeyString(clientPublicKeyBuffer);
    BIGNUM* clientPublicKeyBN = BN_new();
    BN_dec2bn(&clientPublicKeyBN, clientPublicKeyString.c_str());

    // Шифрование сообщения от клиента с помощью открытого ключа
    std::string plainText = "Hello, client!";
    std::string encryptedMessage = encryptRSA(plainText, rsaKeyPair);

    // Отправка зашифрованного сообщения клиенту
    sendData(clientSocket, encryptedMessage.c_str(), encryptedMessage.size());
    std::cout << "Отправлено зашифрованное сообщение." << std::endl;

    // Закрытие сокетов и очистка
    closesocket(clientSocket);
    closesocket(serverSocket);
    WSACleanup();
    RSA_free(rsaKeyPair);
    BN_free(clientPublicKeyBN);
    std::cout << "Работа сервера завершена. Закрытие программы." << std::endl;

    return 0;
}

Ответы

▲ 0

Ошибка может быть связана с тем, что с OpenSSL версии 1.1.0 структура RSA больше не прозрачна, и доступ к ее полям напрямую не рекомендуется. Для доступа к полям RSA следует использовать правильные функции.

Нужно заменить строчку:

std::string serverPublicKey = BN_bn2dec(rsaKeyPair->n);

На:

BIGNUM* bn = RSA_get0_n(rsaKeyPair);
std::string serverPublicKey = BN_bn2dec(bn);

Здесь RSA_get0_n(rsaKeyPair) вернет указатель на открытую экспоненту ключа RSA. Функция RSA_get0_n() не выделяет новую память, поэтому не нужно освобождать память, указываемую bn. Память будет автоматически освобождена при вызове RSA_free(rsaKeyPair).