You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
665 lines
13 KiB
665 lines
13 KiB
// test the published EncryptedString class
|
|
|
|
#include <windows.h>
|
|
|
|
#include <time.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
// Make sure we have an ASSERT() function defined for our test.
|
|
#ifndef ASSERT
|
|
|
|
#ifdef NDEBUG
|
|
#undef NDEBUG
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#define ASSERT assert
|
|
|
|
#endif
|
|
|
|
|
|
// Uncomment the #define if you want to trace the test harness.
|
|
#ifndef TRACE
|
|
//#define TRACE
|
|
#endif
|
|
|
|
class ScopeTracer
|
|
{
|
|
public:
|
|
ScopeTracer(const char* message)
|
|
: m_message(NULL)
|
|
{
|
|
#ifdef TRACE
|
|
if (message)
|
|
{
|
|
m_message = new char[strlen(message) + 1];
|
|
strcpy(m_message, message);
|
|
}
|
|
else
|
|
{
|
|
m_message = new char[1];
|
|
m_message[0] = NULL;
|
|
}
|
|
|
|
PrintIndents();
|
|
printf("->%s\n", m_message);
|
|
++g_indentLevel;
|
|
#else
|
|
// Make the compiler happy.
|
|
message = NULL;
|
|
#endif
|
|
}
|
|
|
|
~ScopeTracer(void)
|
|
{
|
|
#ifdef TRACE
|
|
--g_indentLevel;
|
|
PrintIndents();
|
|
printf("<-%s\n", m_message);
|
|
|
|
delete [] m_message;
|
|
#endif
|
|
}
|
|
|
|
unsigned int GetIndentLevel(void) const
|
|
{
|
|
return g_indentLevel;
|
|
}
|
|
|
|
private:
|
|
|
|
void PrintIndents(void)
|
|
{
|
|
for (unsigned int level = 0;
|
|
level < g_indentLevel;
|
|
++level)
|
|
{
|
|
printf(" ");
|
|
}
|
|
}
|
|
|
|
char* m_message;
|
|
|
|
static unsigned int g_indentLevel;
|
|
};
|
|
|
|
unsigned int ScopeTracer::g_indentLevel = 0;
|
|
|
|
#include "EncryptedString.hpp"
|
|
|
|
#include <list>
|
|
using namespace std;
|
|
|
|
HINSTANCE hResourceModuleHandle = 0;
|
|
const wchar_t* HELPFILE_NAME = 0;
|
|
const wchar_t* RUNTIME_NAME = L"test";
|
|
|
|
//DWORD DEFAULT_LOGGING_OPTIONS = Burnslib::Log::OUTPUT_TYPICAL;
|
|
|
|
const size_t MAX_CHARACTER_COUNT = 2047;
|
|
|
|
void
|
|
TestEmptyness(const EncryptedString& empty)
|
|
{
|
|
ScopeTracer scope("TestEmptyness");
|
|
|
|
ASSERT(empty.IsEmpty());
|
|
ASSERT(empty.GetLength() == 0);
|
|
|
|
// the cleartext of an empty instance should also be empty
|
|
|
|
WCHAR* emptyClear = empty.GetClearTextCopy();
|
|
|
|
ASSERT(emptyClear);
|
|
|
|
ASSERT(*emptyClear == 0);
|
|
|
|
empty.DestroyClearTextCopy(emptyClear);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestEmptyStrings()
|
|
{
|
|
ScopeTracer scope("TestEmptyStrings");
|
|
|
|
EncryptedString empty1;
|
|
|
|
TestEmptyness(empty1);
|
|
|
|
// copies of empty strings are themselves empty
|
|
|
|
EncryptedString empty2(empty1);
|
|
|
|
// source should still be empty
|
|
|
|
TestEmptyness(empty1);
|
|
TestEmptyness(empty2);
|
|
|
|
EncryptedString empty3;
|
|
|
|
TestEmptyness(empty3);
|
|
|
|
empty3 = empty2;
|
|
|
|
// source should still be empty
|
|
|
|
TestEmptyness(empty2);
|
|
TestEmptyness(empty3);
|
|
|
|
empty3 = empty1;
|
|
|
|
TestEmptyness(empty1);
|
|
TestEmptyness(empty2);
|
|
TestEmptyness(empty3);
|
|
|
|
// strings built from empty strings should be empty
|
|
|
|
EncryptedString empty4;
|
|
|
|
TestEmptyness(empty4);
|
|
|
|
empty4.Encrypt(L"");
|
|
|
|
TestEmptyness(empty4);
|
|
|
|
// a string made from an empty string is still empty when the source
|
|
// is made non-empty
|
|
|
|
EncryptedString empty5;
|
|
EncryptedString empty6(empty5);
|
|
|
|
TestEmptyness(empty5);
|
|
TestEmptyness(empty6);
|
|
|
|
empty5.Encrypt(L"not empty any more");
|
|
|
|
ASSERT(!empty5.IsEmpty());
|
|
ASSERT(empty5.GetLength() != 0);
|
|
TestEmptyness(empty6);
|
|
|
|
// A cleared string is empty
|
|
|
|
EncryptedString empty7;
|
|
empty7.Encrypt(L"some text");
|
|
empty7.Clear();
|
|
TestEmptyness(empty7);
|
|
|
|
// empty strings are equal
|
|
|
|
ASSERT(empty1 == empty1);
|
|
ASSERT(empty1 == empty2);
|
|
ASSERT(empty1 == empty3);
|
|
ASSERT(empty1 == empty4);
|
|
ASSERT(empty1 == empty6);
|
|
ASSERT(empty1 == empty7);
|
|
ASSERT(empty2 == empty1);
|
|
ASSERT(empty2 == empty2);
|
|
ASSERT(empty2 == empty3);
|
|
ASSERT(empty2 == empty4);
|
|
ASSERT(empty2 == empty6);
|
|
ASSERT(empty2 == empty7);
|
|
ASSERT(empty3 == empty1);
|
|
ASSERT(empty3 == empty2);
|
|
ASSERT(empty3 == empty3);
|
|
ASSERT(empty3 == empty4);
|
|
ASSERT(empty3 == empty6);
|
|
ASSERT(empty3 == empty7);
|
|
ASSERT(empty4 == empty1);
|
|
ASSERT(empty4 == empty2);
|
|
ASSERT(empty4 == empty3);
|
|
ASSERT(empty4 == empty4);
|
|
ASSERT(empty4 == empty6);
|
|
ASSERT(empty4 == empty7);
|
|
ASSERT(empty6 == empty1);
|
|
ASSERT(empty6 == empty2);
|
|
ASSERT(empty6 == empty3);
|
|
ASSERT(empty6 == empty4);
|
|
ASSERT(empty6 == empty6);
|
|
ASSERT(empty6 == empty7);
|
|
ASSERT(empty7 == empty1);
|
|
ASSERT(empty7 == empty2);
|
|
ASSERT(empty7 == empty3);
|
|
ASSERT(empty7 == empty4);
|
|
ASSERT(empty7 == empty6);
|
|
ASSERT(empty7 == empty7);
|
|
}
|
|
|
|
|
|
|
|
WCHAR*
|
|
MakeRandomString(size_t length)
|
|
{
|
|
//LOG_FUNCTION2(MakeRandomString, String::format(L"%1!d!", length));
|
|
|
|
WCHAR* result = new WCHAR[length + 1];
|
|
|
|
for (size_t i = 0; i < length; ++i)
|
|
{
|
|
// 32 = space, the lowest printable character
|
|
|
|
int r1 = rand() % 0xFFEE;
|
|
|
|
// careful not to use an expression as a parameter to max...
|
|
|
|
int r2 = max(32, r1);
|
|
|
|
ASSERT(r2);
|
|
ASSERT(r2 >= 32);
|
|
ASSERT(r2 < 0xFFEE);
|
|
|
|
result[i] = (WCHAR) r2;
|
|
ASSERT(result[i]);
|
|
}
|
|
|
|
result[length] = 0;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestEncryption(const EncryptedString& s, const WCHAR* sourceClearText)
|
|
{
|
|
ScopeTracer scope("TestEncryption");
|
|
|
|
// decrypt s, compare it to sourceClearText
|
|
|
|
WCHAR* clearText = s.GetClearTextCopy();
|
|
|
|
// the decryption shouldn't fail (barring out-of-memory);
|
|
|
|
ASSERT(clearText);
|
|
ASSERT(wcscmp(clearText, sourceClearText) == 0);
|
|
|
|
s.DestroyClearTextCopy(clearText);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestEncryptionForStringOfLengthN(size_t length)
|
|
{
|
|
//LOG_FUNCTION2(TestEncryptionForStringOfLengthN, String::format(L"%1!d!", length));
|
|
ASSERT(length <= MAX_CHARACTER_COUNT);
|
|
|
|
WCHAR* source = MakeRandomString(length);
|
|
|
|
EncryptedString s;
|
|
s.Encrypt(source);
|
|
|
|
TestEncryption(s, source);
|
|
|
|
EncryptedString s1(s);
|
|
TestEncryption(s1, source);
|
|
|
|
EncryptedString s2;
|
|
s2 = s;
|
|
|
|
TestEncryption(s2, source);
|
|
|
|
delete[] source;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestEncryptionFidelity()
|
|
{
|
|
ScopeTracer scope("TestEncryptionFidelity");
|
|
|
|
// do we get out what we put in?
|
|
|
|
srand(time(0));
|
|
|
|
// test increasing lengths of random strings
|
|
|
|
for (
|
|
size_t length = 0;
|
|
length <= MAX_CHARACTER_COUNT;
|
|
++length)
|
|
{
|
|
TestEncryptionForStringOfLengthN(length);
|
|
}
|
|
|
|
// test decreasing lengths of random strings
|
|
|
|
for (
|
|
size_t length = MAX_CHARACTER_COUNT;
|
|
length != 0;
|
|
--length)
|
|
{
|
|
TestEncryptionForStringOfLengthN(length);
|
|
}
|
|
|
|
// test strings of random length, with lots of outstanding encrypted
|
|
// strings
|
|
|
|
typedef std::list<EncryptedString*> ESPList;
|
|
ESPList strings;
|
|
|
|
for (
|
|
int count = 0;
|
|
count < 1000;
|
|
++count)
|
|
{
|
|
size_t length = rand() % MAX_CHARACTER_COUNT;
|
|
|
|
WCHAR* source = MakeRandomString(length);
|
|
|
|
EncryptedString* ps = new EncryptedString;
|
|
strings.push_back(ps);
|
|
|
|
ps->Encrypt(source);
|
|
|
|
TestEncryption(*ps, source);
|
|
|
|
// make a copy via copy ctor
|
|
|
|
EncryptedString* ps1 = new EncryptedString(*ps);
|
|
strings.push_back(ps1);
|
|
|
|
TestEncryption(*ps1, source);
|
|
|
|
// make a copy via operator =
|
|
|
|
EncryptedString* ps2 = new EncryptedString;
|
|
strings.push_back(ps2);
|
|
|
|
*ps2 = *ps;
|
|
|
|
TestEncryption(*ps2, source);
|
|
|
|
delete[] source;
|
|
}
|
|
|
|
for (
|
|
ESPList::iterator i = strings.begin();
|
|
i != strings.end();
|
|
++i)
|
|
{
|
|
(*i)->Clear();
|
|
TestEmptyness(**i);
|
|
delete *i;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestClearTextCopying()
|
|
{
|
|
ScopeTracer scope("TestClearTextCopying");
|
|
|
|
// make a bunch of copies, make sure the count balances
|
|
|
|
typedef char foo[2];
|
|
|
|
|
|
// An encrypted string and the source string used to build it.
|
|
|
|
typedef
|
|
std::pair<EncryptedString*, WCHAR*>
|
|
EncryptedAndSourcePair;
|
|
|
|
// A list of results from EncryptedString::GetClearTextCopy
|
|
|
|
typedef std::list<WCHAR*> ClearTextList;
|
|
|
|
// A tuple of the encrypted string, its source string, and a list
|
|
// of clear-text copies made from the encrypted string
|
|
|
|
typedef
|
|
std::pair<EncryptedAndSourcePair*, ClearTextList*>
|
|
MasterAndClearTextCopiesPair;
|
|
|
|
// A list of the above tuples.
|
|
|
|
typedef
|
|
std::list<MasterAndClearTextCopiesPair*>
|
|
MasterAndCopiesList;
|
|
|
|
MasterAndCopiesList mcList;
|
|
|
|
for (int count = 0; count < 1000; ++count)
|
|
{
|
|
// Make a random source string
|
|
|
|
size_t length = rand() % MAX_CHARACTER_COUNT;
|
|
WCHAR* source = MakeRandomString(length);
|
|
|
|
// Make an encrypted string from it
|
|
|
|
EncryptedString* ps = new EncryptedString;
|
|
ps->Encrypt(source);
|
|
|
|
// Make a pair of the encrypted string and its source string
|
|
|
|
EncryptedAndSourcePair* esp = new EncryptedAndSourcePair(ps, source);
|
|
|
|
// Make a list of clear-text copies of the encrypted string
|
|
|
|
ClearTextList* ctList = new ClearTextList;
|
|
|
|
// Make a master and copies pair
|
|
|
|
MasterAndClearTextCopiesPair* mcPair = new MasterAndClearTextCopiesPair(esp, ctList);
|
|
|
|
// add the master and copies pair to the master and copies list
|
|
|
|
mcList.push_back(mcPair);
|
|
|
|
int copyMax = max(1, rand() % 50);
|
|
for (int copyCount = 0; copyCount < copyMax; ++copyCount)
|
|
{
|
|
// make some copies
|
|
|
|
ctList->push_back(ps->GetClearTextCopy());
|
|
}
|
|
}
|
|
|
|
for (
|
|
MasterAndCopiesList::iterator i = mcList.begin();
|
|
i != mcList.end();
|
|
++i)
|
|
{
|
|
EncryptedAndSourcePair* esp = (*i)->first;
|
|
ClearTextList* ctList = (*i)->second;
|
|
|
|
// delete each element of the ClearTextList
|
|
|
|
for (
|
|
ClearTextList::iterator j = ctList->begin();
|
|
j != ctList->end();
|
|
++j)
|
|
{
|
|
// all copies should be identical
|
|
|
|
ASSERT(wcscmp(esp->second, *j) == 0);
|
|
|
|
esp->first->DestroyClearTextCopy(*j);
|
|
}
|
|
|
|
// delete the ClearTextList
|
|
|
|
delete ctList;
|
|
|
|
// delete the encrypted string
|
|
|
|
delete esp->first;
|
|
|
|
// delete the source string;
|
|
|
|
delete[] esp->second;
|
|
|
|
// delete the encrypted string/source string pair
|
|
|
|
delete esp;
|
|
|
|
// delete the master and copies pair
|
|
|
|
delete *i;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestAssignment()
|
|
{
|
|
ScopeTracer scope("TestAssignment");
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestEquality(const EncryptedString& s, const EncryptedString& s1, size_t length)
|
|
{
|
|
ScopeTracer scope("TestEquality");
|
|
|
|
// a string is equal to itself
|
|
|
|
ASSERT(s == s);
|
|
ASSERT(s1 == s1);
|
|
|
|
// a string is equal to a copy of itself
|
|
|
|
ASSERT(s1 == s);
|
|
|
|
// a copy is equal to its source
|
|
|
|
ASSERT(s == s1);
|
|
|
|
// a copy is equal to itself
|
|
|
|
ASSERT(s1 == s1);
|
|
|
|
// a copy is the same length as its source
|
|
|
|
ASSERT(s1.GetLength() == length);
|
|
ASSERT(s.GetLength() == length);
|
|
|
|
// a string is the same length as its copy
|
|
|
|
ASSERT(s1.GetLength() == s.GetLength());
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestEqualityForStringOfLengthN(size_t length)
|
|
{
|
|
//LOG_FUNCTION2(TestEncryptionForStringOfLengthN, String::format(L"%1!d!", length));
|
|
ASSERT(length <= MAX_CHARACTER_COUNT);
|
|
|
|
WCHAR* source = MakeRandomString(length);
|
|
|
|
EncryptedString s;
|
|
s.Encrypt(source);
|
|
ASSERT(s.GetLength() == length);
|
|
|
|
EncryptedString s1(s);
|
|
ASSERT(s1.GetLength() == length);
|
|
|
|
TestEquality(s, s1, length);
|
|
|
|
EncryptedString s2;
|
|
s2 = s;
|
|
|
|
TestEquality(s, s2, length);
|
|
TestEquality(s1, s2, length);
|
|
|
|
// a copy is not equal to its source when the source is changed
|
|
|
|
s.Encrypt(L"Something else...");
|
|
ASSERT(s != s1);
|
|
ASSERT(s != s2);
|
|
ASSERT(s2 != s);
|
|
ASSERT(s1 != s);
|
|
|
|
TestEquality(s1, s2, length);
|
|
|
|
delete[] source;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
DoEqualityTests()
|
|
{
|
|
ScopeTracer scope("DoEqualityTests");
|
|
|
|
for (
|
|
size_t length = 0;
|
|
length <= MAX_CHARACTER_COUNT;
|
|
++length)
|
|
{
|
|
TestEqualityForStringOfLengthN(length);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestInequality()
|
|
{
|
|
ScopeTracer scope("TestInequality");
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestBoundaries()
|
|
{
|
|
ScopeTracer scope("TestBoundaries");
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestLegitimateUse()
|
|
{
|
|
ScopeTracer scope("TestLegitimateUse");
|
|
|
|
|
|
TestEmptyStrings();
|
|
|
|
TestClearTextCopying();
|
|
|
|
TestEncryptionFidelity();
|
|
|
|
TestAssignment();
|
|
|
|
DoEqualityTests();
|
|
|
|
TestInequality();
|
|
|
|
TestBoundaries();
|
|
}
|
|
|
|
|
|
|
|
void
|
|
TestIlllegitimateUse()
|
|
{
|
|
ScopeTracer scope("TestIlllegitimateUse");
|
|
|
|
// make strings that are too long,
|
|
// make unbalanced cleartext copyies (call Destroy too many times, not enough times)
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
_cdecl
|
|
main(int, char **)
|
|
{
|
|
ScopeTracer scope("main");
|
|
|
|
TestLegitimateUse();
|
|
TestIlllegitimateUse();
|
|
}
|