added unit test to make sure IV works as we expect.

This commit is contained in:
Nick Bolton 2013-04-08 13:01:21 +00:00
parent 0a69c28ac5
commit b2746bc1b2
3 changed files with 140 additions and 24 deletions

View File

@ -29,10 +29,10 @@ const byte g_iv2[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
using namespace CryptoPP; using namespace CryptoPP;
CCryptoStream::CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream, bool adoptStream) : CCryptoStream::CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream, bool adoptStream) :
CStreamFilter(eventQueue, stream, adoptStream) CStreamFilter(eventQueue, stream, adoptStream),
m_key(NULL),
m_keyLength(0)
{ {
m_encryption.SetKeyWithIV(g_key1, sizeof(g_key1), g_iv1);
m_decryption.SetKeyWithIV(g_key1, sizeof(g_key1), g_iv1);
} }
CCryptoStream::~CCryptoStream() CCryptoStream::~CCryptoStream()
@ -42,6 +42,7 @@ CCryptoStream::~CCryptoStream()
UInt32 UInt32
CCryptoStream::read(void* out, UInt32 n) CCryptoStream::read(void* out, UInt32 n)
{ {
assert(m_key != NULL);
LOG((CLOG_DEBUG4 "crypto: read %i (decrypt)", n)); LOG((CLOG_DEBUG4 "crypto: read %i (decrypt)", n));
byte* cypher = new byte[n]; byte* cypher = new byte[n];
@ -66,6 +67,7 @@ CCryptoStream::read(void* out, UInt32 n)
void void
CCryptoStream::write(const void* in, UInt32 n) CCryptoStream::write(const void* in, UInt32 n)
{ {
assert(m_key != NULL);
LOG((CLOG_DEBUG4 "crypto: write %i (encrypt)", n)); LOG((CLOG_DEBUG4 "crypto: write %i (encrypt)", n));
logBuffer("plaintext", static_cast<byte*>(const_cast<void*>(in)), n); logBuffer("plaintext", static_cast<byte*>(const_cast<void*>(in)), n);
@ -76,6 +78,26 @@ CCryptoStream::write(const void* in, UInt32 n)
delete[] cypher; delete[] cypher;
} }
void
CCryptoStream::setKeyWithIV(const byte* key, size_t length, const byte* iv)
{
LOG((CLOG_DEBUG "crypto: key=%s (%i) iv=%s", key, length, iv));
m_encryption.SetKeyWithIV(key, length, iv);
m_decryption.SetKeyWithIV(key, length, iv);
m_key = key;
m_keyLength = length;
}
void
CCryptoStream::setIV(const byte* iv)
{
assert(m_key != NULL);
LOG((CLOG_DEBUG "crypto: new iv=%s", iv));
m_encryption.SetKeyWithIV(m_key, m_keyLength, iv);
m_decryption.SetKeyWithIV(m_key, m_keyLength, iv);
}
void void
CCryptoStream::logBuffer(const char* name, const byte* buf, int length) CCryptoStream::logBuffer(const char* name, const byte* buf, int length)
{ {

View File

@ -20,7 +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/modes.h"
#include "cryptopp562/aes.h" #include "cryptopp562/aes.h"
//! Bidirectional encrypted stream //! Bidirectional encrypted stream
@ -48,12 +48,30 @@ 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
void setIV(const byte* iv);
private: private:
// TODO: allow user to change between GCM/CTR/CFB // TODO: allow user to change the block cypher mode.
CryptoPP::GCM<CryptoPP::AES>::Encryption m_encryption; /*
CryptoPP::GCM<CryptoPP::AES>::Decryption m_decryption; 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>::Encryption m_encryption;
//CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption m_decryption; //CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption m_decryption;
void logBuffer(const char* name, const byte* buf, int length); void logBuffer(const char* name, const byte* buf, int length);
const byte* m_key;
size_t m_keyLength;
}; };

View File

@ -20,17 +20,20 @@
#include "CMockStream.h" #include "CMockStream.h"
#include "CMockEventQueue.h" #include "CMockEventQueue.h"
#include "CPacketStreamFilter.h" #include "CPacketStreamFilter.h"
using ::testing::_; using ::testing::_;
using ::testing::Invoke; using ::testing::Invoke;
using namespace std; using namespace std;
void assertWrite(const void* in, UInt32 n); void write_assertWrite(const void* in, UInt32 n);
UInt8 mockRead(void* out, UInt32 n); UInt8 read_mockRead(void* out, UInt32 n);
void write4Read1_mockWrite(const void* in, UInt32 n); void write4Read1_mockWrite(const void* in, UInt32 n);
UInt8 write4Read1_mockRead(void* out, UInt32 n); UInt8 write4Read1_mockRead(void* out, UInt32 n);
void write1Read4_mockWrite(const void* in, UInt32 n); void write1Read4_mockWrite(const void* in, UInt32 n);
UInt8 write1Read4_mockRead(void* out, UInt32 n); UInt8 write1Read4_mockRead(void* out, UInt32 n);
void readWriteIVChanged_mockWrite(const void* in, UInt32 n);
UInt8 readWriteIVChanged_mockRead(void* out, UInt32 n);
UInt8 g_write4Read1_buffer[4]; UInt8 g_write4Read1_buffer[4];
UInt32 g_write4Read1_bufferIndex = 0; UInt32 g_write4Read1_bufferIndex = 0;
@ -38,6 +41,11 @@ UInt32 g_write4Read1_bufferIndex = 0;
UInt8 g_write1Read4_buffer[4]; UInt8 g_write1Read4_buffer[4];
UInt32 g_write1Read4_bufferIndex = 0; UInt32 g_write1Read4_bufferIndex = 0;
UInt8 g_readWriteIVChanged_buffer[4];
const byte g_key[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; // +\0, 32-byte/256-bit key.
const byte g_iv[] = "bbbbbbbbbbbbbbb"; // +\0, AES block size = 16
TEST(CCryptoTests, write) TEST(CCryptoTests, write)
{ {
const UInt32 size = 4; const UInt32 size = 4;
@ -50,7 +58,7 @@ TEST(CCryptoTests, write)
CMockEventQueue eventQueue; CMockEventQueue eventQueue;
CMockStream innerStream(eventQueue); CMockStream innerStream(eventQueue);
ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(assertWrite)); ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write_assertWrite));
EXPECT_CALL(innerStream, write(_, _)).Times(1); EXPECT_CALL(innerStream, write(_, _)).Times(1);
EXPECT_CALL(innerStream, getEventTarget()).Times(3); EXPECT_CALL(innerStream, getEventTarget()).Times(3);
EXPECT_CALL(eventQueue, removeHandlers(_)).Times(1); EXPECT_CALL(eventQueue, removeHandlers(_)).Times(1);
@ -58,6 +66,7 @@ TEST(CCryptoTests, write)
EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1); EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1);
CCryptoStream cs(eventQueue, &innerStream, false); CCryptoStream cs(eventQueue, &innerStream, false);
cs.setKeyWithIV(g_key, sizeof(g_key), g_iv);
cs.write(buffer, size); cs.write(buffer, size);
} }
@ -66,7 +75,7 @@ TEST(CCryptoTests, read)
CMockEventQueue eventQueue; CMockEventQueue eventQueue;
CMockStream innerStream(eventQueue); CMockStream innerStream(eventQueue);
ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(mockRead)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(read_mockRead));
EXPECT_CALL(innerStream, read(_, _)).Times(1); EXPECT_CALL(innerStream, read(_, _)).Times(1);
EXPECT_CALL(innerStream, getEventTarget()).Times(3); EXPECT_CALL(innerStream, getEventTarget()).Times(3);
EXPECT_CALL(eventQueue, removeHandlers(_)).Times(1); EXPECT_CALL(eventQueue, removeHandlers(_)).Times(1);
@ -74,6 +83,7 @@ TEST(CCryptoTests, read)
EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1); EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1);
CCryptoStream cs(eventQueue, &innerStream, false); CCryptoStream cs(eventQueue, &innerStream, false);
cs.setKeyWithIV(g_key, sizeof(g_key), g_iv);
const UInt32 size = 4; const UInt32 size = 4;
UInt8* buffer = new UInt8[size]; UInt8* buffer = new UInt8[size];
@ -100,13 +110,16 @@ TEST(CCryptoTests, write4Read1)
EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2);
CCryptoStream cs1(eventQueue, &innerStream, false); CCryptoStream cs1(eventQueue, &innerStream, false);
CCryptoStream cs2(eventQueue, &innerStream, false); cs1.setKeyWithIV(g_key, sizeof(g_key), g_iv);
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);
cs2.setKeyWithIV(g_key, sizeof(g_key), g_iv);
UInt8 buffer[4]; UInt8 buffer[4];
cs2.read(buffer, 4); cs2.read(buffer, 4);
@ -131,7 +144,7 @@ TEST(CCryptoTests, write1Read4)
EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2);
CCryptoStream cs1(eventQueue, &innerStream, false); CCryptoStream cs1(eventQueue, &innerStream, false);
CCryptoStream cs2(eventQueue, &innerStream, false); cs1.setKeyWithIV(g_key, sizeof(g_key), g_iv);
UInt8 bufferIn[4]; UInt8 bufferIn[4];
bufferIn[0] = 'a'; bufferIn[0] = 'a';
@ -140,6 +153,9 @@ TEST(CCryptoTests, write1Read4)
bufferIn[3] = 'd'; bufferIn[3] = 'd';
cs1.write(bufferIn, 4); cs1.write(bufferIn, 4);
CCryptoStream cs2(eventQueue, &innerStream, false);
cs2.setKeyWithIV(g_key, sizeof(g_key), g_iv);
UInt8 bufferOut[4]; UInt8 bufferOut[4];
cs2.read(&bufferOut[0], 1); cs2.read(&bufferOut[0], 1);
cs2.read(&bufferOut[1], 1); cs2.read(&bufferOut[1], 1);
@ -152,24 +168,64 @@ TEST(CCryptoTests, write1Read4)
EXPECT_EQ('d', bufferOut[3]); EXPECT_EQ('d', bufferOut[3]);
} }
TEST(CCryptoTests, readWriteIVChanged)
{
CMockEventQueue eventQueue;
CMockStream innerStream(eventQueue);
ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(readWriteIVChanged_mockWrite));
ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(readWriteIVChanged_mockRead));
EXPECT_CALL(innerStream, write(_, _)).Times(1);
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);
const byte iv1[] = "bbbbbbbbbbbbbbb";
const byte iv2[] = "ccccccccccccccc";
CCryptoStream cs1(eventQueue, &innerStream, false);
cs1.setKeyWithIV(g_key, sizeof(g_key), iv1);
UInt8 bufferIn[4];
bufferIn[0] = 'a';
bufferIn[1] = 'b';
bufferIn[2] = 'c';
bufferIn[3] = 'd';
cs1.write(bufferIn, 4);
CCryptoStream cs2(eventQueue, &innerStream, false);
cs2.setKeyWithIV(g_key, sizeof(g_key), iv2);
UInt8 bufferOut[4];
cs2.read(bufferOut, 4);
// assert that the values have changed.
EXPECT_NE('a', bufferOut[0]);
EXPECT_NE('b', bufferOut[1]);
EXPECT_NE('c', bufferOut[2]);
EXPECT_NE('d', bufferOut[3]);
}
void void
assertWrite(const void* in, UInt32 n) write_assertWrite(const void* in, UInt32 n)
{ {
UInt8* buffer = static_cast<UInt8*>(const_cast<void*>(in)); UInt8* buffer = static_cast<UInt8*>(const_cast<void*>(in));
EXPECT_EQ(55, buffer[0]); EXPECT_EQ(8, buffer[0]);
EXPECT_EQ(142, buffer[1]); EXPECT_EQ(58, buffer[1]);
EXPECT_EQ(189, buffer[2]); EXPECT_EQ(151, buffer[2]);
EXPECT_EQ(237, buffer[3]); EXPECT_EQ(33, buffer[3]);
} }
UInt8 UInt8
mockRead(void* out, UInt32 n) read_mockRead(void* out, UInt32 n)
{ {
UInt8* buffer = static_cast<UInt8*>(out); UInt8* buffer = static_cast<UInt8*>(out);
buffer[0] = 55; buffer[0] = 8;
buffer[1] = 142; buffer[1] = 58;
buffer[2] = 189; buffer[2] = 151;
buffer[3] = 237; buffer[3] = 33;
return n; return n;
} }
@ -209,3 +265,23 @@ write1Read4_mockRead(void* out, UInt32 n)
return 1; return 1;
} }
void
readWriteIVChanged_mockWrite(const void* in, UInt32 n)
{
UInt8* buffer = static_cast<UInt8*>(const_cast<void*>(in));
g_readWriteIVChanged_buffer[0] = buffer[0];
g_readWriteIVChanged_buffer[1] = buffer[1];
g_readWriteIVChanged_buffer[2] = buffer[2];
g_readWriteIVChanged_buffer[3] = buffer[3];
}
UInt8
readWriteIVChanged_mockRead(void* out, UInt32 n)
{
UInt8* buffer = static_cast<UInt8*>(out);
buffer[0] = g_readWriteIVChanged_buffer[0];
buffer[1] = g_readWriteIVChanged_buffer[1];
buffer[2] = g_readWriteIVChanged_buffer[2];
buffer[3] = g_readWriteIVChanged_buffer[3];
return 4;
}