diff --git a/src/lib/client/CClient.cpp b/src/lib/client/CClient.cpp index 728d33e4..f2243b7d 100644 --- a/src/lib/client/CClient.cpp +++ b/src/lib/client/CClient.cpp @@ -35,10 +35,6 @@ #include "CArch.h" #include "IPlatformScreen.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 @@ -52,7 +48,8 @@ CClient::CClient(IEventQueue* eventQueue, const CString& name, const CNetworkAddress& address, ISocketFactory* socketFactory, IStreamFilterFactory* streamFilterFactory, - CScreen* screen) : + CScreen* screen, + const CCryptoOptions& crypto) : m_mock(false), m_name(name), m_serverAddress(address), @@ -67,7 +64,8 @@ CClient::CClient(IEventQueue* eventQueue, m_suspended(false), m_connectOnResume(false), m_eventQueue(eventQueue), - m_cryptoStream(NULL) + m_cryptoStream(NULL), + m_crypto(crypto) { assert(m_socketFactory != NULL); assert(m_screen != NULL); @@ -148,9 +146,9 @@ CClient::connect() } m_stream = new CPacketStreamFilter(m_stream, true); - if (s_cryptoEnabled) { - m_cryptoStream = new CCryptoStream(m_eventQueue, m_stream, true); - m_cryptoStream->setKeyWithIv(g_key, sizeof(g_key), g_iv); + if (m_crypto.m_mode != kDisabled) { + m_cryptoStream = new CCryptoStream( + EVENTQUEUE, m_stream, m_crypto, true); m_stream = m_cryptoStream; } diff --git a/src/lib/client/CClient.h b/src/lib/client/CClient.h index c6d35a0f..86d40cab 100644 --- a/src/lib/client/CClient.h +++ b/src/lib/client/CClient.h @@ -23,6 +23,7 @@ #include "IClipboard.h" #include "CNetworkAddress.h" #include "INode.h" +#include "CCryptoOptions.h" class CEventQueueTimer; class CScreen; @@ -57,7 +58,8 @@ public: const CString& name, const CNetworkAddress& address, ISocketFactory* socketFactory, IStreamFilterFactory* streamFilterFactory, - CScreen* screen); + CScreen* screen, + const CCryptoOptions& crypto); ~CClient(); #ifdef TEST_ENV @@ -217,12 +219,11 @@ private: CString m_dataClipboard[kClipboardEnd]; IEventQueue* m_eventQueue; CCryptoStream* m_cryptoStream; + CCryptoOptions m_crypto; 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/server/CClientListener.cpp b/src/lib/server/CClientListener.cpp index d4802199..ba775186 100644 --- a/src/lib/server/CClientListener.cpp +++ b/src/lib/server/CClientListener.cpp @@ -29,7 +29,8 @@ #include "IEventQueue.h" #include "TMethodEventJob.h" #include "CCryptoStream.h" - +#include "CCryptoOptions.h" + // TODO: these are just for testing -- make sure they're gone by release! const byte g_key[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; const byte g_iv[] = "aaaaaaaaaaaaaaa"; @@ -42,10 +43,12 @@ CEvent::Type CClientListener::s_connectedEvent = CEvent::kUnknown; CClientListener::CClientListener(const CNetworkAddress& address, ISocketFactory* socketFactory, - IStreamFilterFactory* streamFilterFactory) : + IStreamFilterFactory* streamFilterFactory, + const CCryptoOptions& crypto) : m_socketFactory(socketFactory), m_streamFilterFactory(streamFilterFactory), - m_server(NULL) + m_server(NULL), + m_crypto(crypto) { assert(m_socketFactory != NULL); @@ -149,9 +152,9 @@ CClientListener::handleClientConnecting(const CEvent&, void*) } stream = new CPacketStreamFilter(stream, true); - if (s_cryptoEnabled) { - CCryptoStream* cryptoStream = new CCryptoStream(EVENTQUEUE, stream, true); - cryptoStream->setKeyWithIv(g_key, sizeof(g_key), g_iv); + if (m_crypto.m_mode != kDisabled) { + CCryptoStream* cryptoStream = new CCryptoStream( + EVENTQUEUE, stream, m_crypto, true); stream = cryptoStream; } diff --git a/src/lib/server/CClientListener.h b/src/lib/server/CClientListener.h index 21703c2b..fd9c2fd9 100644 --- a/src/lib/server/CClientListener.h +++ b/src/lib/server/CClientListener.h @@ -23,6 +23,7 @@ #include "CEvent.h" #include "stddeque.h" #include "stdset.h" +#include "CCryptoOptions.h" class CClientProxy; class CClientProxyUnknown; @@ -36,7 +37,9 @@ class CClientListener { public: // The factories are adopted. CClientListener(const CNetworkAddress&, - ISocketFactory*, IStreamFilterFactory*); + ISocketFactory*, + IStreamFilterFactory*, + const CCryptoOptions& crypto); ~CClientListener(); //! @name manipulators @@ -81,11 +84,10 @@ private: IStreamFilterFactory* m_streamFilterFactory; CNewClients m_newClients; CWaitingClients m_waitingClients; + CServer* m_server; + CCryptoOptions m_crypto; static CEvent::Type s_connectedEvent; - CServer* m_server; - - static const bool s_cryptoEnabled = true; }; #endif diff --git a/src/lib/synergy/CApp.cpp b/src/lib/synergy/CApp.cpp index 0c3747b3..f88673bf 100644 --- a/src/lib/synergy/CApp.cpp +++ b/src/lib/synergy/CApp.cpp @@ -161,6 +161,14 @@ CApp::parseArg(const int& argc, const char* const* argv, int& i) // 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 else if (isArg(i, argc, argv, NULL, "--vnc")) { argsBase().m_enableVnc = true; diff --git a/src/lib/synergy/CArgsBase.h b/src/lib/synergy/CArgsBase.h index c9df0a4b..ff7b7d18 100644 --- a/src/lib/synergy/CArgsBase.h +++ b/src/lib/synergy/CArgsBase.h @@ -20,6 +20,7 @@ #include "CString.h" #include "CGameDevice.h" +#include "CCryptoOptions.h" class CArgsBase { public: @@ -37,6 +38,7 @@ public: bool m_disableTray; bool m_enableVnc; bool m_enableIpc; + CCryptoOptions m_crypto; #if SYSAPI_WIN32 bool m_debugServiceWait; bool m_pauseOnExit; diff --git a/src/lib/synergy/CClientApp.cpp b/src/lib/synergy/CClientApp.cpp index e2dd095e..00607590 100644 --- a/src/lib/synergy/CClientApp.cpp +++ b/src/lib/synergy/CClientApp.cpp @@ -393,10 +393,10 @@ CClientApp::handleClientDisconnected(const CEvent&, void*) 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( - EVENTQUEUE, name, address, new CTCPSocketFactory, NULL, screen); + EVENTQUEUE, name, address, new CTCPSocketFactory, NULL, screen, crypto); try { EVENTQUEUE->adoptHandler( @@ -454,7 +454,7 @@ CClientApp::startClient() if (s_clientScreen == NULL) { clientScreen = openClientScreen(); s_client = openClient(args().m_name, - *args().m_serverAddress, clientScreen); + *args().m_serverAddress, clientScreen, args().m_crypto); s_clientScreen = clientScreen; LOG((CLOG_NOTE "started client")); } diff --git a/src/lib/synergy/CClientApp.h b/src/lib/synergy/CClientApp.h index ba7d96ec..a191191a 100644 --- a/src/lib/synergy/CClientApp.h +++ b/src/lib/synergy/CClientApp.h @@ -74,7 +74,7 @@ public: void handleClientConnected(const CEvent&, void*); void handleClientFailed(const CEvent& e, 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); bool startClient(); void stopClient(); diff --git a/src/lib/synergy/CCryptoMode.cpp b/src/lib/synergy/CCryptoMode.cpp new file mode 100644 index 00000000..90d66537 --- /dev/null +++ b/src/lib/synergy/CCryptoMode.cpp @@ -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 . +*/ + +#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(m_crypto); + break; + + case kCfb: + delete reinterpret_cast(m_crypto); + break; + + case kCtr: + delete reinterpret_cast(m_crypto); + break; + + case kGcm: + delete reinterpret_cast(m_crypto); + break; + } + } + else { + switch (m_mode) { + case kOfb: + delete reinterpret_cast(m_crypto); + break; + + case kCfb: + delete reinterpret_cast(m_crypto); + break; + + case kCtr: + delete reinterpret_cast(m_crypto); + break; + + case kGcm: + delete reinterpret_cast(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(m_crypto)->ProcessData(out, in, length); + break; + + case kCfb: + reinterpret_cast(m_crypto)->ProcessData(out, in, length); + break; + + case kCtr: + reinterpret_cast(m_crypto)->ProcessData(out, in, length); + break; + + case kGcm: + reinterpret_cast(m_crypto)->ProcessData(out, in, length); + break; + } + } + else { + switch (m_mode) { + case kOfb: + reinterpret_cast(m_crypto)->ProcessData(out, in, length); + break; + + case kCfb: + reinterpret_cast(m_crypto)->ProcessData(out, in, length); + break; + + case kCtr: + reinterpret_cast(m_crypto)->ProcessData(out, in, length); + break; + + case kGcm: + reinterpret_cast(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(m_crypto)->SetKeyWithIV(key, length, iv); + break; + + case kCfb: + reinterpret_cast(m_crypto)->SetKeyWithIV(key, length, iv); + break; + + case kCtr: + reinterpret_cast(m_crypto)->SetKeyWithIV(key, length, iv); + break; + + case kGcm: + reinterpret_cast(m_crypto)->SetKeyWithIV(key, length, iv); + break; + } + } + else { + switch (m_mode) { + case kOfb: + reinterpret_cast(m_crypto)->SetKeyWithIV(key, length, iv); + break; + + case kCfb: + reinterpret_cast(m_crypto)->SetKeyWithIV(key, length, iv); + break; + + case kCtr: + reinterpret_cast(m_crypto)->SetKeyWithIV(key, length, iv); + break; + + case kGcm: + reinterpret_cast(m_crypto)->SetKeyWithIV(key, length, iv); + break; + } + } +} diff --git a/src/lib/synergy/CCryptoMode.h b/src/lib/synergy/CCryptoMode.h new file mode 100644 index 00000000..6c3f52d5 --- /dev/null +++ b/src/lib/synergy/CCryptoMode.h @@ -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 . + */ + +#pragma once + +#include +#include +#include +#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::Encryption COfbModeEnc; + typedef CryptoPP::CFB_Mode::Encryption CCfbModeEnc; + typedef CryptoPP::CTR_Mode::Encryption CCtrModeEnc; + typedef CryptoPP::GCM::Encryption CGcmModeEnc; + + typedef CryptoPP::OFB_Mode::Decryption COfbModeDec; + typedef CryptoPP::CFB_Mode::Decryption CCfbModeDec; + typedef CryptoPP::CTR_Mode::Decryption CCtrModeDec; + typedef CryptoPP::GCM::Decryption CGcmModeDec; + + static CCryptoMode::ECryptoMode parseMode(CString& mode); + + ECryptoMode m_mode; + void* m_crypto; + bool m_encryption; +}; diff --git a/src/lib/synergy/CCryptoOptions.cpp b/src/lib/synergy/CCryptoOptions.cpp new file mode 100644 index 00000000..c87b8397 --- /dev/null +++ b/src/lib/synergy/CCryptoOptions.cpp @@ -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 . + */ + +#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"); + } +} diff --git a/src/lib/synergy/CCryptoOptions.h b/src/lib/synergy/CCryptoOptions.h new file mode 100644 index 00000000..ba9512ef --- /dev/null +++ b/src/lib/synergy/CCryptoOptions.h @@ -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 . + */ + +#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; +}; diff --git a/src/lib/synergy/CCryptoStream.cpp b/src/lib/synergy/CCryptoStream.cpp index c161f794..d5111eea 100644 --- a/src/lib/synergy/CCryptoStream.cpp +++ b/src/lib/synergy/CCryptoStream.cpp @@ -19,18 +19,36 @@ #include "CLog.h" #include #include +#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), 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() { + delete[] m_key; } UInt32 @@ -52,7 +70,7 @@ CCryptoStream::read(void* out, UInt32 n) } logBuffer("cypher", cypher, n); - m_decryption.ProcessData(static_cast(out), cypher, n); + m_decryption.processData(static_cast(out), cypher, n); logBuffer("plaintext", static_cast(out), n); delete[] cypher; return result; @@ -66,23 +84,29 @@ CCryptoStream::write(const void* in, UInt32 n) logBuffer("plaintext", static_cast(const_cast(in)), n); byte* cypher = new byte[n]; - m_encryption.ProcessData(cypher, static_cast(in), n); + m_encryption.processData(cypher, static_cast(in), n); logBuffer("cypher", cypher, n); getStream()->write(cypher, n); delete[] cypher; } 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); - logBuffer("key", iv, CRYPTO_IV_SIZE); + assert(keyLength <= SHA256::DIGESTSIZE); - m_encryption.SetKeyWithIV(key, length, iv); - m_decryption.SetKeyWithIV(key, length, iv); + byte temp[SHA256::DIGESTSIZE]; + byte* in = reinterpret_cast(const_cast(password.c_str())); + SHA256().CalculateDigest(temp, in, password.length()); - m_key = key; - m_keyLength = length; + byte* tempKey = new byte[SHA256::DIGESTSIZE]; + 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 @@ -90,8 +114,9 @@ CCryptoStream::setIv(const byte* iv) { assert(m_key != NULL); 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 diff --git a/src/lib/synergy/CCryptoStream.h b/src/lib/synergy/CCryptoStream.h index 64d819b3..8c606094 100644 --- a/src/lib/synergy/CCryptoStream.h +++ b/src/lib/synergy/CCryptoStream.h @@ -19,10 +19,10 @@ #include "BasicTypes.h" #include "CStreamFilter.h" -#include -#include -#include +#include "CCryptoMode.h" +#include "CCryptoOptions.h" #include +#include "cryptopp562/sha.h" #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 { public: - CCryptoStream(IEventQueue* eventQueue, synergy::IStream* stream, bool adoptStream = true); + CCryptoStream(IEventQueue* eventQueue, synergy::IStream* stream, const CCryptoOptions& options, bool adoptStream = true); virtual ~CCryptoStream(); //! @name manipulators @@ -51,9 +51,6 @@ public: */ 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 void setIv(const byte* iv); @@ -64,25 +61,22 @@ public: */ void newIv(byte* out); -private: - // TODO: allow user to change the block cypher mode. - /* - 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::Encryption m_encryption; - CryptoPP::OFB_Mode::Decryption m_decryption; - //CryptoPP::CFB_Mode::Encryption m_encryption; - //CryptoPP::CFB_Mode::Decryption m_decryption; - //CryptoPP::GCM::Encryption m_encryption; - //CryptoPP::GCM::Decryption m_decryption; - //CryptoPP::CTR_Mode::Encryption m_encryption; - //CryptoPP::CTR_Mode::Decryption m_decryption; + //! Creates a key from a password + static void createKey(byte* out, const CString& password, UInt8 keyLength, UInt8 hashCount); +private: void logBuffer(const char* name, const byte* buf, int length); - - const byte* m_key; - size_t m_keyLength; + + byte* m_key; + CCryptoMode m_encryption; + CCryptoMode m_decryption; CryptoPP::AutoSeededRandomPool m_autoSeedRandomPool; -}; +}; + +namespace synergy { +namespace crypto { + +const UInt32 kKeyLength = 32; + +} +} diff --git a/src/lib/synergy/CMakeLists.txt b/src/lib/synergy/CMakeLists.txt index 1d9df5c6..49e31a39 100644 --- a/src/lib/synergy/CMakeLists.txt +++ b/src/lib/synergy/CMakeLists.txt @@ -51,6 +51,9 @@ set(inc CEventGameDevice.h CVncClient.h CCryptoStream.h + CCryptoMode.h + ECryptoMode.h + CCryptoOptions.h ) set(src @@ -82,7 +85,9 @@ set(src CEventGameDevice.cpp CVncClient.cpp CGameDevice.cpp - CCryptoStream.cpp + CCryptoStream.cpp + CCryptoMode.cpp + CCryptoOptions.cpp ) if (WIN32) diff --git a/src/lib/synergy/CServerApp.cpp b/src/lib/synergy/CServerApp.cpp index 29128927..1dddca62 100644 --- a/src/lib/synergy/CServerApp.cpp +++ b/src/lib/synergy/CServerApp.cpp @@ -695,7 +695,7 @@ CClientListener* CServerApp::openClientListener(const CNetworkAddress& address) { CClientListener* listen = - new CClientListener(address, new CTCPSocketFactory, NULL); + new CClientListener(address, new CTCPSocketFactory, NULL, args().m_crypto); EVENTQUEUE->adoptHandler(CClientListener::getConnectedEvent(), listen, new TMethodEventJob( this, &CServerApp::handleClientConnected, listen)); diff --git a/src/lib/synergy/ECryptoMode.h b/src/lib/synergy/ECryptoMode.h new file mode 100644 index 00000000..d8f28752 --- /dev/null +++ b/src/lib/synergy/ECryptoMode.h @@ -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 . +*/ + +#pragma once + +enum ECryptoMode { + kDisabled, + kOfb, + kCfb, + kCtr, + kGcm, + kNumOfModes +}; diff --git a/src/test/unittests/io/CMockCryptoStream.h b/src/test/unittests/io/CMockCryptoStream.h index 33a51fdc..33f5e0d8 100644 --- a/src/test/unittests/io/CMockCryptoStream.h +++ b/src/test/unittests/io/CMockCryptoStream.h @@ -19,11 +19,14 @@ #include #include "CCryptoStream.h" +#include "CCryptoOptions.h" class CMockCryptoStream : public CCryptoStream { 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(write, void(const void*, UInt32)); }; diff --git a/src/test/unittests/server/CClientProxyTests.cpp b/src/test/unittests/server/CClientProxyTests.cpp index 6c1625f1..13d8e4e8 100644 --- a/src/test/unittests/server/CClientProxyTests.cpp +++ b/src/test/unittests/server/CClientProxyTests.cpp @@ -26,9 +26,6 @@ using ::testing::_; using ::testing::NiceMock; 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; UInt8 cryptoIvWrite_buffer[cryptoIvWrite_bufferLen]; UInt32 cryptoIvWrite_bufferIndex = 0; @@ -42,7 +39,6 @@ TEST(CClientProxyTests, cryptoIvWrite) NiceMock innerStream; NiceMock server; NiceMock* stream = new NiceMock(&eventQueue, &innerStream); - stream->setKeyWithIv(g_key, sizeof(g_key), g_iv); ON_CALL(*stream, write(_, _)).WillByDefault(Invoke(cryptoIv_mockWrite)); diff --git a/src/test/unittests/synergy/CCryptoStreamTests.cpp b/src/test/unittests/synergy/CCryptoStreamTests.cpp index 94abd179..51802d4a 100644 --- a/src/test/unittests/synergy/CCryptoStreamTests.cpp +++ b/src/test/unittests/synergy/CCryptoStreamTests.cpp @@ -27,6 +27,8 @@ using ::testing::NiceMock; using namespace std; +const byte kIv[] = "aaaaaaaaaaaaaa"; // +\0, AES block size = 16 + UInt8 g_write_buffer[4]; 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_readBufferIndex = 0; 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 void readWriteIvChangeTrigger_mockWrite(const void* in, 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 +UInt8 readWriteIvChangeTrigger_mockRead(void* out, UInt32 n); TEST(CCryptoTests, write) { @@ -67,33 +66,35 @@ TEST(CCryptoTests, write) NiceMock eventQueue; NiceMock innerStream; + CCryptoOptions options("ctr", "mock"); ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write_mockWrite)); - - CCryptoStream cs(&eventQueue, &innerStream, false); - cs.setKeyWithIv(g_key, sizeof(g_key), g_iv); + + CCryptoStream cs(&eventQueue, &innerStream, options, false); + cs.setIv(kIv); cs.write(buffer, size); - EXPECT_EQ(254, g_write_buffer[0]); - EXPECT_EQ(44, g_write_buffer[1]); - EXPECT_EQ(187, g_write_buffer[2]); - EXPECT_EQ(253, g_write_buffer[3]); + EXPECT_EQ(198, g_write_buffer[0]); + EXPECT_EQ(62, g_write_buffer[1]); + EXPECT_EQ(15, g_write_buffer[2]); + EXPECT_EQ(87, g_write_buffer[3]); } TEST(CCryptoTests, read) { NiceMock eventQueue; NiceMock innerStream; + CCryptoOptions options("ctr", "mock"); 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; - g_read_buffer[1] = 44; - g_read_buffer[2] = 187; - g_read_buffer[3] = 253; + CCryptoStream cs(&eventQueue, &innerStream, options, false); + cs.setIv(kIv); + + g_read_buffer[0] = 198; + g_read_buffer[1] = 62; + g_read_buffer[2] = 15; + g_read_buffer[3] = 87; const UInt32 size = 4; UInt8* buffer = new UInt8[size]; @@ -109,20 +110,21 @@ TEST(CCryptoTests, write4Read1) { NiceMock eventQueue; NiceMock innerStream; + CCryptoOptions options("ctr", "mock"); ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write4Read1_mockWrite)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(write4Read1_mockRead)); - - CCryptoStream cs1(&eventQueue, &innerStream, false); - cs1.setKeyWithIv(g_key, sizeof(g_key), g_iv); + + CCryptoStream cs1(&eventQueue, &innerStream, options, false); + cs1.setIv(kIv); cs1.write("a", 1); cs1.write("b", 1); cs1.write("c", 1); cs1.write("d", 1); - CCryptoStream cs2(&eventQueue, &innerStream, false); - cs2.setKeyWithIv(g_key, sizeof(g_key), g_iv); + CCryptoStream cs2(&eventQueue, &innerStream, options, false); + cs2.setIv(kIv); UInt8 buffer[4]; cs2.read(buffer, 4); @@ -137,12 +139,13 @@ TEST(CCryptoTests, write1Read4) { NiceMock eventQueue; NiceMock innerStream; + CCryptoOptions options("ctr", "mock"); ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write1Read4_mockWrite)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(write1Read4_mockRead)); - CCryptoStream cs1(&eventQueue, &innerStream, false); - cs1.setKeyWithIv(g_key, sizeof(g_key), g_iv); + CCryptoStream cs1(&eventQueue, &innerStream, options, false); + cs1.setIv(kIv); UInt8 bufferIn[4]; bufferIn[0] = 'a'; @@ -151,8 +154,8 @@ TEST(CCryptoTests, write1Read4) bufferIn[3] = 'd'; cs1.write(bufferIn, 4); - CCryptoStream cs2(&eventQueue, &innerStream, false); - cs2.setKeyWithIv(g_key, sizeof(g_key), g_iv); + CCryptoStream cs2(&eventQueue, &innerStream, options, false); + cs2.setIv(kIv); UInt8 bufferOut[4]; cs2.read(&bufferOut[0], 1); @@ -170,15 +173,16 @@ TEST(CCryptoTests, readWriteIvChanged) { NiceMock eventQueue; NiceMock innerStream; + CCryptoOptions options("ctr", "mock"); ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(readWriteIvChanged_mockWrite)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(readWriteIvChanged_mockRead)); - - const byte iv1[] = "bbbbbbbbbbbbbbb"; + + const byte iv1[] = "bbbbbbbbbbbbbbb"; const byte iv2[] = "ccccccccccccccc"; - - CCryptoStream cs1(&eventQueue, &innerStream, false); - cs1.setKeyWithIv(g_key, sizeof(g_key), iv1); + + CCryptoStream cs1(&eventQueue, &innerStream, options, false); + cs1.setIv(iv1); UInt8 bufferIn[4]; bufferIn[0] = 'a'; @@ -187,8 +191,8 @@ TEST(CCryptoTests, readWriteIvChanged) bufferIn[3] = 'd'; cs1.write(bufferIn, 4); - CCryptoStream cs2(&eventQueue, &innerStream, false); - cs2.setKeyWithIv(g_key, sizeof(g_key), iv2); + CCryptoStream cs2(&eventQueue, &innerStream, options, false); + cs1.setIv(iv2); UInt8 bufferOut[4]; cs2.read(bufferOut, 4); @@ -215,6 +219,20 @@ TEST(CCryptoTests, readWriteIvChanged) 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 write_mockWrite(const void* in, UInt32 n) {