void ShuffleRound::HandlePrivateKey(QDataStream &stream, const Id &id) { qDebug() << _group.GetIndex(_local_id) << _local_id.ToString() << ": received private key from " << _group.GetIndex(id) << id.ToString() << ", received" << _keys_received << "keys."; if(_state != Verification && _state != PrivateKeySharing) { qWarning() << "Received a private key message while in state " << StateToString(_state); return; } QByteArray key; stream >> key; int idx = _group.GetIndex(id); int kidx = _group.GetSize() - 1 - idx; _private_inner_keys[idx] = new CppPrivateKey(key); if(!_private_inner_keys[idx]->VerifyKey(*_public_inner_keys[kidx])) { qWarning() << "Invalid inner key for " << idx << id.ToString(); return; } if(++_keys_received == _private_inner_keys.count()) { Decrypt(); } }
void ShuffleRound::HandleVerification(bool go, const Id &id) { qDebug() << _group.GetIndex(_local_id) << _local_id.ToString() << ": received" << go << " from " << _group.GetIndex(id) << id.ToString(); if(_state != Verification && _state != ShuffleDone) { qWarning() << "Received a GoNoGo message while in state" << StateToString(_state); return; } if(!go) { return; } int idx = _group.GetIndex(id); if(_go_received[idx]) { qWarning() << "Multiple \"go\"s received from " << id.ToString(); return; } _go_received[idx] = true; if(++_go == _group.GetSize()) { BroadcastPrivateKey(); } }
void BulkRound::HandleBulkData(QDataStream &stream, const Id &from) { qDebug() << GetGroup().GetIndex(GetLocalId()) << GetLocalId().ToString() << ": received bulk data from " << GetGroup().GetIndex(from) << from.ToString(); if(IsLeader() || !_app_broadcast) { if(_state != DataSharing) { throw QRunTimeError("Received a misordered BulkData message"); } } else if(_app_broadcast && _state != ProcessingLeaderData) { throw QRunTimeError("Waiting for data from leader, received something else."); } int idx = GetGroup().GetIndex(from); if(!_messages[idx].isEmpty()) { throw QRunTimeError("Already have bulk data."); } QByteArray payload; stream >> payload; if(payload.size() != _expected_bulk_size) { throw QRunTimeError("Incorrect bulk message length"); } _messages[idx] = payload; if(++_received_messages == GetGroup().Count()) { ProcessMessages(); Finish(); } }
void Round::HandleDisconnect(const Id &id) { if(_group.Contains(id)) { SetInterrupted(); Stop(QString(id.ToString() + " disconnected")); } }
void ConnectionManager::BindEdge(Edge *edge, const Id &rem_id) { /// @TODO add an extra variable to the connection message such as a session ///token so that quick reconnects can be enabled. if(_con_tab.GetConnection(rem_id) != 0) { qWarning() << "Already have a connection to: " << rem_id.ToString() << " closing Edge: " << edge->ToString(); QVariantMap notification; notification["method"] = "CM::Close"; _rpc.SendNotification(notification, edge); Address addr = edge->GetRemoteAddress(); edge->Close("Duplicate connection"); emit ConnectionAttemptFailure(addr, "Duplicate connection"); return; } QSharedPointer<Edge> pedge = _con_tab.GetEdge(edge); if(pedge.isNull()) { qCritical() << "An edge attempted to create a connection, but there " "is no record of it" << edge->ToString(); return; } QVariantMap notification; notification["method"] = "CM::Connect"; notification["peer_id"] = _local_id.GetByteArray(); _rpc.SendNotification(notification, edge); CreateConnection(pedge, rem_id); }
void ShuffleRound::HandleData(QDataStream &stream, const Id &id) { qDebug() << _group.GetIndex(_local_id) << _local_id.ToString() << ": received initial data from " << _group.GetIndex(id) << id.ToString(); if(_state != KeySharing && _state != DataSubmission && _state != WaitingForShuffle) { qWarning() << "Received a data message while in state " << StateToString(_state) << " from " << id.ToString(); return; } int idx = _group.GetIndex(_local_id); if(idx != 0) { qWarning() << "Received a data message while not the first node " << " in the group. Actual position: " << idx; return; } QByteArray data; stream >> data; idx = _group.GetIndex(id); if(data.isEmpty()) { qWarning() << _group.GetIndex(_local_id) << _local_id.ToString() << ": received null data from " << idx << id.ToString(); return; } if(!_shuffle_data[idx].isEmpty()) { if(_shuffle_data[idx] != data) { qWarning() << "Received a second data message from " << id.ToString(); } else { qWarning() << "Received a duplicate data message from " << id.ToString(); } return; } _shuffle_data[idx] = data; if(++_data_received == _group.GetSize()) { Shuffle(); } }
TEST(Id, InvalidString) { Id id; QString bad = "ABCD"; QString good = id.ToString(); EXPECT_EQ(Id::Zero(), Id(bad)); EXPECT_EQ(id, Id(good)); }
void RelayAddress::Init(const Id &id) { QUrl url; url.setScheme(Scheme); url.setPath(id.ToString()); _data = new RelayAddressData(url, id); }
RelayForwarder::RelayForwarder(const Id &local_id, const ConnectionTable &ct, const QSharedPointer<RpcHandler> &rpc) : _local_id(local_id), _base_been(local_id.ToString()), _ct(ct), _rpc(rpc), _cache(4096) { _rpc->Register("RF::Data", this, "IncomingData"); }
void RelayForwarder::Send(const QSharedPointer<Connection> &con, const Id &to, const QByteArray &data, const QStringList &been, const QStringList &reverse) { QVariantHash msg; msg["to"] = to.ToString(); msg["data"] = data; msg["been"] = been + _base_been; if(!reverse.isEmpty()) { msg["reverse"] = reverse; } qDebug() << con->GetLocalId().ToString() << "Forwarding message from" << msg["been"].toStringList().value(0) << "to" << to.ToString() << "via" << con->GetRemoteId().ToString() << "Reverse path" << !reverse.isEmpty(); _rpc->SendNotification(con, "RF::Data", msg); }
void BulkRound::HandleLoggedBulkData(QDataStream &stream, const Id &from) { if(from == GetLocalId()) { return; } qDebug() << GetGroup().GetIndex(GetLocalId()) << GetLocalId().ToString() << ": received logged bulk data from " << GetGroup().GetIndex(from) << from.ToString(); if(GetGroup().GetLeader() != from) { throw QRunTimeError("Received logged bulk data from non-leader."); } if(_state != ReceivingLeaderData) { throw QRunTimeError("Not expected at this time."); } QByteArray binary_log; stream >> binary_log; Log log(binary_log); if(log.Count() != GetGroup().Count()) { throw QRunTimeError("Incorrect number of log messages."); } _state = ProcessingLeaderData; for(int idx = 0; idx < log.Count(); idx++) { const QPair<QByteArray, Id> &res = log.At(idx); try { ProcessDataBase(res.second, res.first); } catch (QRunTimeError &err) { const Id &from = res.second; qWarning() << GetGroup().GetIndex(GetLocalId()) << GetLocalId().ToString() << "leader equivocated in message from" << GetGroup().GetIndex(from) << from.ToString() << "in session / round" << GetRoundId().ToString() << "in state" << StateToString(_state) << "causing the following exception: " << err.What(); // Should end round. break; } } }
void ShuffleRound::HandleShuffle(QDataStream &stream, const Id &id) { qDebug() << _group.GetIndex(_local_id) << _local_id.ToString() << ": received shuffle data from " << _group.GetIndex(id) << id.ToString(); if(_state != WaitingForShuffle) { qWarning() << "Received a shuffle message while in state " << StateToString(_state) << " from " << id.ToString(); return; } if(_group.Previous(_local_id) != id) { qWarning() << "Received shuffle out of order from " << id.ToString(); return; } stream >> _shuffle_data; Shuffle(); }
void ShuffleRound::ProcessData(const QByteArray &data, const Id &id) { QByteArray payload; if(!Verify(data, payload, id)) { return; } QDataStream stream(payload); int mtype; QByteArray session_id; stream >> mtype >> session_id; MessageType msg_type = (MessageType) mtype; Id sid(session_id); if(sid != GetId()) { qWarning() << "Invalid session, expected " << GetId().ToString() << ", found " << sid.ToString(); return; } _in_log.Append(data, id); switch(msg_type) { case PublicKeys: HandlePublicKeys(stream, id); break; case Data: HandleData(stream, id); break; case ShuffleData: HandleShuffle(stream, id); break; case EncryptedData: HandleDataBroadcast(stream, id); break; case GoMessage: HandleVerification(true, id); break; case NoGoMessage: HandleVerification(false, id); break; case PrivateKey: HandlePrivateKey(stream, id); break; default: qWarning() << "Unknown message type: " << MessageTypeToString(msg_type) << " from " << id.ToString(); return; } }
void RepeatingBulkRound::ProcessData(const Id &from, const QByteArray &data) { _log.Append(data, from); try { ProcessDataBase(from, data); } catch (QRunTimeError &err) { qWarning() << GetGroup().GetIndex(GetLocalId()) << GetLocalId().ToString() << "received a message from" << GetGroup().GetIndex(from) << from.ToString() << "in session / round" << GetRoundId().ToString() << "in state" << StateToString(_state) << "causing the following exception: " << err.What(); _log.Pop(); return; } }
void ShuffleRound::HandlePublicKeys(QDataStream &stream, const Id &id) { qDebug() << _group.GetIndex(_local_id) << _local_id.ToString() << ": received public keys from " << _group.GetIndex(id) << id.ToString(); if(_state != Offline && _state != KeySharing) { qWarning() << "Received a key message while in state " << StateToString(_state) << " from " << id.ToString(); return; } int idx = _group.GetIndex(id); int kidx = _group.GetSize() - 1 - idx; if(_public_inner_keys[kidx] != 0 || _public_outer_keys[kidx] != 0) { qWarning() << _group.GetIndex(_local_id) << _local_id.ToString() << ": received duplicate public keys from " << _group.GetIndex(id) << id.ToString(); return; } QByteArray inner_key, outer_key; stream >> inner_key >> outer_key; _public_inner_keys[kidx] = new CppPublicKey(inner_key); _public_outer_keys[kidx] = new CppPublicKey(outer_key); if(!_public_inner_keys[kidx]->IsValid()) { qWarning() << _group.GetIndex(_local_id) << _local_id.ToString() << ": invalid inner key from " << idx << id.ToString(); } else if(!_public_outer_keys[kidx]->IsValid()) { qWarning() << _group.GetIndex(_local_id) << _local_id.ToString() << ": invalid outer key from " << idx << id.ToString(); } if(++_keys_received == _group.GetSize()) { SubmitData(); } }
void RepeatingBulkRound::HandleBulkData(QDataStream &stream, const Id &from) { qDebug() << GetGroup().GetIndex(GetLocalId()) << GetLocalId().ToString() << ": received bulk data from " << GetGroup().GetIndex(from) << from.ToString() << "Have" << (_received_messages + 1) << "expecting" << _messages.count(); if(_state != DataSharing) { throw QRunTimeError("Received a misordered BulkData message"); } uint idx = GetGroup().GetIndex(from); if(!_messages[idx].isEmpty()) { throw QRunTimeError("Already have bulk data."); } QByteArray payload; stream >> payload; if(static_cast<uint>(payload.size()) != _expected_bulk_size) { throw QRunTimeError("Incorrect bulk message length, got " + QString::number(payload.size()) + " expected " + QString::number(_expected_bulk_size)); } _messages[idx] = payload; if(++_received_messages == static_cast<uint>(GetGroup().Count())) { ProcessMessages(); SetState(PhasePreparation); qDebug() << "In" << ToString() << "ending phase."; _phase++; if(!PrepForNextPhase()) { return; } SetState(DataSharing); uint count = static_cast<uint>(_offline_log.Count()); for(uint idx = 0; idx < count; idx++) { QPair<QByteArray, Id> entry = _offline_log.At(idx); ProcessData(entry.second, entry.first); } _offline_log.Clear(); NextPhase(); } }
void ShuffleRound::HandleDataBroadcast(QDataStream &stream, const Id &id) { qDebug() << _group.GetIndex(_local_id) << _local_id.ToString() << ": received data broadcast from " << _group.GetIndex(id) << id.ToString(); if(_state != ShuffleDone) { return; } if(_group.GetSize() - 1 != _group.GetIndex(id)) { qWarning() << "Received data broadcast from wrong node."; return; } stream >> _encrypted_data; Verify(); }
void BulkRound::HandleAggregatedBulkData(QDataStream &stream, const Id &from) { if(from == GetLocalId()) { return; } qDebug() << GetGroup().GetIndex(GetLocalId()) << GetLocalId().ToString() << ": received aggregated bulk data from " << GetGroup().GetIndex(from) << from.ToString(); if(GetGroup().GetLeader() != from) { throw QRunTimeError("Received aggregated bulk data from non-leader."); } if(_state != ReceivingLeaderData) { throw QRunTimeError("Not expected at this time."); } QVector<QByteArray> cleartexts; stream >> cleartexts; const QVector<Descriptor> &des = GetDescriptors(); if(cleartexts.count() != des.count()) { throw QRunTimeError("Cleartext count does not match descriptor count: " + QString::number(cleartexts.count()) + " " + QString::number(des.count())); } Hash hashalgo; for(int idx = 0; idx < cleartexts.count(); idx++) { QByteArray cleartext = cleartexts[idx]; QByteArray hash = hashalgo.ComputeHash(cleartext); if(hash != des[idx].CleartextHash()) { throw QRunTimeError("Cleartext hash does not match descriptor hash."); } if(!cleartext.isEmpty()) { PushData(GetSharedPointer(), cleartext); } } Finish(); }
void ConnectionManager::BindEdge(const QSharedPointer<Edge> &edge, const Id &rem_id) { /// @TODO add an extra variable to the connection message such as a session ///token so that quick reconnects can be enabled. if(_con_tab.GetConnection(rem_id) != 0) { qDebug() << "Already have a connection to: " << rem_id.ToString() << " closing Edge: " << edge->ToString(); _rpc->SendNotification(edge, "CM::Close", QVariant()); Address addr = edge->GetRemoteAddress(); edge->Stop("Duplicate connection"); emit ConnectionAttemptFailure(addr, "Duplicate connection"); return; } _rpc->SendNotification(edge, "CM::Connect", _local_id.GetByteArray()); CreateConnection(edge, rem_id); }
RelayAddress::RelayAddress(const QUrl &url) { if(url.scheme() != Scheme) { qWarning() << "Supplied an invalid scheme" << url.scheme(); _data = new AddressData(url); return; } QString sid = url.path().mid(1); Id id = Id(sid); if(id.ToString() != sid) { qWarning() << "Supplied an invalid Id:" << sid; _data = new AddressData(url); return; } Init(id); _data = new RelayAddressData(url, id); }
void TestRoundBad(CreateRound good_cr, CreateRound bad_cr, const BadGuyCB &callback, bool client, bool will_finish) { int servers = 3, clients = 10; ConnectionManager::UseTimer = false; Timer::GetInstance().UseVirtualTime(); OverlayNetwork net = ConstructOverlay(servers, clients); VerifyStoppedNetwork(net); StartNetwork(net); VerifyNetwork(net); Sessions sessions = BuildSessions(net, good_cr); // Find a bad guy and replace him... int badguy = Random::GetInstance().GetInt(0, clients); Id badid = net.second[badguy]->GetId(); if(!client) { badguy = Random::GetInstance().GetInt(0, servers); badid = net.first[badguy]->GetId(); } qDebug() << "Bad guy at" << badguy << badid; QSharedPointer<AsymmetricKey> key = sessions.private_keys[badid.ToString()]; if(client) { ClientPointer cs = MakeSession<ClientSession>( net.second[badguy], key, sessions.keys, bad_cr); cs->SetSink(sessions.sink_multiplexers[servers + badguy].data()); sessions.clients[badguy] = cs; } else { ServerPointer ss = MakeSession<ServerSession>( net.first[badguy], key, sessions.keys, bad_cr); ss->SetSink(sessions.sink_multiplexers[badguy].data()); sessions.servers[badguy] = ss; } // Find a sender != badguy int sender = Random::GetInstance().GetInt(0, clients); if(client) { while(sender == badguy) { sender = Random::GetInstance().GetInt(0, clients); } } QByteArray msg(64, 0); CryptoRandom().GenerateBlock(msg); sessions.clients[sender]->Send(msg); qDebug() << "Starting sessions..."; StartSessions(sessions); StartRound(sessions); QSharedPointer<Round> bad_round; if(client) { bad_round = sessions.clients[badguy]->GetRound(); } else { bad_round = sessions.servers[badguy]->GetRound(); } SignalCounter sc; for(int idx = 0; idx < servers; idx++) { QObject::connect(sessions.servers[idx].data(), SIGNAL(RoundFinished(const QSharedPointer<Anonymity::Round> &)), &sc, SLOT(Counter())); } for(int idx = 0; idx < clients; idx++) { QObject::connect(sessions.clients[idx].data(), SIGNAL(RoundFinished(const QSharedPointer<Anonymity::Round> &)), &sc, SLOT(Counter())); } RunUntil(sc, clients + servers); if(will_finish) { ASSERT_EQ(sc.GetCount(), clients + servers); ASSERT_EQ(bad_round->GetBadMembers().size(), 1); ASSERT_EQ(badid, bad_round->GetBadMembers()[0]); } if(!callback(bad_round.data())) { std::cout << "RoundTest_BadGuy was never triggered, " "consider rerunning." << std::endl; } StopNetwork(sessions.network); VerifyStoppedNetwork(sessions.network); ConnectionManager::UseTimer = true; }
/** * Send a notification -- a request without expecting a response * @param notification message for the remote side * @param to id to destination */ inline virtual void Send(const QByteArray &data, const Id &to) { Connection *con = _ct.GetConnection(to); if(con == 0) { qWarning() << "Attempting to send a notification when no such peer exists," << to.ToString(); return; } Send(data, con); }