Jerry's patch for password hash and custom mode (via command line).

This commit is contained in:
Nick Bolton 2013-04-09 21:57:07 +00:00
parent 7010de9cc4
commit 880819fab7
20 changed files with 557 additions and 108 deletions

View File

@ -35,10 +35,6 @@
#include "CArch.h" #include "CArch.h"
#include "IPlatformScreen.h" #include "IPlatformScreen.h"
#include "CCryptoStream.h" #include "CCryptoStream.h"
// TODO: these are just for testing -- make sure they're gone by release!
const byte g_key[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const byte g_iv[] = "aaaaaaaaaaaaaaa";
// //
// CClient // CClient
@ -52,7 +48,8 @@ CClient::CClient(IEventQueue* eventQueue,
const CString& name, const CNetworkAddress& address, const CString& name, const CNetworkAddress& address,
ISocketFactory* socketFactory, ISocketFactory* socketFactory,
IStreamFilterFactory* streamFilterFactory, IStreamFilterFactory* streamFilterFactory,
CScreen* screen) : CScreen* screen,
const CCryptoOptions& crypto) :
m_mock(false), m_mock(false),
m_name(name), m_name(name),
m_serverAddress(address), m_serverAddress(address),
@ -67,7 +64,8 @@ CClient::CClient(IEventQueue* eventQueue,
m_suspended(false), m_suspended(false),
m_connectOnResume(false), m_connectOnResume(false),
m_eventQueue(eventQueue), m_eventQueue(eventQueue),
m_cryptoStream(NULL) m_cryptoStream(NULL),
m_crypto(crypto)
{ {
assert(m_socketFactory != NULL); assert(m_socketFactory != NULL);
assert(m_screen != NULL); assert(m_screen != NULL);
@ -148,9 +146,9 @@ CClient::connect()
} }
m_stream = new CPacketStreamFilter(m_stream, true); m_stream = new CPacketStreamFilter(m_stream, true);
if (s_cryptoEnabled) { if (m_crypto.m_mode != kDisabled) {
m_cryptoStream = new CCryptoStream(m_eventQueue, m_stream, true); m_cryptoStream = new CCryptoStream(
m_cryptoStream->setKeyWithIv(g_key, sizeof(g_key), g_iv); EVENTQUEUE, m_stream, m_crypto, true);
m_stream = m_cryptoStream; m_stream = m_cryptoStream;
} }

View File

@ -23,6 +23,7 @@
#include "IClipboard.h" #include "IClipboard.h"
#include "CNetworkAddress.h" #include "CNetworkAddress.h"
#include "INode.h" #include "INode.h"
#include "CCryptoOptions.h"
class CEventQueueTimer; class CEventQueueTimer;
class CScreen; class CScreen;
@ -57,7 +58,8 @@ public:
const CString& name, const CNetworkAddress& address, const CString& name, const CNetworkAddress& address,
ISocketFactory* socketFactory, ISocketFactory* socketFactory,
IStreamFilterFactory* streamFilterFactory, IStreamFilterFactory* streamFilterFactory,
CScreen* screen); CScreen* screen,
const CCryptoOptions& crypto);
~CClient(); ~CClient();
#ifdef TEST_ENV #ifdef TEST_ENV
@ -217,12 +219,11 @@ private:
CString m_dataClipboard[kClipboardEnd]; CString m_dataClipboard[kClipboardEnd];
IEventQueue* m_eventQueue; IEventQueue* m_eventQueue;
CCryptoStream* m_cryptoStream; CCryptoStream* m_cryptoStream;
CCryptoOptions m_crypto;
static CEvent::Type s_connectedEvent; static CEvent::Type s_connectedEvent;
static CEvent::Type s_connectionFailedEvent; static CEvent::Type s_connectionFailedEvent;
static CEvent::Type s_disconnectedEvent; static CEvent::Type s_disconnectedEvent;
static const int s_cryptoEnabled = true;
}; };
#endif #endif

View File

@ -29,7 +29,8 @@
#include "IEventQueue.h" #include "IEventQueue.h"
#include "TMethodEventJob.h" #include "TMethodEventJob.h"
#include "CCryptoStream.h" #include "CCryptoStream.h"
#include "CCryptoOptions.h"
// 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_key[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; const byte g_key[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const byte g_iv[] = "aaaaaaaaaaaaaaa"; const byte g_iv[] = "aaaaaaaaaaaaaaa";
@ -42,10 +43,12 @@ CEvent::Type CClientListener::s_connectedEvent = CEvent::kUnknown;
CClientListener::CClientListener(const CNetworkAddress& address, CClientListener::CClientListener(const CNetworkAddress& address,
ISocketFactory* socketFactory, ISocketFactory* socketFactory,
IStreamFilterFactory* streamFilterFactory) : IStreamFilterFactory* streamFilterFactory,
const CCryptoOptions& crypto) :
m_socketFactory(socketFactory), m_socketFactory(socketFactory),
m_streamFilterFactory(streamFilterFactory), m_streamFilterFactory(streamFilterFactory),
m_server(NULL) m_server(NULL),
m_crypto(crypto)
{ {
assert(m_socketFactory != NULL); assert(m_socketFactory != NULL);
@ -149,9 +152,9 @@ CClientListener::handleClientConnecting(const CEvent&, void*)
} }
stream = new CPacketStreamFilter(stream, true); stream = new CPacketStreamFilter(stream, true);
if (s_cryptoEnabled) { if (m_crypto.m_mode != kDisabled) {
CCryptoStream* cryptoStream = new CCryptoStream(EVENTQUEUE, stream, true); CCryptoStream* cryptoStream = new CCryptoStream(
cryptoStream->setKeyWithIv(g_key, sizeof(g_key), g_iv); EVENTQUEUE, stream, m_crypto, true);
stream = cryptoStream; stream = cryptoStream;
} }

View File

@ -23,6 +23,7 @@
#include "CEvent.h" #include "CEvent.h"
#include "stddeque.h" #include "stddeque.h"
#include "stdset.h" #include "stdset.h"
#include "CCryptoOptions.h"
class CClientProxy; class CClientProxy;
class CClientProxyUnknown; class CClientProxyUnknown;
@ -36,7 +37,9 @@ class CClientListener {
public: public:
// The factories are adopted. // The factories are adopted.
CClientListener(const CNetworkAddress&, CClientListener(const CNetworkAddress&,
ISocketFactory*, IStreamFilterFactory*); ISocketFactory*,
IStreamFilterFactory*,
const CCryptoOptions& crypto);
~CClientListener(); ~CClientListener();
//! @name manipulators //! @name manipulators
@ -81,11 +84,10 @@ private:
IStreamFilterFactory* m_streamFilterFactory; IStreamFilterFactory* m_streamFilterFactory;
CNewClients m_newClients; CNewClients m_newClients;
CWaitingClients m_waitingClients; CWaitingClients m_waitingClients;
CServer* m_server;
CCryptoOptions m_crypto;
static CEvent::Type s_connectedEvent; static CEvent::Type s_connectedEvent;
CServer* m_server;
static const bool s_cryptoEnabled = true;
}; };
#endif #endif

View File

@ -161,6 +161,14 @@ CApp::parseArg(const int& argc, const char* const* argv, int& i)
// HACK: stop error happening when using portable (synergyp) // HACK: stop error happening when using portable (synergyp)
} }
else if (isArg(i, argc, argv, NULL, "--crypto-pass")) {
argsBase().m_crypto.m_pass = argv[++i];
}
else if (isArg(i, argc, argv, NULL, "--crypto-mode")) {
argsBase().m_crypto.setMode(argv[++i]);
}
#if VNC_SUPPORT #if VNC_SUPPORT
else if (isArg(i, argc, argv, NULL, "--vnc")) { else if (isArg(i, argc, argv, NULL, "--vnc")) {
argsBase().m_enableVnc = true; argsBase().m_enableVnc = true;

View File

@ -20,6 +20,7 @@
#include "CString.h" #include "CString.h"
#include "CGameDevice.h" #include "CGameDevice.h"
#include "CCryptoOptions.h"
class CArgsBase { class CArgsBase {
public: public:
@ -37,6 +38,7 @@ public:
bool m_disableTray; bool m_disableTray;
bool m_enableVnc; bool m_enableVnc;
bool m_enableIpc; bool m_enableIpc;
CCryptoOptions m_crypto;
#if SYSAPI_WIN32 #if SYSAPI_WIN32
bool m_debugServiceWait; bool m_debugServiceWait;
bool m_pauseOnExit; bool m_pauseOnExit;

View File

@ -393,10 +393,10 @@ CClientApp::handleClientDisconnected(const CEvent&, void*)
CClient* CClient*
CClientApp::openClient(const CString& name, const CNetworkAddress& address, CScreen* screen) CClientApp::openClient(const CString& name, const CNetworkAddress& address, CScreen* screen, const CCryptoOptions& crypto)
{ {
CClient* client = new CClient( CClient* client = new CClient(
EVENTQUEUE, name, address, new CTCPSocketFactory, NULL, screen); EVENTQUEUE, name, address, new CTCPSocketFactory, NULL, screen, crypto);
try { try {
EVENTQUEUE->adoptHandler( EVENTQUEUE->adoptHandler(
@ -454,7 +454,7 @@ CClientApp::startClient()
if (s_clientScreen == NULL) { if (s_clientScreen == NULL) {
clientScreen = openClientScreen(); clientScreen = openClientScreen();
s_client = openClient(args().m_name, s_client = openClient(args().m_name,
*args().m_serverAddress, clientScreen); *args().m_serverAddress, clientScreen, args().m_crypto);
s_clientScreen = clientScreen; s_clientScreen = clientScreen;
LOG((CLOG_NOTE "started client")); LOG((CLOG_NOTE "started client"));
} }

View File

@ -74,7 +74,7 @@ public:
void handleClientConnected(const CEvent&, void*); void handleClientConnected(const CEvent&, void*);
void handleClientFailed(const CEvent& e, void*); void handleClientFailed(const CEvent& e, void*);
void handleClientDisconnected(const CEvent&, void*); void handleClientDisconnected(const CEvent&, void*);
CClient* openClient(const CString& name, const CNetworkAddress& address, CScreen* screen); CClient* openClient(const CString& name, const CNetworkAddress& address, CScreen* screen, const CCryptoOptions& crypto);
void closeClient(CClient* client); void closeClient(CClient* client);
bool startClient(); bool startClient();
void stopClient(); void stopClient();

View File

@ -0,0 +1,218 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CCryptoMode.h"
using namespace CryptoPP;
CCryptoMode::CCryptoMode(ECryptoMode mode, bool encryption) :
m_mode(mode),
m_crypto(NULL),
m_encryption(encryption)
{
if (m_encryption) {
switch (m_mode) {
case kOfb:
m_crypto = new COfbModeEnc;
break;
case kCfb:
m_crypto = new CCfbModeEnc;
break;
case kCtr:
m_crypto = new CCtrModeEnc;
break;
case kGcm:
m_crypto = new CGcmModeEnc;
break;
case kDisabled:
break;
default:
throw std::exception("crypto mode not set");
}
}
else {
switch (m_mode) {
case kOfb:
m_crypto = new COfbModeDec;
break;
case kCfb:
m_crypto = new CCfbModeDec;
break;
case kCtr:
m_crypto = new CCtrModeDec;
break;
case kGcm:
m_crypto = new CGcmModeDec;
break;
case kDisabled:
break;
default:
throw std::exception("crypto mode not set");
}
}
}
CCryptoMode::~CCryptoMode()
{
if (m_crypto == NULL) {
return;
}
if (m_encryption) {
switch (m_mode) {
case kOfb:
delete reinterpret_cast<COfbModeEnc*>(m_crypto);
break;
case kCfb:
delete reinterpret_cast<CCfbModeEnc*>(m_crypto);
break;
case kCtr:
delete reinterpret_cast<CCtrModeEnc*>(m_crypto);
break;
case kGcm:
delete reinterpret_cast<CGcmModeEnc*>(m_crypto);
break;
}
}
else {
switch (m_mode) {
case kOfb:
delete reinterpret_cast<COfbModeDec*>(m_crypto);
break;
case kCfb:
delete reinterpret_cast<CCfbModeDec*>(m_crypto);
break;
case kCtr:
delete reinterpret_cast<CCtrModeDec*>(m_crypto);
break;
case kGcm:
delete reinterpret_cast<CGcmModeDec*>(m_crypto);
break;
}
}
}
void
CCryptoMode::processData(byte* out, const byte* in, size_t length)
{
if (m_crypto == NULL) {
return;
}
if (m_encryption) {
switch (m_mode) {
case kOfb:
reinterpret_cast<COfbModeEnc*>(m_crypto)->ProcessData(out, in, length);
break;
case kCfb:
reinterpret_cast<CCfbModeEnc*>(m_crypto)->ProcessData(out, in, length);
break;
case kCtr:
reinterpret_cast<CCtrModeEnc*>(m_crypto)->ProcessData(out, in, length);
break;
case kGcm:
reinterpret_cast<CGcmModeEnc*>(m_crypto)->ProcessData(out, in, length);
break;
}
}
else {
switch (m_mode) {
case kOfb:
reinterpret_cast<COfbModeDec*>(m_crypto)->ProcessData(out, in, length);
break;
case kCfb:
reinterpret_cast<CCfbModeDec*>(m_crypto)->ProcessData(out, in, length);
break;
case kCtr:
reinterpret_cast<CCtrModeDec*>(m_crypto)->ProcessData(out, in, length);
break;
case kGcm:
reinterpret_cast<CGcmModeDec*>(m_crypto)->ProcessData(out, in, length);
break;
}
}
}
void
CCryptoMode::setKeyWithIv(const byte* key, size_t length, const byte* iv)
{
if (m_crypto == NULL) {
return;
}
if (m_encryption) {
switch (m_mode) {
case kOfb:
reinterpret_cast<COfbModeEnc*>(m_crypto)->SetKeyWithIV(key, length, iv);
break;
case kCfb:
reinterpret_cast<CCfbModeEnc*>(m_crypto)->SetKeyWithIV(key, length, iv);
break;
case kCtr:
reinterpret_cast<CCtrModeEnc*>(m_crypto)->SetKeyWithIV(key, length, iv);
break;
case kGcm:
reinterpret_cast<CGcmModeEnc*>(m_crypto)->SetKeyWithIV(key, length, iv);
break;
}
}
else {
switch (m_mode) {
case kOfb:
reinterpret_cast<COfbModeDec*>(m_crypto)->SetKeyWithIV(key, length, iv);
break;
case kCfb:
reinterpret_cast<CCfbModeDec*>(m_crypto)->SetKeyWithIV(key, length, iv);
break;
case kCtr:
reinterpret_cast<CCtrModeDec*>(m_crypto)->SetKeyWithIV(key, length, iv);
break;
case kGcm:
reinterpret_cast<CGcmModeDec*>(m_crypto)->SetKeyWithIV(key, length, iv);
break;
}
}
}

View File

@ -0,0 +1,58 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cryptopp562/gcm.h>
#include <cryptopp562/modes.h>
#include <cryptopp562/aes.h>
#include "ECryptoMode.h"
#include "CString.h"
//! Encapsulation of modes
/*!
Polymorphism is tricky in Crypto++, so we encapsulate all crypto modes
and switch based on an enum for ctor, dtor and all functions.
*/
class CCryptoMode {
public:
CCryptoMode(ECryptoMode mode, bool encryption = true);
~CCryptoMode();
//! Encrypt or decrypt data
void processData(byte* out, const byte* in, size_t length);
//! Variable length key and initialization vector
void setKeyWithIv(const byte* key, size_t length, const byte* iv);
private:
typedef CryptoPP::OFB_Mode<CryptoPP::AES>::Encryption COfbModeEnc;
typedef CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption CCfbModeEnc;
typedef CryptoPP::CTR_Mode<CryptoPP::AES>::Encryption CCtrModeEnc;
typedef CryptoPP::GCM<CryptoPP::AES>::Encryption CGcmModeEnc;
typedef CryptoPP::OFB_Mode<CryptoPP::AES>::Decryption COfbModeDec;
typedef CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption CCfbModeDec;
typedef CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption CCtrModeDec;
typedef CryptoPP::GCM<CryptoPP::AES>::Decryption CGcmModeDec;
static CCryptoMode::ECryptoMode parseMode(CString& mode);
ECryptoMode m_mode;
void* m_crypto;
bool m_encryption;
};

View File

@ -0,0 +1,53 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CCryptoOptions.h"
CCryptoOptions::CCryptoOptions(
const CString& modeString,
const CString& pass) :
m_mode(parseMode(modeString)),
m_pass(pass)
{
}
void
CCryptoOptions::setMode(CString modeString)
{
m_modeString = modeString;
m_mode = parseMode(modeString);
}
ECryptoMode
CCryptoOptions::parseMode(CString modeString)
{
if (modeString == "ofb") {
return kOfb;
}
else if (modeString == "cfb") {
return kCfb;
}
else if (modeString == "ctr") {
return kCtr;
}
else if (modeString == "gcm") {
return kGcm;
}
else {
throw std::exception("invalid crypto mode");
}
}

View File

@ -0,0 +1,38 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "CString.h"
#include "ECryptoMode.h"
//! Encapsulates basic crypto options
class CCryptoOptions {
public:
CCryptoOptions() : m_mode(kDisabled) { }
CCryptoOptions(const CString& modeString, const CString& pass);
//! Return enum for mode string
static ECryptoMode parseMode(CString modeString);
//! Parse and set mode string
void setMode(CString modeString);
CString m_pass;
ECryptoMode m_mode;
CString m_modeString;
};

View File

@ -19,18 +19,36 @@
#include "CLog.h" #include "CLog.h"
#include <sstream> #include <sstream>
#include <string> #include <string>
#include "CCryptoOptions.h"
using namespace CryptoPP; using namespace CryptoPP;
using namespace synergy::crypto;
CCryptoStream::CCryptoStream(IEventQueue* eventQueue, synergy::IStream* stream, bool adoptStream) : CCryptoStream::CCryptoStream(
IEventQueue* eventQueue,
synergy::IStream* stream,
const CCryptoOptions& options,
bool adoptStream) :
CStreamFilter(eventQueue, stream, adoptStream), CStreamFilter(eventQueue, stream, adoptStream),
m_key(NULL), m_key(NULL),
m_keyLength(0) m_encryption(options.m_mode, true),
m_decryption(options.m_mode, false)
{ {
LOG((CLOG_INFO "crypto mode: %s", options.m_modeString.c_str()));
m_key = new byte[kKeyLength];
if (!options.m_pass.empty()) {
createKey(m_key, options.m_pass, kKeyLength, options.m_pass.length());
byte iv[CRYPTO_IV_SIZE];
createKey(iv, options.m_pass, CRYPTO_IV_SIZE, options.m_pass.length() * 2);
setIv(iv);
}
} }
CCryptoStream::~CCryptoStream() CCryptoStream::~CCryptoStream()
{ {
delete[] m_key;
} }
UInt32 UInt32
@ -52,7 +70,7 @@ CCryptoStream::read(void* out, UInt32 n)
} }
logBuffer("cypher", cypher, n); logBuffer("cypher", cypher, n);
m_decryption.ProcessData(static_cast<byte*>(out), cypher, n); m_decryption.processData(static_cast<byte*>(out), cypher, n);
logBuffer("plaintext", static_cast<byte*>(out), n); logBuffer("plaintext", static_cast<byte*>(out), n);
delete[] cypher; delete[] cypher;
return result; return result;
@ -66,23 +84,29 @@ CCryptoStream::write(const void* in, UInt32 n)
logBuffer("plaintext", static_cast<byte*>(const_cast<void*>(in)), n); logBuffer("plaintext", static_cast<byte*>(const_cast<void*>(in)), n);
byte* cypher = new byte[n]; byte* cypher = new byte[n];
m_encryption.ProcessData(cypher, static_cast<const byte*>(in), n); m_encryption.processData(cypher, static_cast<const byte*>(in), n);
logBuffer("cypher", cypher, n); logBuffer("cypher", cypher, n);
getStream()->write(cypher, n); getStream()->write(cypher, n);
delete[] cypher; delete[] cypher;
} }
void void
CCryptoStream::setKeyWithIv(const byte* key, size_t length, const byte* iv) CCryptoStream::createKey(byte* out, const CString& password, UInt8 keyLength, UInt8 hashCount)
{ {
logBuffer("iv", key, length); assert(keyLength <= SHA256::DIGESTSIZE);
logBuffer("key", iv, CRYPTO_IV_SIZE);
m_encryption.SetKeyWithIV(key, length, iv); byte temp[SHA256::DIGESTSIZE];
m_decryption.SetKeyWithIV(key, length, iv); byte* in = reinterpret_cast<byte*>(const_cast<char*>(password.c_str()));
SHA256().CalculateDigest(temp, in, password.length());
m_key = key; byte* tempKey = new byte[SHA256::DIGESTSIZE];
m_keyLength = length; for (int i = 0; i < hashCount; ++i) {
memcpy(tempKey, temp, SHA256::DIGESTSIZE);
SHA256().CalculateDigest(temp, tempKey, SHA256::DIGESTSIZE);
}
delete[] tempKey;
memcpy(out, temp, keyLength);
} }
void void
@ -90,8 +114,9 @@ CCryptoStream::setIv(const byte* iv)
{ {
assert(m_key != NULL); assert(m_key != NULL);
logBuffer("iv", iv, CRYPTO_IV_SIZE); logBuffer("iv", iv, CRYPTO_IV_SIZE);
m_encryption.SetKeyWithIV(m_key, m_keyLength, iv);
m_decryption.SetKeyWithIV(m_key, m_keyLength, iv); m_encryption.setKeyWithIv(m_key, kKeyLength, iv);
m_decryption.setKeyWithIv(m_key, kKeyLength, iv);
} }
void void

View File

@ -19,10 +19,10 @@
#include "BasicTypes.h" #include "BasicTypes.h"
#include "CStreamFilter.h" #include "CStreamFilter.h"
#include <cryptopp562/gcm.h> #include "CCryptoMode.h"
#include <cryptopp562/modes.h> #include "CCryptoOptions.h"
#include <cryptopp562/aes.h>
#include <cryptopp562/osrng.h> #include <cryptopp562/osrng.h>
#include "cryptopp562/sha.h"
#define CRYPTO_IV_SIZE CryptoPP::AES::BLOCKSIZE #define CRYPTO_IV_SIZE CryptoPP::AES::BLOCKSIZE
@ -32,7 +32,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, bool adoptStream = true); CCryptoStream(IEventQueue* eventQueue, synergy::IStream* stream, const CCryptoOptions& options, bool adoptStream = true);
virtual ~CCryptoStream(); virtual ~CCryptoStream();
//! @name manipulators //! @name manipulators
@ -51,9 +51,6 @@ public:
*/ */
virtual void write(const void* in, UInt32 n); virtual void write(const void* in, UInt32 n);
//! Set the key and IV
void setKeyWithIv(const byte* key, size_t length, const byte* iv);
//! Set the IV //! Set the IV
void setIv(const byte* iv); void setIv(const byte* iv);
@ -64,25 +61,22 @@ public:
*/ */
void newIv(byte* out); void newIv(byte* out);
private: //! Creates a key from a password
// TODO: allow user to change the block cypher mode. static void createKey(byte* out, const CString& password, UInt8 keyLength, UInt8 hashCount);
/*
For CBC and CFB, reusing an IV leaks some information about the first block of plaintext,
and about any common prefix shared by the two messages. For OFB and CTR, reusing an IV
completely destroys security. http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation
*/
CryptoPP::OFB_Mode<CryptoPP::AES>::Encryption m_encryption;
CryptoPP::OFB_Mode<CryptoPP::AES>::Decryption m_decryption;
//CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_encryption;
//CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_decryption;
//CryptoPP::GCM<CryptoPP::AES>::Encryption m_encryption;
//CryptoPP::GCM<CryptoPP::AES>::Decryption m_decryption;
//CryptoPP::CTR_Mode<CryptoPP::AES>::Encryption m_encryption;
//CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption m_decryption;
private:
void logBuffer(const char* name, const byte* buf, int length); void logBuffer(const char* name, const byte* buf, int length);
const byte* m_key; byte* m_key;
size_t m_keyLength; CCryptoMode m_encryption;
CCryptoMode m_decryption;
CryptoPP::AutoSeededRandomPool m_autoSeedRandomPool; CryptoPP::AutoSeededRandomPool m_autoSeedRandomPool;
}; };
namespace synergy {
namespace crypto {
const UInt32 kKeyLength = 32;
}
}

View File

@ -51,6 +51,9 @@ set(inc
CEventGameDevice.h CEventGameDevice.h
CVncClient.h CVncClient.h
CCryptoStream.h CCryptoStream.h
CCryptoMode.h
ECryptoMode.h
CCryptoOptions.h
) )
set(src set(src
@ -82,7 +85,9 @@ set(src
CEventGameDevice.cpp CEventGameDevice.cpp
CVncClient.cpp CVncClient.cpp
CGameDevice.cpp CGameDevice.cpp
CCryptoStream.cpp CCryptoStream.cpp
CCryptoMode.cpp
CCryptoOptions.cpp
) )
if (WIN32) if (WIN32)

View File

@ -695,7 +695,7 @@ CClientListener*
CServerApp::openClientListener(const CNetworkAddress& address) CServerApp::openClientListener(const CNetworkAddress& address)
{ {
CClientListener* listen = CClientListener* listen =
new CClientListener(address, new CTCPSocketFactory, NULL); new CClientListener(address, new CTCPSocketFactory, NULL, args().m_crypto);
EVENTQUEUE->adoptHandler(CClientListener::getConnectedEvent(), listen, EVENTQUEUE->adoptHandler(CClientListener::getConnectedEvent(), listen,
new TMethodEventJob<CServerApp>( new TMethodEventJob<CServerApp>(
this, &CServerApp::handleClientConnected, listen)); this, &CServerApp::handleClientConnected, listen));

View File

@ -0,0 +1,27 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
enum ECryptoMode {
kDisabled,
kOfb,
kCfb,
kCtr,
kGcm,
kNumOfModes
};

View File

@ -19,11 +19,14 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include "CCryptoStream.h" #include "CCryptoStream.h"
#include "CCryptoOptions.h"
class CMockCryptoStream : public CCryptoStream class CMockCryptoStream : public CCryptoStream
{ {
public: public:
CMockCryptoStream(IEventQueue* eventQueue, IStream* stream) : CCryptoStream(eventQueue, stream, false) { } CMockCryptoStream(IEventQueue* eventQueue, IStream* stream) :
CCryptoStream(eventQueue, stream, CCryptoOptions("gcm", "stub"), false) { }
MOCK_METHOD2(read, UInt32(void*, UInt32)); MOCK_METHOD2(read, UInt32(void*, UInt32));
MOCK_METHOD2(write, void(const void*, UInt32)); MOCK_METHOD2(write, void(const void*, UInt32));
}; };

View File

@ -26,9 +26,6 @@ using ::testing::_;
using ::testing::NiceMock; using ::testing::NiceMock;
using ::testing::Invoke; using ::testing::Invoke;
const byte g_key[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; // +\0, 32-byte/256-bit key.
const byte g_iv[] = "bbbbbbbbbbbbbb"; // +\0, AES block size = 16
const UInt8 cryptoIvWrite_bufferLen = 200; const UInt8 cryptoIvWrite_bufferLen = 200;
UInt8 cryptoIvWrite_buffer[cryptoIvWrite_bufferLen]; UInt8 cryptoIvWrite_buffer[cryptoIvWrite_bufferLen];
UInt32 cryptoIvWrite_bufferIndex = 0; UInt32 cryptoIvWrite_bufferIndex = 0;
@ -42,7 +39,6 @@ TEST(CClientProxyTests, cryptoIvWrite)
NiceMock<CMockStream> innerStream; NiceMock<CMockStream> innerStream;
NiceMock<CMockServer> server; NiceMock<CMockServer> server;
NiceMock<CMockCryptoStream>* stream = new NiceMock<CMockCryptoStream>(&eventQueue, &innerStream); NiceMock<CMockCryptoStream>* stream = new NiceMock<CMockCryptoStream>(&eventQueue, &innerStream);
stream->setKeyWithIv(g_key, sizeof(g_key), g_iv);
ON_CALL(*stream, write(_, _)).WillByDefault(Invoke(cryptoIv_mockWrite)); ON_CALL(*stream, write(_, _)).WillByDefault(Invoke(cryptoIv_mockWrite));

View File

@ -27,6 +27,8 @@ using ::testing::NiceMock;
using namespace std; using namespace std;
const byte kIv[] = "aaaaaaaaaaaaaa"; // +\0, AES block size = 16
UInt8 g_write_buffer[4]; UInt8 g_write_buffer[4];
void write_mockWrite(const void* in, UInt32 n); void write_mockWrite(const void* in, UInt32 n);
@ -47,14 +49,11 @@ UInt8 g_readWriteIvChanged_buffer[4];
UInt32 g_readWriteIvChangeTrigger_writeBufferIndex = 0; UInt32 g_readWriteIvChangeTrigger_writeBufferIndex = 0;
UInt32 g_readWriteIvChangeTrigger_readBufferIndex = 0; UInt32 g_readWriteIvChangeTrigger_readBufferIndex = 0;
void readWriteIvChanged_mockWrite(const void* in, UInt32 n); void readWriteIvChanged_mockWrite(const void* in, UInt32 n);
UInt8 readWriteIvChanged_mockRead(void* out, UInt32 n); UInt8 readWriteIvChanged_mockRead(void* out, UInt32 n);
UInt8 g_readWriteIvChangeTrigger_buffer[4 + 4 + 16]; // abcd, DCIV, 16-byte IV UInt8 g_readWriteIvChangeTrigger_buffer[4 + 4 + 16]; // abcd, DCIV, 16-byte IV
void readWriteIvChangeTrigger_mockWrite(const void* in, UInt32 n); void readWriteIvChangeTrigger_mockWrite(const void* in, UInt32 n);
UInt8 readWriteIvChangeTrigger_mockRead(void* out, UInt32 n); UInt8 readWriteIvChangeTrigger_mockRead(void* out, UInt32 n);
const byte g_key[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; // +\0, 32-byte/256-bit key.
const byte g_iv[] = "bbbbbbbbbbbbbb"; // +\0, AES block size = 16
TEST(CCryptoTests, write) TEST(CCryptoTests, write)
{ {
@ -67,33 +66,35 @@ TEST(CCryptoTests, write)
NiceMock<CMockEventQueue> eventQueue; NiceMock<CMockEventQueue> eventQueue;
NiceMock<CMockStream> innerStream; NiceMock<CMockStream> innerStream;
CCryptoOptions options("ctr", "mock");
ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write_mockWrite)); ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write_mockWrite));
CCryptoStream cs(&eventQueue, &innerStream, false); CCryptoStream cs(&eventQueue, &innerStream, options, false);
cs.setKeyWithIv(g_key, sizeof(g_key), g_iv); cs.setIv(kIv);
cs.write(buffer, size); cs.write(buffer, size);
EXPECT_EQ(254, g_write_buffer[0]); EXPECT_EQ(198, g_write_buffer[0]);
EXPECT_EQ(44, g_write_buffer[1]); EXPECT_EQ(62, g_write_buffer[1]);
EXPECT_EQ(187, g_write_buffer[2]); EXPECT_EQ(15, g_write_buffer[2]);
EXPECT_EQ(253, g_write_buffer[3]); EXPECT_EQ(87, g_write_buffer[3]);
} }
TEST(CCryptoTests, read) TEST(CCryptoTests, read)
{ {
NiceMock<CMockEventQueue> eventQueue; NiceMock<CMockEventQueue> eventQueue;
NiceMock<CMockStream> innerStream; NiceMock<CMockStream> innerStream;
CCryptoOptions options("ctr", "mock");
ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(read_mockRead)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(read_mockRead));
CCryptoStream cs(&eventQueue, &innerStream, false);
cs.setKeyWithIv(g_key, sizeof(g_key), g_iv);
g_read_buffer[0] = 254; CCryptoStream cs(&eventQueue, &innerStream, options, false);
g_read_buffer[1] = 44; cs.setIv(kIv);
g_read_buffer[2] = 187;
g_read_buffer[3] = 253; g_read_buffer[0] = 198;
g_read_buffer[1] = 62;
g_read_buffer[2] = 15;
g_read_buffer[3] = 87;
const UInt32 size = 4; const UInt32 size = 4;
UInt8* buffer = new UInt8[size]; UInt8* buffer = new UInt8[size];
@ -109,20 +110,21 @@ TEST(CCryptoTests, write4Read1)
{ {
NiceMock<CMockEventQueue> eventQueue; NiceMock<CMockEventQueue> eventQueue;
NiceMock<CMockStream> innerStream; NiceMock<CMockStream> innerStream;
CCryptoOptions options("ctr", "mock");
ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write4Read1_mockWrite)); ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write4Read1_mockWrite));
ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(write4Read1_mockRead)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(write4Read1_mockRead));
CCryptoStream cs1(&eventQueue, &innerStream, false); CCryptoStream cs1(&eventQueue, &innerStream, options, false);
cs1.setKeyWithIv(g_key, sizeof(g_key), g_iv); cs1.setIv(kIv);
cs1.write("a", 1); cs1.write("a", 1);
cs1.write("b", 1); cs1.write("b", 1);
cs1.write("c", 1); cs1.write("c", 1);
cs1.write("d", 1); cs1.write("d", 1);
CCryptoStream cs2(&eventQueue, &innerStream, false); CCryptoStream cs2(&eventQueue, &innerStream, options, false);
cs2.setKeyWithIv(g_key, sizeof(g_key), g_iv); cs2.setIv(kIv);
UInt8 buffer[4]; UInt8 buffer[4];
cs2.read(buffer, 4); cs2.read(buffer, 4);
@ -137,12 +139,13 @@ TEST(CCryptoTests, write1Read4)
{ {
NiceMock<CMockEventQueue> eventQueue; NiceMock<CMockEventQueue> eventQueue;
NiceMock<CMockStream> innerStream; NiceMock<CMockStream> innerStream;
CCryptoOptions options("ctr", "mock");
ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write1Read4_mockWrite)); ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write1Read4_mockWrite));
ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(write1Read4_mockRead)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(write1Read4_mockRead));
CCryptoStream cs1(&eventQueue, &innerStream, false); CCryptoStream cs1(&eventQueue, &innerStream, options, false);
cs1.setKeyWithIv(g_key, sizeof(g_key), g_iv); cs1.setIv(kIv);
UInt8 bufferIn[4]; UInt8 bufferIn[4];
bufferIn[0] = 'a'; bufferIn[0] = 'a';
@ -151,8 +154,8 @@ TEST(CCryptoTests, write1Read4)
bufferIn[3] = 'd'; bufferIn[3] = 'd';
cs1.write(bufferIn, 4); cs1.write(bufferIn, 4);
CCryptoStream cs2(&eventQueue, &innerStream, false); CCryptoStream cs2(&eventQueue, &innerStream, options, false);
cs2.setKeyWithIv(g_key, sizeof(g_key), g_iv); cs2.setIv(kIv);
UInt8 bufferOut[4]; UInt8 bufferOut[4];
cs2.read(&bufferOut[0], 1); cs2.read(&bufferOut[0], 1);
@ -170,15 +173,16 @@ TEST(CCryptoTests, readWriteIvChanged)
{ {
NiceMock<CMockEventQueue> eventQueue; NiceMock<CMockEventQueue> eventQueue;
NiceMock<CMockStream> innerStream; NiceMock<CMockStream> innerStream;
CCryptoOptions options("ctr", "mock");
ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(readWriteIvChanged_mockWrite)); ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(readWriteIvChanged_mockWrite));
ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(readWriteIvChanged_mockRead)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(readWriteIvChanged_mockRead));
const byte iv1[] = "bbbbbbbbbbbbbbb"; const byte iv1[] = "bbbbbbbbbbbbbbb";
const byte iv2[] = "ccccccccccccccc"; const byte iv2[] = "ccccccccccccccc";
CCryptoStream cs1(&eventQueue, &innerStream, false); CCryptoStream cs1(&eventQueue, &innerStream, options, false);
cs1.setKeyWithIv(g_key, sizeof(g_key), iv1); cs1.setIv(iv1);
UInt8 bufferIn[4]; UInt8 bufferIn[4];
bufferIn[0] = 'a'; bufferIn[0] = 'a';
@ -187,8 +191,8 @@ TEST(CCryptoTests, readWriteIvChanged)
bufferIn[3] = 'd'; bufferIn[3] = 'd';
cs1.write(bufferIn, 4); cs1.write(bufferIn, 4);
CCryptoStream cs2(&eventQueue, &innerStream, false); CCryptoStream cs2(&eventQueue, &innerStream, options, false);
cs2.setKeyWithIv(g_key, sizeof(g_key), iv2); cs1.setIv(iv2);
UInt8 bufferOut[4]; UInt8 bufferOut[4];
cs2.read(bufferOut, 4); cs2.read(bufferOut, 4);
@ -215,6 +219,20 @@ TEST(CCryptoTests, readWriteIvChanged)
EXPECT_EQ('d', bufferOut[3]); EXPECT_EQ('d', bufferOut[3]);
} }
TEST(CCryptoTests, createKey)
{
byte hash1[16];
CCryptoStream::createKey(hash1, "MockLongPassword", 16, 16);
EXPECT_EQ(hash1[0], 149);
EXPECT_EQ(hash1[15], 235);
byte hash2[32];
CCryptoStream::createKey(hash2, "MockLongPassword", 32, 16);
EXPECT_EQ(hash2[0], 149);
EXPECT_EQ(hash2[15], 235);
EXPECT_EQ(hash2[31], 7);
}
void void
write_mockWrite(const void* in, UInt32 n) write_mockWrite(const void* in, UInt32 n)
{ {