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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -34,6 +34,7 @@
#include <cstdlib>
#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();

View File

@ -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

View File

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

View File

@ -29,6 +29,7 @@
#include "XBase.h"
#include <memory>
#include <cstring>
#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),

View File

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

View File

@ -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"));
}

View File

@ -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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,6 +16,9 @@
*/
#include "CCryptoStream.h"
#include "CLog.h"
#include <sstream>
#include <string>
// 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<byte*>(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<byte*>(out), cypher, n);
logBuffer("plaintext", static_cast<byte*>(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<const byte*>(in), n);
getStream()->write(out, n);
delete[] out;
LOG((CLOG_DEBUG4 "crypto: write %i (encrypt)", n));
logBuffer("plaintext", static_cast<byte*>(const_cast<void*>(in)), n);
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 "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<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
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

View File

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

View File

@ -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<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;
}