implemented crypto stream, with some extra unit tests

This commit is contained in:
Nick Bolton 2013-04-05 16:33:48 +00:00
parent 728ad02d61
commit 0a69c28ac5
21 changed files with 217 additions and 32 deletions

View File

@ -62,7 +62,7 @@ endif()
include_directories(${inc}) include_directories(${inc})
add_executable(synergyc ${src}) add_executable(synergyc ${src})
target_link_libraries(synergyc 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) if (CONF_CPACK)
install(TARGETS install(TARGETS

View File

@ -49,7 +49,7 @@ if (VNC_SUPPORT)
endif() endif()
target_link_libraries(synergyd 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) if (CONF_CPACK)
install(TARGETS install(TARGETS

View File

@ -64,7 +64,7 @@ else()
endif() endif()
target_link_libraries(synergyp 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) if (CONF_CPACK)
install(TARGETS install(TARGETS

View File

@ -62,7 +62,7 @@ endif()
include_directories(${inc}) include_directories(${inc})
add_executable(synergys ${src}) add_executable(synergys ${src})
target_link_libraries(synergys 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) if (CONF_CPACK)
install(TARGETS install(TARGETS

View File

@ -34,6 +34,7 @@
#include <cstdlib> #include <cstdlib>
#include "CArch.h" #include "CArch.h"
#include "IPlatformScreen.h" #include "IPlatformScreen.h"
#include "CCryptoStream.h"
// //
// CClient // CClient
@ -147,6 +148,10 @@ CClient::connect()
} }
m_stream = new CPacketStreamFilter(m_stream, true); m_stream = new CPacketStreamFilter(m_stream, true);
if (s_cryptoEnabled) {
m_stream = new CCryptoStream(*EVENTQUEUE, m_stream, true);
}
// connect // connect
LOG((CLOG_DEBUG1 "connecting to server")); LOG((CLOG_DEBUG1 "connecting to server"));
setupConnecting(); setupConnecting();

View File

@ -208,13 +208,13 @@ private:
IClipboard::Time m_timeClipboard[kClipboardEnd]; IClipboard::Time m_timeClipboard[kClipboardEnd];
CString m_dataClipboard[kClipboardEnd]; CString m_dataClipboard[kClipboardEnd];
IEventQueue& m_eventQueue; IEventQueue& m_eventQueue;
static CEvent::Type s_connectedEvent;
static CEvent::Type s_connectionFailedEvent;
static CEvent::Type s_disconnectedEvent;
protected:
bool m_mock; 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 #endif

View File

@ -36,6 +36,7 @@ set(inc
../mt ../mt
../net ../net
../synergy ../synergy
../../../tools
) )
if (UNIX) if (UNIX)

View File

@ -29,6 +29,7 @@
#include "XBase.h" #include "XBase.h"
#include <memory> #include <memory>
#include <cstring> #include <cstring>
#include "CCryptoStream.h"
// //
// CServerProxy // CServerProxy
@ -37,6 +38,7 @@
CServerProxy::CServerProxy(CClient* client, synergy::IStream* stream, IEventQueue& eventQueue) : CServerProxy::CServerProxy(CClient* client, synergy::IStream* stream, IEventQueue& eventQueue) :
m_client(client), m_client(client),
m_stream(stream), m_stream(stream),
m_cryptoStream(NULL),
m_seqNum(0), m_seqNum(0),
m_compressMouse(false), m_compressMouse(false),
m_compressMouseRelative(false), m_compressMouseRelative(false),

View File

@ -30,6 +30,7 @@ class CEventQueueTimer;
class IClipboard; class IClipboard;
namespace synergy { class IStream; } namespace synergy { class IStream; }
class IEventQueue; class IEventQueue;
class CCryptoStream;
//! Proxy for server //! Proxy for server
/*! /*!
@ -105,7 +106,8 @@ private:
typedef EResult (CServerProxy::*MessageParser)(const UInt8*); typedef EResult (CServerProxy::*MessageParser)(const UInt8*);
CClient* m_client; CClient* m_client;
synergy::IStream* m_stream; synergy::IStream* m_stream;
CCryptoStream* m_cryptoStream;
UInt32 m_seqNum; UInt32 m_seqNum;

View File

@ -1499,7 +1499,7 @@ COSXScreen::updateScreenShape()
// We want to notify the peer screen whether we are primary screen or not // We want to notify the peer screen whether we are primary screen or not
sendEvent(getShapeChangedEvent()); 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, m_x, m_y, m_w, m_h, displayCount,
(displayCount == 1) ? "display" : "displays")); (displayCount == 1) ? "display" : "displays"));
} }

View File

@ -28,6 +28,7 @@
#include "CLog.h" #include "CLog.h"
#include "IEventQueue.h" #include "IEventQueue.h"
#include "TMethodEventJob.h" #include "TMethodEventJob.h"
#include "CCryptoStream.h"
// //
// CClientListener // CClientListener
@ -143,6 +144,10 @@ CClientListener::handleClientConnecting(const CEvent&, void*)
stream = m_streamFilterFactory->create(stream, true); stream = m_streamFilterFactory->create(stream, true);
} }
stream = new CPacketStreamFilter(stream, true); stream = new CPacketStreamFilter(stream, true);
if (s_cryptoEnabled) {
stream = new CCryptoStream(*EVENTQUEUE, stream, true);
}
assert(m_server != NULL); assert(m_server != NULL);

View File

@ -84,6 +84,8 @@ private:
static CEvent::Type s_connectedEvent; static CEvent::Type s_connectedEvent;
CServer* m_server; CServer* m_server;
static const bool s_cryptoEnabled = true;
}; };
#endif #endif

View File

@ -35,7 +35,6 @@ CClientProxy::CClientProxy(const CString& name, synergy::IStream* stream) :
CBaseClientProxy(name), CBaseClientProxy(name),
m_stream(stream) m_stream(stream)
{ {
// do nothing
} }
CClientProxy::~CClientProxy() CClientProxy::~CClientProxy()

View File

@ -25,6 +25,8 @@
namespace synergy { class IStream; } namespace synergy { class IStream; }
const int g_encryptionEnabled = true;
//! Generic proxy for client //! Generic proxy for client
class CClientProxy : public CBaseClientProxy { class CClientProxy : public CBaseClientProxy {
public: public:
@ -47,9 +49,16 @@ public:
//! @name accessors //! @name accessors
//@{ //@{
//! Get stream (unmodified)
/*!
Returns the original stream passed to the c'tor.
*/
synergy::IStream* getStreamUnmodified() const;
//! Get stream //! 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; synergy::IStream* getStream() const;

View File

@ -76,7 +76,7 @@ private:
void handleReady(const CEvent&, void*); void handleReady(const CEvent&, void*);
private: private:
synergy::IStream* m_stream; synergy::IStream* m_stream;
CEventQueueTimer* m_timer; CEventQueueTimer* m_timer;
CClientProxy* m_proxy; CClientProxy* m_proxy;
bool m_ready; bool m_ready;

View File

@ -58,6 +58,7 @@ set(inc
../mt ../mt
../net ../net
../synergy ../synergy
../../../tools
) )
if (UNIX) if (UNIX)

View File

@ -16,6 +16,9 @@
*/ */
#include "CCryptoStream.h" #include "CCryptoStream.h"
#include "CLog.h"
#include <sstream>
#include <string>
// TODO: these are just for testing -- make sure they're gone by release! // TODO: these are just for testing -- make sure they're gone by release!
const byte g_key1[] = "aaaaaaaaaaaaaaa"; const byte g_key1[] = "aaaaaaaaaaaaaaa";
@ -25,8 +28,8 @@ const byte g_iv2[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
using namespace CryptoPP; using namespace CryptoPP;
CCryptoStream::CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream) : CCryptoStream::CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream, bool adoptStream) :
CStreamFilter(eventQueue, stream, false) CStreamFilter(eventQueue, stream, adoptStream)
{ {
m_encryption.SetKeyWithIV(g_key1, sizeof(g_key1), g_iv1); m_encryption.SetKeyWithIV(g_key1, sizeof(g_key1), g_iv1);
m_decryption.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 UInt32
CCryptoStream::read(void* out, UInt32 n) CCryptoStream::read(void* out, UInt32 n)
{ {
byte* in = new byte[n]; LOG((CLOG_DEBUG4 "crypto: read %i (decrypt)", n));
int result = getStream()->read(in, n);
m_decryption.ProcessData(static_cast<byte*>(out), in, n); byte* cypher = new byte[n];
delete[] in; 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<byte*>(out), cypher, n);
logBuffer("plaintext", static_cast<byte*>(out), n);
delete[] cypher;
return result; return result;
} }
void void
CCryptoStream::write(const void* in, UInt32 n) CCryptoStream::write(const void* in, UInt32 n)
{ {
byte* out = new byte[n]; LOG((CLOG_DEBUG4 "crypto: write %i (encrypt)", n));
m_encryption.ProcessData(out, static_cast<const byte*>(in), n);
getStream()->write(out, n); logBuffer("plaintext", static_cast<byte*>(const_cast<void*>(in)), n);
delete[] out; byte* cypher = new byte[n];
m_encryption.ProcessData(cypher, static_cast<const byte*>(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()));
} }

View File

@ -20,6 +20,7 @@
#include "BasicTypes.h" #include "BasicTypes.h"
#include "CStreamFilter.h" #include "CStreamFilter.h"
#include "cryptopp562/gcm.h" #include "cryptopp562/gcm.h"
//#include "cryptopp562/modes.h"
#include "cryptopp562/aes.h" #include "cryptopp562/aes.h"
//! Bidirectional encrypted stream //! Bidirectional encrypted stream
@ -28,7 +29,7 @@ Encrypts (on write) and decrypts (on read) to and from an underlying stream.
*/ */
class CCryptoStream : public CStreamFilter { class CCryptoStream : public CStreamFilter {
public: public:
CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream); CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream, bool adoptStream = true);
virtual ~CCryptoStream(); virtual ~CCryptoStream();
//! @name manipulators //! @name manipulators
@ -50,5 +51,9 @@ public:
private: private:
// TODO: allow user to change between GCM/CTR/CFB // TODO: allow user to change between GCM/CTR/CFB
CryptoPP::GCM<CryptoPP::AES>::Encryption m_encryption; CryptoPP::GCM<CryptoPP::AES>::Encryption m_encryption;
CryptoPP::GCM<CryptoPP::AES>::Decryption m_decryption; CryptoPP::GCM<CryptoPP::AES>::Decryption m_decryption;
//CryptoPP::CTR_Mode<CryptoPP::AES>::Encryption m_encryption;
//CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption m_decryption;
void logBuffer(const char* name, const byte* buf, int length);
}; };

View File

@ -102,7 +102,7 @@ CKeyMap::addKeyEntry(const KeyItem& item)
// add item list // add item list
entries.push_back(items); 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 void

View File

@ -36,7 +36,7 @@ main(int argc, char **argv)
arch.init(); arch.init();
CLog log; CLog log;
log.setFilter(kDEBUG2); log.setFilter(kDEBUG4);
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);

View File

@ -19,7 +19,7 @@
#include "CCryptoStream.h" #include "CCryptoStream.h"
#include "CMockStream.h" #include "CMockStream.h"
#include "CMockEventQueue.h" #include "CMockEventQueue.h"
#include "CPacketStreamFilter.h"
using ::testing::_; using ::testing::_;
using ::testing::Invoke; using ::testing::Invoke;
@ -27,6 +27,16 @@ using namespace std;
void assertWrite(const void* in, UInt32 n); void assertWrite(const void* in, UInt32 n);
UInt8 mockRead(void* out, 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) TEST(CCryptoTests, write)
{ {
@ -47,7 +57,7 @@ TEST(CCryptoTests, write)
EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(1); EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(1);
EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1); EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1);
CCryptoStream cs(eventQueue, &innerStream); CCryptoStream cs(eventQueue, &innerStream, false);
cs.write(buffer, size); cs.write(buffer, size);
} }
@ -63,7 +73,7 @@ TEST(CCryptoTests, read)
EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(1); EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(1);
EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1); EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1);
CCryptoStream cs(eventQueue, &innerStream); CCryptoStream cs(eventQueue, &innerStream, false);
const UInt32 size = 4; const UInt32 size = 4;
UInt8* buffer = new UInt8[size]; UInt8* buffer = new UInt8[size];
@ -75,6 +85,73 @@ TEST(CCryptoTests, read)
EXPECT_EQ('N', buffer[3]); 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 void
assertWrite(const void* in, UInt32 n) assertWrite(const void* in, UInt32 n)
{ {
@ -95,3 +172,40 @@ mockRead(void* out, UInt32 n)
buffer[3] = 237; buffer[3] = 237;
return n; return n;
} }
void
write4Read1_mockWrite(const void* in, UInt32 n)
{
UInt8* buffer = static_cast<UInt8*>(const_cast<void*>(in));
g_write4Read1_buffer[g_write4Read1_bufferIndex++] = buffer[0];
}
UInt8
write4Read1_mockRead(void* out, UInt32 n)
{
UInt8* buffer = static_cast<UInt8*>(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<UInt8*>(const_cast<void*>(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<UInt8*>(out);
buffer[0] = g_write1Read4_buffer[g_write1Read4_bufferIndex++];
return 1;
}