diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp
index 4375e0727..7b91da114 100644
--- a/libwhisper/Message.cpp
+++ b/libwhisper/Message.cpp
@@ -35,34 +35,8 @@ Message::Message(Envelope const& _e, FullTopic const& _fk, Secret const& _s)
if (!decrypt(_s, &(_e.data()), b))
return;
else{}
- else
- {
- // public - need to get the key through combining with the topic/topicIndex we know.
- unsigned topicIndex = 0;
- Secret topicSecret;
-
- // determine topicSecret/topicIndex from knowledge of the collapsed topics (which give the order) and our full-size filter topic.
- CollapsedTopic 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
- h256 tk = h256(bytesConstRef(&(_e.data())).cropped(32 * topicIndex, 32));
- bytesConstRef cipherText = bytesConstRef(&(_e.data())).cropped(32 * _e.topic().size());
-// cdebug << "Decrypting(" << topicIndex << "): " << topicSecret << tk << (topicSecret ^ tk) << toHex(cipherText);
- if (!decryptSym(topicSecret ^ tk, cipherText, b))
- return;
-// cdebug << "Got: " << toHex(b);
- }
+ else if (!openBroadcastEnvelope(_e, _fk, b))
+ return;
if (populate(b))
if (_s)
@@ -73,6 +47,40 @@ Message::Message(Envelope const& _e, FullTopic const& _fk, Secret const& _s)
}
}
+bool Message::openBroadcastEnvelope(Envelope const& _e, FullTopic const& _fk, bytes& o_b)
+{
+ // retrieve the key using the known topic and topicIndex.
+ unsigned topicIndex = 0;
+ Secret topicSecret;
+
+ // determine topicSecret/topicIndex from knowledge of the collapsed topics (which give the order) and our full-size filter topic.
+ CollapsedTopic 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 false;
+
+ h256 encryptedKey = h256(bytesConstRef(&(_e.data())).cropped(32 * topicIndex, 32));
+ h256 key = generateGamma(topicSecret) ^ encryptedKey;
+ bytesConstRef cipherText = bytesConstRef(&(_e.data())).cropped(32 * _e.topic().size());
+ return decryptSym(key, cipherText, o_b);
+}
+
+h256 Message::generateGamma(h256 const& _seed) const
+{
+ int const c_rounds = 128;
+ bytes zeroSalt;
+ bytes hashedTopic = dev::pbkdf2(_seed.hex(), zeroSalt, c_rounds);
+ return h256(hashedTopic);
+}
+
bool Message::populate(bytes const& _data)
{
if (!_data.size())
@@ -116,23 +124,14 @@ Envelope Message::seal(Secret _from, FullTopic const& _fullTopic, unsigned _ttl,
encrypt(m_to, &input, ret.m_data);
else
{
- // create the shared secret and encrypt
+ // create the shared secret for encrypting the payload, then encrypt the shared secret with each topic
Secret s = Secret::random();
- for (h256 const& t: _fullTopic)
- ret.m_data += (t ^ s).asBytes();
+ for (h256 const& t : _fullTopic)
+ ret.m_data += (generateGamma(t) ^ s).asBytes();
+
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);
diff --git a/libwhisper/Message.h b/libwhisper/Message.h
index 0735d6714..c9e6d7dc0 100644
--- a/libwhisper/Message.h
+++ b/libwhisper/Message.h
@@ -127,6 +127,8 @@ public:
private:
bool populate(bytes const& _data);
+ h256 generateGamma(h256 const& _seed) const;
+ bool openBroadcastEnvelope(Envelope const& _e, FullTopic const& _fk, bytes& o_b);
Public m_from;
Public m_to;
diff --git a/test/libwhisper/whisperMessage.cpp b/test/libwhisper/whisperMessage.cpp
new file mode 100644
index 000000000..26fdb0bd5
--- /dev/null
+++ b/test/libwhisper/whisperMessage.cpp
@@ -0,0 +1,103 @@
+/*
+This file is part of cpp-ethereum.
+
+cpp-ethereum is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+cpp-ethereum is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with cpp-ethereum. If not, see .
+*/
+/** @file whisperMessage.cpp
+* @author Vladislav Gluhovsky
+* @date May 2015
+*/
+
+#include
+#include
+
+using namespace std;
+using namespace dev;
+using namespace dev::shh;
+
+struct VerbosityHolder
+{
+ VerbosityHolder() : oldLogVerbosity(g_logVerbosity) { g_logVerbosity = 10; }
+ ~VerbosityHolder() { g_logVerbosity = oldLogVerbosity; }
+
+ int oldLogVerbosity;
+};
+
+FullTopic createRandomTopics(unsigned int i)
+{
+ FullTopic ret;
+ h256 t(i);
+
+ for (int j = 0; j < 8; ++j)
+ {
+ t = sha3(t);
+ ret.push_back(t);
+ }
+
+ return move(ret);
+}
+
+bytes createRandomPayload(unsigned int i)
+{
+ bytes ret;
+ srand(i);
+ int const sz = rand() % 1024;
+ for (int j = 0; j < sz; ++j)
+ ret.push_back(rand() % 256);
+
+ return move(ret);
+}
+
+void comparePayloads(Message const& m1, Message const& m2)
+{
+ bytes const& p1 = m1.payload();
+ bytes const& p2 = m2.payload();
+ BOOST_REQUIRE_EQUAL(p1.size(), p2.size());
+
+ for (size_t i = 0; i < p1.size(); ++i)
+ BOOST_REQUIRE_EQUAL(p1[i], p2[i]);
+}
+
+void sealAndOpenSingleMessage(unsigned int i)
+{
+ Secret zero;
+ FullTopic topics = createRandomTopics(i);
+ bytes const payload = createRandomPayload(i);
+ Message m1(payload);
+ Envelope e = m1.seal(zero, topics, 1, 1);
+
+ for (auto const& t: topics)
+ {
+ FullTopic singleTopic;
+ singleTopic.push_back(t);
+ Message m2(e, singleTopic, zero);
+ comparePayloads(m1, m2);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE(whisperMessage)
+
+BOOST_AUTO_TEST_CASE(seal)
+{
+ VerbosityHolder verbosityHolder;
+ cnote << "Testing Envelope encryption...";
+
+ for (unsigned int i = 1; i < 32; ++i)
+ {
+ cnote << i;
+ sealAndOpenSingleMessage(i);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()