diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index a608957a9..3c87f649a 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2414,10 +2414,10 @@ void Main::refreshWhispers() shh::Envelope const& e = w.second; shh::Message m; for (pair const& i: m_server->ids()) - if (!!(m = e.open(shh::FilterKey(shh::Undefined, i.second)))) + if (!!(m = e.open(shh::FullTopic(), i.second))) break; if (!m) - m = e.open(shh::FilterKey()); + m = e.open(shh::FullTopic()); QString msg; if (m.from()) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 0fd9476a4..c8aff938f 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -576,12 +576,12 @@ Json::Value WebThreeStubServerBase::shh_changed(int const& _id) if (pub) { cwarn << "Silently decrypting message from identity" << pub.abridged() << ": User validation hook goes here."; - m = e.open(shh::FilterKey(shh::Undefined, m_ids[pub])); - if (!m) - continue; + m = e.open(face()->fullTopic(_id), m_ids[pub]); } else - m = e.open(face()->filterKey(_id)); + m = e.open(face()->fullTopic(_id)); + if (!m) + continue; ret.append(toJson(h, e, m)); } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 6e3eb1cd1..37651a826 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -49,8 +49,6 @@ struct InstalledFilter { InstalledFilter(FullTopic const& _f): full(_f), filter(_f) {} - FilterKey filterKey() const { unsigned i; for (i = 0; i < full.size() && !full[i]; ++i) {} return i < full.size() ? FilterKey(i, full[i]) : FilterKey(); } - FullTopic full; TopicFilter filter; unsigned refCount = 1; @@ -72,7 +70,7 @@ public: virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0; - virtual FilterKey filterKey(unsigned _id) const = 0; + virtual FullTopic const& fullTopic(unsigned _id) const = 0; virtual unsigned installWatch(FullTopic const& _mask) = 0; virtual unsigned installWatchOnId(h256 _filterId) = 0; virtual void uninstallWatch(unsigned _watchId) = 0; diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index b87ba0717..74ce9475d 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -26,28 +26,56 @@ using namespace dev; using namespace dev::p2p; using namespace dev::shh; -Message::Message(Envelope const& _e, FilterKey const& _fk) +Topic collapse(FullTopic const& _fullTopic) +{ + Topic ret; + ret.reserve(_fullTopic.size()); + for (auto const& ft: _fullTopic) + ret.push_back(TopicPart(ft)); + return ret; +} + +Message::Message(Envelope const& _e, FullTopic const& _fk, Secret const& _s) { try { bytes b; - if (_fk.topicIndex == Undefined) - if (!_fk.key || !decrypt(_fk.key, &(_e.data()), b)) + if (_s) + if (!decrypt(_s, &(_e.data()), b)) return; else{} else { // public - need to get the key through combining with the topic/topicIndex we know. - if (_e.data().size() < _e.topics().size() * 32) + unsigned topicIndex = 0; + Secret topicSecret; + + // determine topicSecret/topicIndex from knowledge of the collapsed topics (which give the order) and our full-size filter topic. + Topic knownTopic = collapse(_fk); + for (unsigned ti = 0; ti < _fk.size() && !topicSecret; ++ti) + for (unsigned i = 0; i < _e.topic().size(); ++i) + if (_e.topic()[i] == knownTopic[ti]) + { + topicSecret = _fk[ti]; + topicIndex = i; + break; + } + + if (_e.data().size() < _e.topic().size() * 32) return; + // get key from decrypted topic key: just xor - if (!decryptSym(_fk.key ^ h256(bytesConstRef(&(_e.data())).cropped(32 * _fk.topicIndex, 32)), bytesConstRef(&(_e.data())).cropped(32 * _e.topics().size()), b)) + h256 tk = h256(bytesConstRef(&(_e.data())).cropped(32 * topicIndex, 32)); + bytesConstRef cipherText = bytesConstRef(&(_e.data())).cropped(32 * _e.topic().size()); + cnote << "Decrypting(" << topicIndex << "): " << topicSecret << tk << (topicSecret ^ tk) << toHex(cipherText); + if (!decryptSym(topicSecret ^ tk, cipherText, b)) return; + cnote << "Got: " << toHex(b); } if (populate(b)) - if (_fk.key && _fk.topicIndex == Undefined) - m_to = KeyPair(_fk.key).pub(); + if (_s) + m_to = KeyPair(_s).pub(); } catch (...) // Invalid secret? TODO: replace ... with InvalidSecret { @@ -77,9 +105,7 @@ bool Message::populate(bytes const& _data) Envelope Message::seal(Secret _from, FullTopic const& _fullTopic, unsigned _ttl, unsigned _workToProve) const { - Topic topic; - for (auto const& ft: _fullTopic) - topic.push_back(TopicPart(ft)); + Topic topic = collapse(_fullTopic); Envelope ret(time(0) + _ttl, _ttl, topic); bytes input(1 + m_payload.size()); @@ -106,6 +132,16 @@ Envelope Message::seal(Secret _from, FullTopic const& _fullTopic, unsigned _ttl, bytes d; encryptSym(s, &input, d); ret.m_data += d; + + for (unsigned i = 0; i < _fullTopic.size(); ++i) + { + bytes b; + h256 tk = h256(bytesConstRef(&(ret.m_data)).cropped(32 * i, 32)); + bytesConstRef cipherText = bytesConstRef(&(ret.m_data)).cropped(32 * ret.topic().size()); + cnote << "Test decrypting(" << i << "): " << _fullTopic[i] << tk << (_fullTopic[i] ^ tk) << toHex(cipherText); + assert(decryptSym(_fullTopic[i] ^ tk, cipherText, b)); + cnote << "Got: " << toHex(b); + } } ret.proveWork(_workToProve); @@ -121,9 +157,9 @@ Envelope::Envelope(RLP const& _m) m_nonce = _m[4].toInt(); } -Message Envelope::open(FilterKey const& _filterKey) const +Message Envelope::open(FullTopic const& _ft, Secret const& _s) const { - return Message(*this, _filterKey); + return Message(*this, _ft, _s); } unsigned Envelope::workProved() const diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 00e619461..b4b88b472 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -74,7 +74,7 @@ public: Topic const& topic() const { return m_topic; } bytes const& data() const { return m_data; } - Message open(FilterKey const& _fk) const; + Message open(FullTopic const& _ft, Secret const& _s = Secret()) const; unsigned workProved() const; void proveWork(unsigned _ms); @@ -101,7 +101,7 @@ class Message { public: Message() {} - Message(Envelope const& _e, FilterKey const& _fk); + Message(Envelope const& _e, FullTopic const& _ft, Secret const& _s = Secret()); Message(bytes const& _payload): m_payload(_payload) {} Message(bytesConstRef _payload): m_payload(_payload.toBytes()) {} Message(bytes&& _payload) { std::swap(_payload, m_payload); } diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 425fe3108..8111c6449 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -39,6 +39,8 @@ namespace dev namespace shh { +static const FullTopic EmptyFullTopic; + class WhisperHost: public HostCapability, public Interface, public Worker { friend class WhisperPeer; @@ -51,7 +53,7 @@ public: virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override; - virtual FilterKey filterKey(unsigned _id) const { try { return m_filters.at(m_watches.at(_id).id).filterKey(); } catch (...) { return FilterKey(); } } + virtual FullTopic const& fullTopic(unsigned _id) const { try { return m_filters.at(m_watches.at(_id).id).full; } catch (...) { return EmptyFullTopic; } } virtual unsigned installWatch(FullTopic const& _filter) override; virtual unsigned installWatchOnId(h256 _filterId) override; virtual void uninstallWatch(unsigned _watchId) override; diff --git a/test/whisperTopic.cpp b/test/whisperTopic.cpp index 635defd75..0162124b8 100644 --- a/test/whisperTopic.cpp +++ b/test/whisperTopic.cpp @@ -34,7 +34,7 @@ BOOST_AUTO_TEST_CASE(topic) { cnote << "Testing Whisper..."; auto oldLogVerbosity = g_logVerbosity; - g_logVerbosity = 4; + g_logVerbosity = 0; bool started = false; unsigned result = 0; @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(topic) { for (auto i: wh->checkWatch(w)) { - Message msg = wh->envelope(i).open(wh->filterKey(w)); + Message msg = wh->envelope(i).open(wh->fullTopic(w)); last = RLP(msg.payload()).toInt(); cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt(); result += last; @@ -116,7 +116,7 @@ BOOST_AUTO_TEST_CASE(forwarding) { for (auto i: wh->checkWatch(w)) { - Message msg = wh->envelope(i).open(wh->filterKey(w)); + Message msg = wh->envelope(i).open(wh->fullTopic(w)); unsigned last = RLP(msg.payload()).toInt(); cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt(); result = last; @@ -152,7 +152,7 @@ BOOST_AUTO_TEST_CASE(forwarding) { for (auto i: wh->checkWatch(w)) { - Message msg = wh->envelope(i).open(wh->filterKey(w)); + Message msg = wh->envelope(i).open(wh->fullTopic(w)); cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt(); } this_thread::sleep_for(chrono::milliseconds(50)); @@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) { for (auto i: wh->checkWatch(w)) { - Message msg = wh->envelope(i).open(wh->filterKey(w)); + Message msg = wh->envelope(i).open(wh->fullTopic(w)); cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt(); } this_thread::sleep_for(chrono::milliseconds(50)); @@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE(asyncforwarding) { for (auto i: wh->checkWatch(w)) { - Message msg = wh->envelope(i).open(wh->filterKey(w)); + Message msg = wh->envelope(i).open(wh->fullTopic(w)); unsigned last = RLP(msg.payload()).toInt(); cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt(); result = last;