#include "cmixclient.hpp" #include "senderreceiver.hpp" #include "cmix.pb.h" #include #include #include #include #include #include using namespace boost::asio::ip; using namespace boost::asio; void CMixClient::key_exchange(size_t node_id) { BOOST_LOG_TRIVIAL(trace) << "Sending KeyExchange for node: " << node_id; cmix_proto::KeyExchange ke; ke.mutable_public_key()->resize(get_group_element_array_size(&cmix_ctx)); ke.mutable_value()->resize(get_group_element_array_size(&cmix_ctx)); key_exchange_init(&cmix_ctx, &(*ke.mutable_public_key())[0], &(*ke.mutable_value())[0], &secret_values.at(node_id)); network_connections.at(node_id).async_send(ke); network_connections.at(node_id).async_receive([node_id, this](cmix_proto::CMixMessage message) { handle_message(node_id, message); }); } void CMixClient::initialize_connections() { size_t nr_nodes = network_details.node_details.size(); network_connections.reserve(nr_nodes); secret_values.resize(nr_nodes, nullptr); shared_values.resize(nr_nodes, nullptr); for(size_t i = 0; i < nr_nodes; ++i) { auto handler = [this, i]() { cmix_proto::ImAClient imaclient; char* id; size_t len; get_pub_key_hash(&cmix_ctx, &id, &len); imaclient.set_id(id, len); free(id); BOOST_LOG_TRIVIAL(trace) << "sending imaclient to node: " << i; network_connections.at(i).async_send(imaclient); network_connections.at(i).async_receive([i, this](cmix_proto::CMixMessage message) { handle_message(i, message); }); }; network_connections.emplace_back(std::unique_ptr>(new ssl::stream(io_service, *ssl_ctx))); network_connections.back().async_connect(network_details.node_details[i].host, network_details.node_details[i].port, handler); } } void CMixClient::handle_payload(cmix_proto::Payload pl) { std::cout << "Received message: " << pl.payload() << std::endl; } void CMixClient::handle_key_exchange(size_t node_id, cmix_proto::KeyExchange const& ke) { key_exchange_initiator( &cmix_ctx, &shared_values.at(node_id), ke.public_key().data(), ke.value().data(), &secret_values.at(node_id) ); if(std::all_of(shared_values.begin(), shared_values.end(), [](GroupElement const& value){return value != nullptr;})) { size_t len = cmix_ctx.nr_mixes * get_message_size(&cmix_ctx); std::vector vec(len, '\0'); char* id; size_t id_len; get_pub_key_hash(&cmix_ctx, &id, &id_len); std::string s = "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"; create_message(&cmix_ctx, vec.data(), id, id_len, s.data(), s.size()); free(id); cmix_proto::UserMessage message; message.mutable_m()->resize(get_group_element_array_size(&cmix_ctx) * cmix_ctx.nr_mixes); blind_message(&cmix_ctx, &(*message.mutable_m())[0], vec.data(), shared_values.data(), shared_values.size()); BOOST_LOG_TRIVIAL(trace) << "sending UserMessage: " << message.ShortDebugString(); network_connections.at(0).async_send(message); size_t last_node_id = network_details.node_details.size() - 1; network_connections.at(last_node_id).async_receive( [this, last_node_id](cmix_proto::CMixMessage const& inner_message) { handle_message(last_node_id, inner_message); } ); } } void CMixClient::handle_message(size_t node_id, cmix_proto::CMixMessage message) { switch(message.contents_case()) { case cmix_proto::CMixMessage::ContentsCase::kKeyexchange: { BOOST_LOG_TRIVIAL(trace) << "handling keyexchange for node: " << node_id; handle_key_exchange(node_id, *message.mutable_keyexchange()); return; } case cmix_proto::CMixMessage::ContentsCase::kBye: { BOOST_LOG_TRIVIAL(trace) << "handling bye for node: " << node_id; network_connections.at(node_id).close(); if(std::all_of(network_connections.begin(), network_connections.end(), [](SSLSenderReceiver const& c) { return !c.is_open(); })) { break; } else { return; } } case cmix_proto::CMixMessage::ContentsCase::kNodeready: { BOOST_LOG_TRIVIAL(trace) << "handling NodeReady: " << node_id; key_exchange(node_id); return; } case cmix_proto::CMixMessage::ContentsCase::kPayload: { BOOST_LOG_TRIVIAL(trace) << "handling Payload: "; handle_payload(message.payload()); return; } case cmix_proto::CMixMessage::ContentsCase::CONTENTS_NOT_SET: case cmix_proto::CMixMessage::ContentsCase::kInitialization: case cmix_proto::CMixMessage::ContentsCase::kSecretkey: case cmix_proto::CMixMessage::ContentsCase::kImaclient: case cmix_proto::CMixMessage::ContentsCase::kImanode: case cmix_proto::CMixMessage::ContentsCase::kUsermessage: case cmix_proto::CMixMessage::ContentsCase::kPrepre: case cmix_proto::CMixMessage::ContentsCase::kPremix: case cmix_proto::CMixMessage::ContentsCase::kPrepost: case cmix_proto::CMixMessage::ContentsCase::kRealpre: case cmix_proto::CMixMessage::ContentsCase::kRealmix: case cmix_proto::CMixMessage::ContentsCase::kRealpost: case cmix_proto::CMixMessage::ContentsCase::kCommitments: case cmix_proto::CMixMessage::ContentsCase::kPerformance: { BOOST_LOG_TRIVIAL(error) << "Received unknown message"; break; } } io_service.stop(); } CMixClient::CMixClient(NetworkDetails details) : io_service() , ssl_ctx(std::make_shared(boost::asio::ssl::context::sslv23)) , cmix_ctx(initialize_cmix_context(get_implementation(), details.nr_mixes)) , network_details(details) , network_connections() , secret_values() , shared_values() { initialize_keypair(&cmix_ctx); if(!details.certdir.empty()) { ssl_ctx->add_verify_path(details.certdir); } initialize_connections(); } CMixClient::~CMixClient() { for(auto&& v : shared_values) { cmix_ctx.api.free_group_element(v); v = nullptr; } deinitialize(&cmix_ctx); } void CMixClient::run() { io_service.run(); }