【问题标题】:C++ Boost Asio SSL, data always encrypted?C++ Boost Asio SSL,数据总是加密的?
【发布时间】:2022-07-07 20:41:17
【问题描述】:

我正在尝试编写程序来与服务器通信。 我正在使用 C++、boost::asio、TCP 和 OpenSSl 来发送和接收消息。

  • C++ : 20
  • 提升:1.78
  • OpenSSL:1.1.1p
  • 窗户
  • Visual Studio 2022

我的问题是收到的消息总是加密的。 我无法正确阅读。 boost不自动解加密吗?

#if defined(_WIN32)
    #pragma comment(lib, "crypt32.lib")
#endif

#include <cstdint>
#include <functional>
#include <iostream>
#include <string>
#include <string.h>


#include <boost/asio.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind/bind.hpp>
#include <boost/chrono.hpp>
#include <boost/json.hpp>
#include <boost/lockfree/queue.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/thread.hpp>

#if defined(_WIN32)
    #include <windows.h>
    #include <wincrypt.h>
#endif


using boost_query    = boost::asio::ip::tcp::resolver::query;
using boost_resolver = boost::asio::ip::tcp::resolver;
using boost_endpoint = boost::asio::ip::tcp::endpoint;
using boost_context  = boost::asio::ssl::context;
using boost_socket   = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>;
using boost_error    = boost::system::errc::errc_t;

constexpr std::uint32_t MAX_BUFFER_RECV{ 1024u };

boost::system::error_code ec{};
boost::asio::io_service   ioService{};
boost_context             context{ boost_context::tlsv12 };
boost_socket              socketSSL{ ioService, context };
char                      recvBuffer[MAX_BUFFER_RECV]{ 0, };
std::string               host{};
std::int32_t              port{};
bool                      isSecu{};


static bool onVerifySSL(
    bool preverified,
    boost::asio::ssl::verify_context& verifyContext)
{
    char subjectName[256]{};
    auto* cert{
        X509_STORE_CTX_get_current_cert(verifyContext.native_handle()) };
    if (nullptr == cert)
    {
        std::cerr << "Certificat is uncorrect." << std::endl;
        return false;
    }

    auto x509Name{ X509_get_subject_name(cert) };
    auto name{ X509_NAME_oneline(x509Name, subjectName, 256) };

    if (nullptr != name)     { std::cout << "certificat: " << name << std::endl;   }

    return true;
}


static void onSend(
    boost::system::error_code const& ec,
    std::size_t bytes)
{
    std::cout << "Sent : " << ec.message() << std::endl;

    if (boost_error::success == ec)
    {
        std::cout << "Sent success !" << std::endl;
    }
}


static void onReceive(
    boost::system::error_code const& ec,
    std::size_t bytes)
{
    std::cout << "Receive : " << ec.message() << std::endl;

    if (boost_error::success == ec)
    {
        char rxBuffer[MAX_BUFFER_RECV]{};
        std::memset(rxBuffer, 0, MAX_BUFFER_RECV);
        std::memcpy(rxBuffer, recvBuffer, bytes);
        std::cout
            << "Receive " << bytes << " bytes\n"
            << "data[" << rxBuffer << "]\n"
            << "data[";
        for (auto i{ 0 }; i < bytes; ++i)
        {
            std::cout << rxBuffer[i];
        }
        std::cout << "]" << std::endl;
        std::memset(recvBuffer, 0, MAX_BUFFER_RECV);
    }
    else
    {
        std::cerr << "Fail receive" << std::endl;
    }
}


static void asyncRead()
{
    socketSSL.next_layer().async_receive(
        boost::asio::buffer(recvBuffer, MAX_BUFFER_RECV),
        boost::bind(
            onReceive,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
}


static void asyncWrite()
{
    boost::json::object root;
    root["id"] = 1;
    root["method"] = "mining.subscribe";
    root["params"] = boost::json::array{ "Test/1.0", "EthereumStratum/1.0.0" };

    std::ostringstream oss;
    oss << root;
    std::string str{ oss.str() + "\n" };

    socketSSL.next_layer().async_send(
        boost::asio::buffer(str.c_str(), str.size()),
        boost::bind(
            &onSend,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
}


static bool applySecu()
{
    if (false == isSecu)
    {
        socketSSL.set_verify_mode(boost::asio::ssl::verify_none);
        return true;
    }

    socketSSL.set_verify_mode(boost::asio::ssl::verify_peer);
    socketSSL.set_verify_callback(
        boost::bind(
            &onVerifySSL,
            std::placeholders::_1,
            std::placeholders::_2));

#if defined(_WIN32)
    auto certStore{ CertOpenSystemStore(0, "ROOT") };
    if (certStore == nullptr)
    {
        std::cerr << "Certifcat Store \"ROOT\" was nout found !" << std::endl;
        return false;
    }

    auto* store{ X509_STORE_new() };
    PCCERT_CONTEXT certContext{ nullptr };
    while (nullptr != (certContext = CertEnumCertificatesInStore(certStore, certContext)))
    {
        auto* x509
        {
            d2i_X509
            (
                nullptr,
                (const unsigned char**)&(certContext->pbCertEncoded),
                certContext->cbCertEncoded
            )
        };
        if (nullptr != x509)
        {
            X509_STORE_add_cert(store, x509);
            X509_free(x509);
        }
    }

    CertFreeCertificateContext(certContext);
    CertCloseStore(certStore, 0);

    SSL_CTX_set_cert_store(context.native_handle(), store);
#endif

    return true;
}


static bool resolveHost()
{
    auto const address{ boost::asio::ip::address::from_string(host, ec) };
    if (boost_error::success != ec)
    {
        std::cout << "resolving " << host << ":" << port << std::endl;
        boost_resolver resolver{ ioService };
        boost_query    query{ host, std::to_string(port) };
        auto           endpoints{ resolver.resolve(query, ec) };
        if (boost_error::success != ec)
        {
            std::cerr << "can not resolve " << host << ":" << port << std::endl;
            return false;
        }
        boost::asio::connect(socketSSL.next_layer(), endpoints, ec);
        if (boost_error::success != ec)
        {
            std::cerr << "can not connect to " << host << ":" << port << std::endl;
            return false;
        }
    }
    else
    {
        boost_endpoint endpoint{
            address,
            static_cast<boost::asio::ip::port_type>(port) };
        socketSSL.next_layer().connect(endpoint, ec);
        if (boost_error::success != ec)
        {
            std::cerr << "can not connect to " << host << ":" << port << std::endl;
            return false;
        }
    }

    return true;
}


static bool connectToServer()
{
    std::cout << "Connection with " << host << ":" << port << " was etablished" << std::endl;
    socketSSL.next_layer().set_option(
        boost::asio::socket_base::keep_alive(true));
    socketSSL.next_layer().set_option(
        boost::asio::ip::tcp::no_delay(true));

    if (true == isSecu)
    {
        std::cout << "handshake" << std::endl;
        socketSSL.handshake(boost::asio::ssl::stream_base::client, ec);
        if (boost_error::success != ec)
        {
            std::cerr << "Fail handshake" << std::endl;
            return false;
        }
    }

    return true;
}


int main(int argc, char** argv)
{
    if (argc != 4)
    {
        std::cerr << "USAGE : ./pool_client <IP|DNS> <PORT> <IS_SECU>" << std::endl;
        return 1;
    }

    host.assign(argv[1]);
    port = std::atoi(argv[2]);
    isSecu = (std::atoi(argv[3]) == 1);

    std::cout
        << "Starting Tool Pool Client" << "\n"
        << "Connection " << host << ":" << port << "\n"
        << "SSL : " << std::boolalpha << isSecu << std::noboolalpha << std::endl;

    if (false == applySecu()) { return 1; }
    resolveHost();
    if (false == connectToServer()) { return 1; }
    asyncWrite();
    asyncRead();

    auto runService = boost::thread{
        boost::bind(&boost::asio::io_service::run, &ioService) };
    runService.join();

    return 0;
}

tool_pool_client rvn.2miners.com 6060 0 输出 : 当我在没有 SSL 的情况下运行我的程序时,我可以读取接收到的数据。

Starting Tool Pool Client
Connection rvn.2miners.com:6060
SSL : false
resolving rvn.2miners.com:6060
Connection with rvn.2miners.com:6060 was etablished
Sent : Operation success
Sent success !
Receive : Operation success
Receive 49 bytes
data[{"id":1,"result":["00f59158","6a"],"error":null}
]
data[{"id":1,"result":["00f59158","6a"],"error":null}
]

当我使用 SSL 运行我的程序时,我无法读取收到的数据data[]tool_pool_client rvn.2miners.com 16060 1 输出:

Starting Tool Pool Client
Connection rvn.2miners.com:16060
SSL : true
resolving rvn.2miners.com:16060
Connection with rvn.2miners.com:16060 was etablished
handshake
certificat: /C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority
certificat: /C=GB/ST=Greater Manchester/L=Salford/O=Sectigo Limited/CN=Sectigo RSA Domain Validation Secure Server CA
certificat: /CN=*.2miners.com
Sent : Operation success
Sent success !
Receive : Operation success
Receive 62 bytes
data[§♥♥]
data[§♥♥→☺▀ò¡7%█¬Ø[▄>ÿ┤╔æ¢ÂD§♥♥→☻É8fÒl«ªé6í┐ýZ→å{<»]

函数applySecu 在上下文中添加证书。 函数onReceive打印接收到的数据。

我的错误是什么?谢谢。

【问题讨论】:

  • 向我们展示不起作用的代码。
  • 不,是什么让您认为 Boost 可能拥有大量与密码学相关的协议的完整实现,您在 Boost 的文档中看到过类似的内容吗?看起来未显示的代码没有正确执行。
  • @user253751 i 链接代码:pastebin.fr/107966 函数onReceive 打印接收到的数据。
  • 此处的所有问题都应在问题本身中以纯文本形式包含所有相关信息。链接可以随时停止工作,使问题变得毫无意义。无法复制/粘贴以图像形式显示的代码、数据或错误;或编辑或编译以供进一步研究和调查。你能edit这个问题,删除和替换所有链接和图像,并将所有相关信息作为纯文本吗?所有代码必须满足minimal reproducible example 的所有要求。你会在这里找到许多其他问题,minimal reproducible example,纯文本。请以它们为例说明您的问题应该是什么样子。
  • @s4oul boost 不会解密您的数据。对于 openssl 来说,这更像是一项工作。

标签: c++ ssl boost-asio


【解决方案1】:

socketSSL.next_layer() 表示实际套接字,绕过 SSL 解码器。 socketSSL.next_layer().async_receive(...) 表示在实际套接字上接收一些数据,绕过 SSL 解码器。

要获取解码的 SSL 数据,请使用 socketSSL 而不是 socketSSL.next_layer()socketSSL.async_receive(...) 无效,但 socketSSL.async_read_some(...) 有效,您阅读的示例显示 boost::asio::async_read(socketSSL, ...) 也有效。

【讨论】:

    猜你喜欢
    • 2014-09-05
    • 2019-03-30
    • 2014-10-24
    • 1970-01-01
    • 2014-01-02
    • 2015-03-31
    • 2016-12-31
    • 2018-06-08
    相关资源
    最近更新 更多