From 0a69c28ac50a6fa1d847feef814559197f3023fb Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Fri, 5 Apr 2013 16:33:48 +0000 Subject: [PATCH] implemented crypto stream, with some extra unit tests --- src/cmd/synergyc/CMakeLists.txt | 2 +- src/cmd/synergyd/CMakeLists.txt | 2 +- src/cmd/synergyp/CMakeLists.txt | 2 +- src/cmd/synergys/CMakeLists.txt | 2 +- src/lib/client/CClient.cpp | 5 + src/lib/client/CClient.h | 12 +- src/lib/client/CMakeLists.txt | 1 + src/lib/client/CServerProxy.cpp | 2 + src/lib/client/CServerProxy.h | 4 +- src/lib/platform/COSXScreen.cpp | 2 +- src/lib/server/CClientListener.cpp | 5 + src/lib/server/CClientListener.h | 2 + src/lib/server/CClientProxy.cpp | 1 - src/lib/server/CClientProxy.h | 11 +- src/lib/server/CClientProxyUnknown.h | 2 +- src/lib/server/CMakeLists.txt | 1 + src/lib/synergy/CCryptoStream.cpp | 60 +++++++-- src/lib/synergy/CCryptoStream.h | 9 +- src/lib/synergy/CKeyMap.cpp | 2 +- src/test/unittests/Main.cpp | 2 +- .../unittests/synergy/CCryptoStreamTests.cpp | 120 +++++++++++++++++- 21 files changed, 217 insertions(+), 32 deletions(-) diff --git a/src/cmd/synergyc/CMakeLists.txt b/src/cmd/synergyc/CMakeLists.txt index 1015df59..a9b2da74 100644 --- a/src/cmd/synergyc/CMakeLists.txt +++ b/src/cmd/synergyc/CMakeLists.txt @@ -62,7 +62,7 @@ endif() include_directories(${inc}) add_executable(synergyc ${src}) target_link_libraries(synergyc - arch base client common io mt net ipc platform server synergy ${libs}) + arch base client common io mt net ipc platform server synergy cryptopp ${libs}) if (CONF_CPACK) install(TARGETS diff --git a/src/cmd/synergyd/CMakeLists.txt b/src/cmd/synergyd/CMakeLists.txt index c7d66f07..39eaf59d 100644 --- a/src/cmd/synergyd/CMakeLists.txt +++ b/src/cmd/synergyd/CMakeLists.txt @@ -49,7 +49,7 @@ if (VNC_SUPPORT) endif() target_link_libraries(synergyd - arch base common io ipc mt net platform synergy ${libs}) + arch base common io ipc mt net platform synergy cryptopp ${libs}) if (CONF_CPACK) install(TARGETS diff --git a/src/cmd/synergyp/CMakeLists.txt b/src/cmd/synergyp/CMakeLists.txt index 292197dc..cb65722e 100644 --- a/src/cmd/synergyp/CMakeLists.txt +++ b/src/cmd/synergyp/CMakeLists.txt @@ -64,7 +64,7 @@ else() endif() target_link_libraries(synergyp - arch base client common io mt net ipc platform server synergy client ${libs}) + arch base client common io mt net ipc platform server synergy client cryptopp ${libs}) if (CONF_CPACK) install(TARGETS diff --git a/src/cmd/synergys/CMakeLists.txt b/src/cmd/synergys/CMakeLists.txt index 1f442058..e706ea5e 100644 --- a/src/cmd/synergys/CMakeLists.txt +++ b/src/cmd/synergys/CMakeLists.txt @@ -62,7 +62,7 @@ endif() include_directories(${inc}) add_executable(synergys ${src}) target_link_libraries(synergys - arch base client common io mt net ipc platform server synergy ${libs}) + arch base client common io mt net ipc platform server synergy cryptopp ${libs}) if (CONF_CPACK) install(TARGETS diff --git a/src/lib/client/CClient.cpp b/src/lib/client/CClient.cpp index 46387377..0babb949 100644 --- a/src/lib/client/CClient.cpp +++ b/src/lib/client/CClient.cpp @@ -34,6 +34,7 @@ #include #include "CArch.h" #include "IPlatformScreen.h" +#include "CCryptoStream.h" // // CClient @@ -147,6 +148,10 @@ CClient::connect() } m_stream = new CPacketStreamFilter(m_stream, true); + if (s_cryptoEnabled) { + m_stream = new CCryptoStream(*EVENTQUEUE, m_stream, true); + } + // connect LOG((CLOG_DEBUG1 "connecting to server")); setupConnecting(); diff --git a/src/lib/client/CClient.h b/src/lib/client/CClient.h index ea9ce92d..08db693c 100644 --- a/src/lib/client/CClient.h +++ b/src/lib/client/CClient.h @@ -208,13 +208,13 @@ private: IClipboard::Time m_timeClipboard[kClipboardEnd]; CString m_dataClipboard[kClipboardEnd]; IEventQueue& m_eventQueue; - - static CEvent::Type s_connectedEvent; - static CEvent::Type s_connectionFailedEvent; - static CEvent::Type s_disconnectedEvent; - -protected: bool m_mock; + + static CEvent::Type s_connectedEvent; + static CEvent::Type s_connectionFailedEvent; + static CEvent::Type s_disconnectedEvent; + + static const int s_cryptoEnabled = true; }; #endif diff --git a/src/lib/client/CMakeLists.txt b/src/lib/client/CMakeLists.txt index b40bbc7f..488e1ff3 100644 --- a/src/lib/client/CMakeLists.txt +++ b/src/lib/client/CMakeLists.txt @@ -36,6 +36,7 @@ set(inc ../mt ../net ../synergy + ../../../tools ) if (UNIX) diff --git a/src/lib/client/CServerProxy.cpp b/src/lib/client/CServerProxy.cpp index 659412b1..39f54e5a 100644 --- a/src/lib/client/CServerProxy.cpp +++ b/src/lib/client/CServerProxy.cpp @@ -29,6 +29,7 @@ #include "XBase.h" #include #include +#include "CCryptoStream.h" // // CServerProxy @@ -37,6 +38,7 @@ CServerProxy::CServerProxy(CClient* client, synergy::IStream* stream, IEventQueue& eventQueue) : m_client(client), m_stream(stream), + m_cryptoStream(NULL), m_seqNum(0), m_compressMouse(false), m_compressMouseRelative(false), diff --git a/src/lib/client/CServerProxy.h b/src/lib/client/CServerProxy.h index fe763f58..d2c5be09 100644 --- a/src/lib/client/CServerProxy.h +++ b/src/lib/client/CServerProxy.h @@ -30,6 +30,7 @@ class CEventQueueTimer; class IClipboard; namespace synergy { class IStream; } class IEventQueue; +class CCryptoStream; //! Proxy for server /*! @@ -105,7 +106,8 @@ private: typedef EResult (CServerProxy::*MessageParser)(const UInt8*); CClient* m_client; - synergy::IStream* m_stream; + synergy::IStream* m_stream; + CCryptoStream* m_cryptoStream; UInt32 m_seqNum; diff --git a/src/lib/platform/COSXScreen.cpp b/src/lib/platform/COSXScreen.cpp index 9de405fe..a445b982 100644 --- a/src/lib/platform/COSXScreen.cpp +++ b/src/lib/platform/COSXScreen.cpp @@ -1499,7 +1499,7 @@ COSXScreen::updateScreenShape() // We want to notify the peer screen whether we are primary screen or not sendEvent(getShapeChangedEvent()); - LOG((CLOG_DEBUG "screen shape: center=%d,%d size=%dx%d on %u %s (%s)", + LOG((CLOG_DEBUG "screen shape: center=%d,%d size=%dx%d on %u %s", m_x, m_y, m_w, m_h, displayCount, (displayCount == 1) ? "display" : "displays")); } diff --git a/src/lib/server/CClientListener.cpp b/src/lib/server/CClientListener.cpp index 571bad8e..5c6487ae 100644 --- a/src/lib/server/CClientListener.cpp +++ b/src/lib/server/CClientListener.cpp @@ -28,6 +28,7 @@ #include "CLog.h" #include "IEventQueue.h" #include "TMethodEventJob.h" +#include "CCryptoStream.h" // // CClientListener @@ -143,6 +144,10 @@ CClientListener::handleClientConnecting(const CEvent&, void*) stream = m_streamFilterFactory->create(stream, true); } stream = new CPacketStreamFilter(stream, true); + + if (s_cryptoEnabled) { + stream = new CCryptoStream(*EVENTQUEUE, stream, true); + } assert(m_server != NULL); diff --git a/src/lib/server/CClientListener.h b/src/lib/server/CClientListener.h index 3ad8fa24..21703c2b 100644 --- a/src/lib/server/CClientListener.h +++ b/src/lib/server/CClientListener.h @@ -84,6 +84,8 @@ private: static CEvent::Type s_connectedEvent; CServer* m_server; + + static const bool s_cryptoEnabled = true; }; #endif diff --git a/src/lib/server/CClientProxy.cpp b/src/lib/server/CClientProxy.cpp index 69320239..895b4d11 100644 --- a/src/lib/server/CClientProxy.cpp +++ b/src/lib/server/CClientProxy.cpp @@ -35,7 +35,6 @@ CClientProxy::CClientProxy(const CString& name, synergy::IStream* stream) : CBaseClientProxy(name), m_stream(stream) { - // do nothing } CClientProxy::~CClientProxy() diff --git a/src/lib/server/CClientProxy.h b/src/lib/server/CClientProxy.h index 82b2c846..6fe6d22d 100644 --- a/src/lib/server/CClientProxy.h +++ b/src/lib/server/CClientProxy.h @@ -25,6 +25,8 @@ namespace synergy { class IStream; } +const int g_encryptionEnabled = true; + //! Generic proxy for client class CClientProxy : public CBaseClientProxy { public: @@ -47,9 +49,16 @@ public: //! @name accessors //@{ + //! Get stream (unmodified) + /*! + Returns the original stream passed to the c'tor. + */ + synergy::IStream* getStreamUnmodified() const; + //! Get stream /*! - Returns the stream passed to the c'tor. + Returns a crypto stream if the user has this enabled, + otherwise returns the original stream passed to the c'tor. */ synergy::IStream* getStream() const; diff --git a/src/lib/server/CClientProxyUnknown.h b/src/lib/server/CClientProxyUnknown.h index bf9dabf1..279fb55a 100644 --- a/src/lib/server/CClientProxyUnknown.h +++ b/src/lib/server/CClientProxyUnknown.h @@ -76,7 +76,7 @@ private: void handleReady(const CEvent&, void*); private: - synergy::IStream* m_stream; + synergy::IStream* m_stream; CEventQueueTimer* m_timer; CClientProxy* m_proxy; bool m_ready; diff --git a/src/lib/server/CMakeLists.txt b/src/lib/server/CMakeLists.txt index 818c9061..3c2b0582 100644 --- a/src/lib/server/CMakeLists.txt +++ b/src/lib/server/CMakeLists.txt @@ -58,6 +58,7 @@ set(inc ../mt ../net ../synergy + ../../../tools ) if (UNIX) diff --git a/src/lib/synergy/CCryptoStream.cpp b/src/lib/synergy/CCryptoStream.cpp index 6cde52ba..ef181836 100644 --- a/src/lib/synergy/CCryptoStream.cpp +++ b/src/lib/synergy/CCryptoStream.cpp @@ -16,6 +16,9 @@ */ #include "CCryptoStream.h" +#include "CLog.h" +#include +#include // TODO: these are just for testing -- make sure they're gone by release! const byte g_key1[] = "aaaaaaaaaaaaaaa"; @@ -25,8 +28,8 @@ const byte g_iv2[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; using namespace CryptoPP; -CCryptoStream::CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream) : - CStreamFilter(eventQueue, stream, false) +CCryptoStream::CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream, bool adoptStream) : + CStreamFilter(eventQueue, stream, adoptStream) { m_encryption.SetKeyWithIV(g_key1, sizeof(g_key1), g_iv1); m_decryption.SetKeyWithIV(g_key1, sizeof(g_key1), g_iv1); @@ -39,18 +42,55 @@ CCryptoStream::~CCryptoStream() UInt32 CCryptoStream::read(void* out, UInt32 n) { - byte* in = new byte[n]; - int result = getStream()->read(in, n); - m_decryption.ProcessData(static_cast(out), in, n); - delete[] in; + LOG((CLOG_DEBUG4 "crypto: read %i (decrypt)", n)); + + byte* cypher = new byte[n]; + int result = getStream()->read(cypher, n); + if (result == 0) { + // nothing to read. + return 0; + } + + if (result != n) { + LOG((CLOG_ERR "crypto: decrypt failed, only %i of %i bytes", result, n)); + return 0; + } + + logBuffer("cypher", cypher, n); + m_decryption.ProcessData(static_cast(out), cypher, n); + logBuffer("plaintext", static_cast(out), n); + delete[] cypher; return result; } void CCryptoStream::write(const void* in, UInt32 n) { - byte* out = new byte[n]; - m_encryption.ProcessData(out, static_cast(in), n); - getStream()->write(out, n); - delete[] out; + LOG((CLOG_DEBUG4 "crypto: write %i (encrypt)", n)); + + logBuffer("plaintext", static_cast(const_cast(in)), n); + byte* cypher = new byte[n]; + m_encryption.ProcessData(cypher, static_cast(in), n); + logBuffer("cypher", cypher, n); + getStream()->write(cypher, n); + delete[] cypher; +} + +void +CCryptoStream::logBuffer(const char* name, const byte* buf, int length) +{ + if (CLOG->getFilter() < kDEBUG4) { + return; + } + + std::stringstream ss; + ss << "crypto: " << name << ":"; + + char buffer[4]; + for (int i = 0; i < length; i++) { + sprintf(buffer, " %02X", buf[i]); + ss << buffer; + } + + LOG((CLOG_DEBUG4 "%s", ss.str().c_str())); } diff --git a/src/lib/synergy/CCryptoStream.h b/src/lib/synergy/CCryptoStream.h index 3d32d8db..3b1cf0c8 100644 --- a/src/lib/synergy/CCryptoStream.h +++ b/src/lib/synergy/CCryptoStream.h @@ -20,6 +20,7 @@ #include "BasicTypes.h" #include "CStreamFilter.h" #include "cryptopp562/gcm.h" +//#include "cryptopp562/modes.h" #include "cryptopp562/aes.h" //! Bidirectional encrypted stream @@ -28,7 +29,7 @@ Encrypts (on write) and decrypts (on read) to and from an underlying stream. */ class CCryptoStream : public CStreamFilter { public: - CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream); + CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream, bool adoptStream = true); virtual ~CCryptoStream(); //! @name manipulators @@ -50,5 +51,9 @@ public: private: // TODO: allow user to change between GCM/CTR/CFB CryptoPP::GCM::Encryption m_encryption; - CryptoPP::GCM::Decryption m_decryption; + CryptoPP::GCM::Decryption m_decryption; + //CryptoPP::CTR_Mode::Encryption m_encryption; + //CryptoPP::CTR_Mode::Decryption m_decryption; + + void logBuffer(const char* name, const byte* buf, int length); }; diff --git a/src/lib/synergy/CKeyMap.cpp b/src/lib/synergy/CKeyMap.cpp index 63f36efa..6aca0fd4 100644 --- a/src/lib/synergy/CKeyMap.cpp +++ b/src/lib/synergy/CKeyMap.cpp @@ -102,7 +102,7 @@ CKeyMap::addKeyEntry(const KeyItem& item) // add item list entries.push_back(items); - LOG((CLOG_DEBUG3 "add key: %04x %d %03x %04x (%04x %04x %04x)%s", newItem.m_id, newItem.m_group, newItem.m_button, newItem.m_client, newItem.m_required, newItem.m_sensitive, newItem.m_generates, newItem.m_dead ? " dead" : "")); + LOG((CLOG_DEBUG5 "add key: %04x %d %03x %04x (%04x %04x %04x)%s", newItem.m_id, newItem.m_group, newItem.m_button, newItem.m_client, newItem.m_required, newItem.m_sensitive, newItem.m_generates, newItem.m_dead ? " dead" : "")); } void diff --git a/src/test/unittests/Main.cpp b/src/test/unittests/Main.cpp index 58533e4b..dd165045 100644 --- a/src/test/unittests/Main.cpp +++ b/src/test/unittests/Main.cpp @@ -36,7 +36,7 @@ main(int argc, char **argv) arch.init(); CLog log; - log.setFilter(kDEBUG2); + log.setFilter(kDEBUG4); testing::InitGoogleTest(&argc, argv); diff --git a/src/test/unittests/synergy/CCryptoStreamTests.cpp b/src/test/unittests/synergy/CCryptoStreamTests.cpp index f36ec140..2e444b61 100644 --- a/src/test/unittests/synergy/CCryptoStreamTests.cpp +++ b/src/test/unittests/synergy/CCryptoStreamTests.cpp @@ -19,7 +19,7 @@ #include "CCryptoStream.h" #include "CMockStream.h" #include "CMockEventQueue.h" - +#include "CPacketStreamFilter.h" using ::testing::_; using ::testing::Invoke; @@ -27,6 +27,16 @@ using namespace std; void assertWrite(const void* in, UInt32 n); UInt8 mockRead(void* out, UInt32 n); +void write4Read1_mockWrite(const void* in, UInt32 n); +UInt8 write4Read1_mockRead(void* out, UInt32 n); +void write1Read4_mockWrite(const void* in, UInt32 n); +UInt8 write1Read4_mockRead(void* out, UInt32 n); + +UInt8 g_write4Read1_buffer[4]; +UInt32 g_write4Read1_bufferIndex = 0; + +UInt8 g_write1Read4_buffer[4]; +UInt32 g_write1Read4_bufferIndex = 0; TEST(CCryptoTests, write) { @@ -47,7 +57,7 @@ TEST(CCryptoTests, write) EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(1); EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1); - CCryptoStream cs(eventQueue, &innerStream); + CCryptoStream cs(eventQueue, &innerStream, false); cs.write(buffer, size); } @@ -63,7 +73,7 @@ TEST(CCryptoTests, read) EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(1); EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1); - CCryptoStream cs(eventQueue, &innerStream); + CCryptoStream cs(eventQueue, &innerStream, false); const UInt32 size = 4; UInt8* buffer = new UInt8[size]; @@ -75,6 +85,73 @@ TEST(CCryptoTests, read) EXPECT_EQ('N', buffer[3]); } +TEST(CCryptoTests, write4Read1) +{ + CMockEventQueue eventQueue; + CMockStream innerStream(eventQueue); + + ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write4Read1_mockWrite)); + ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(write4Read1_mockRead)); + EXPECT_CALL(innerStream, write(_, _)).Times(4); + EXPECT_CALL(innerStream, read(_, _)).Times(1); + EXPECT_CALL(innerStream, getEventTarget()).Times(6); + EXPECT_CALL(eventQueue, removeHandlers(_)).Times(2); + EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(2); + EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); + + CCryptoStream cs1(eventQueue, &innerStream, false); + CCryptoStream cs2(eventQueue, &innerStream, false); + + cs1.write("a", 1); + cs1.write("b", 1); + cs1.write("c", 1); + cs1.write("d", 1); + + UInt8 buffer[4]; + cs2.read(buffer, 4); + + EXPECT_EQ('a', buffer[0]); + EXPECT_EQ('b', buffer[1]); + EXPECT_EQ('c', buffer[2]); + EXPECT_EQ('d', buffer[3]); +} + +TEST(CCryptoTests, write1Read4) +{ + CMockEventQueue eventQueue; + CMockStream innerStream(eventQueue); + + ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write1Read4_mockWrite)); + ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(write1Read4_mockRead)); + EXPECT_CALL(innerStream, write(_, _)).Times(1); + EXPECT_CALL(innerStream, read(_, _)).Times(4); + EXPECT_CALL(innerStream, getEventTarget()).Times(6); + EXPECT_CALL(eventQueue, removeHandlers(_)).Times(2); + EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(2); + EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); + + CCryptoStream cs1(eventQueue, &innerStream, false); + CCryptoStream cs2(eventQueue, &innerStream, false); + + UInt8 bufferIn[4]; + bufferIn[0] = 'a'; + bufferIn[1] = 'b'; + bufferIn[2] = 'c'; + bufferIn[3] = 'd'; + cs1.write(bufferIn, 4); + + UInt8 bufferOut[4]; + cs2.read(&bufferOut[0], 1); + cs2.read(&bufferOut[1], 1); + cs2.read(&bufferOut[2], 1); + cs2.read(&bufferOut[3], 1); + + EXPECT_EQ('a', bufferOut[0]); + EXPECT_EQ('b', bufferOut[1]); + EXPECT_EQ('c', bufferOut[2]); + EXPECT_EQ('d', bufferOut[3]); +} + void assertWrite(const void* in, UInt32 n) { @@ -95,3 +172,40 @@ mockRead(void* out, UInt32 n) buffer[3] = 237; return n; } + +void +write4Read1_mockWrite(const void* in, UInt32 n) +{ + UInt8* buffer = static_cast(const_cast(in)); + g_write4Read1_buffer[g_write4Read1_bufferIndex++] = buffer[0]; +} + +UInt8 +write4Read1_mockRead(void* out, UInt32 n) +{ + UInt8* buffer = static_cast(out); + buffer[0] = g_write4Read1_buffer[0]; + buffer[1] = g_write4Read1_buffer[1]; + buffer[2] = g_write4Read1_buffer[2]; + buffer[3] = g_write4Read1_buffer[3]; + return 4; +} + +void +write1Read4_mockWrite(const void* in, UInt32 n) +{ + UInt8* buffer = static_cast(const_cast(in)); + g_write1Read4_buffer[0] = buffer[0]; + g_write1Read4_buffer[1] = buffer[1]; + g_write1Read4_buffer[2] = buffer[2]; + g_write1Read4_buffer[3] = buffer[3]; +} + +UInt8 +write1Read4_mockRead(void* out, UInt32 n) +{ + UInt8* buffer = static_cast(out); + buffer[0] = g_write1Read4_buffer[g_write1Read4_bufferIndex++]; + return 1; +} +