Browse Source

Whisper now 100% encrypted.

cl-refactor
Gav Wood 10 years ago
parent
commit
7d504a275f
  1. 4
      alethzero/MainWin.cpp
  2. 8
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  3. 4
      libwhisper/Interface.h
  4. 60
      libwhisper/Message.cpp
  5. 4
      libwhisper/Message.h
  6. 4
      libwhisper/WhisperHost.h
  7. 12
      test/whisperTopic.cpp

4
alethzero/MainWin.cpp

@ -2414,10 +2414,10 @@ void Main::refreshWhispers()
shh::Envelope const& e = w.second;
shh::Message m;
for (pair<Public, Secret> 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())

8
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));
}

4
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;

60
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<u256>();
}
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

4
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); }

4
libwhisper/WhisperHost.h

@ -39,6 +39,8 @@ namespace dev
namespace shh
{
static const FullTopic EmptyFullTopic;
class WhisperHost: public HostCapability<WhisperPeer>, 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;

12
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<unsigned>();
cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
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<unsigned>();
cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
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<unsigned>();
}
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<unsigned>();
}
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<unsigned>();
cnote << "New message from:" << msg.from().abridged() << RLP(msg.payload()).toInt<unsigned>();
result = last;

Loading…
Cancel
Save