This article makes use of the Crypto++ library, available here. To run compile the demo code, you will need to download the Windows version of the Crypto++ library and source files.
Overview
This was put together because I needed a secure log file class that would allow selective access.
I needed something that could Write/Read encrypted log files (because sensitive data was being kept in them). I also wanted to know who was using the application (Domain\User), so as to restrict access accordingly.
In the application I was writing, I created two little dialogs for logging on and changing the Pass Phrase/Password. The CLogIt
demo application includes these dialogs.
The first thing I needed was the ability to login, so I had to create a Login Screen (below). I added the "Admin Password" edit box because I wanted a way to know if the current user had rights to use certain controls in the application (some of the logs/controls may contain sensitive information).
If they got past here then they had the correct Pass Phrase, and possibly the correct Admin Password.
There are only two entries in the registry - one for "Pass Phrase" and the other for "Admin Password". Both registry entries are encrypted, and only this application can decrypt them (using a built-in Pass Phrase).
The built in Pass Phrase encrypts the two entries in the registry, the user's Pass Phrase (given at login) En/Decrypts the log information.
I needed the ability to change these if they were ever compromised (or I thought they were), so the following dialog was born - (which should be only available to users who have the Admin password)
What does the application look like (you ask).......
Here is what the log file looks like.......
I know it isn't so pretty (no splitter window, etc...), but I wanted to just put this together for you all and not spend a lot of time on it.
Implementation Notes
I'll explain the CLogIt
code, then how I implemented the Crypt++ v3.2.
I had to find a way to get the Domain\User in one swipe, and based this code on the MSDN article Q155698...
BOOL CLogIt::GetSystemDomainUserName(void)
{
LPTSTR UserName = User;
LPDWORD cchUserName = &cchUser;
LPTSTR DomainName = Domain;
LPDWORD cchDomainName = &cchDomain;
HANDLE hToken;
#define MY_BUFSIZE 512
UCHAR InfoBuffer[ MY_BUFSIZE ];
DWORD cbInfoBuffer = MY_BUFSIZE;
SID_NAME_USE snu;
BOOL bSuccess;
BOOL bRet = FALSE;
CString csMsg = _T("");
if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken)) {
if(GetLastError() == ERROR_NO_TOKEN) {
if(!OpenProcessToken(GetCurrentProcess(),
TOKEN_QUERY, &hToken )) {
csMsg.Format("Error(%u): OpenProcessToken: %s",
GetLastError(), DisplayError(GetLastError()));
WriteLog(csMsg, 0);
return FALSE;
}
}
else {
csMsg.Format("Error(%u): OpenThreadToken: %s",
GetLastError(), DisplayError(GetLastError()));
WriteLog(csMsg, 0);
return FALSE;
}
bSuccess = GetTokenInformation(hToken, TokenUser,
InfoBuffer, cbInfoBuffer, &cbInfoBuffer);
if(!bSuccess) {
csMsg.Format("Error(%u): GetTokenInformation: %s",
GetLastError(), DisplayError(GetLastError()));
WriteLog(csMsg, 0);
return FALSE;
}
else {
bRet = LookupAccountSid(NULL,
((PTOKEN_USER)InfoBuffer)->User.Sid,
UserName, cchUserName, DomainName,
cchDomainName, &snu );
if (!bRet) {
csMsg.Format("Error(%u): LookupAccountSid: %s",
GetLastError(), DisplayError(GetLastError()));
WriteLog(csMsg, 0);
CloseHandle(hToken);
return FALSE;
}
else {
m_csDomainUserName.Format("%s\\%s", DomainName, UserName);
}
}
}
return TRUE;
}
Now with that out of the way, I needed to write a function to log to a file and encrypt it.
For the image lists, I used a bitmap (16 x ...) and so when I write to the log, I simply tell it which image (from the image list) to use, based on the type of the log entry (see below code). Of course, I did have to write a class CLogIt
to hold all of this (and a few extra functions to support the class).
Here is the basic method to log an encrypted string to a file:
void CLogIt::WriteLog(CString csMsg, int nEntryType)
{
if (!IsOpen()) {
CString csText = _T("");
if (m_bDirExists) {
m_fLog = fopen(m_csFullLogName, "a");
if (m_fLog != NULL) {
csText.Format("%s~%i~%s~%s", m_csDomainUserName,
nEntryType, m_csLogEntryTime, csMsg);
CString szRet = EncryptString(LPCTSTR(csText),
LPCTSTR(m_csAppsPPhrase));
csText = szRet;
fprintf(m_fLog, "%s\n", csText);
}
int nClosed = fclose(m_fLog);
if (nClosed == 0)
m_fLog = NULL;
else
MessageBox(NULL, "Problem closing log file",
"Error: Closing file", MB_OK);
Sleep(100);
}
else {
csText.Format("Logging Directory doesn't exist [%s]!", m_csLogDir);
MessageBox(NULL, csText, "Error: Accessing Log Directory", MB_OK);
}
}
}
The EncryptString
method called above uses the DefaultEncryptorWithMAC
class of the Crypto++ libraries.
Basically, this code is modeled on the code from the "Cryptest" Project (found in the Crypto++ zip file), modified so I could use CString
instead of const char *
:
using namespace CryptoPP;
CString CLogIt::EncryptString(CString csInStr, CString csPassPhrase)
{
unsigned int unLen = csInStr.GetLength();
char* szOutstr;
DefaultEncryptorWithMAC encryptor((LPCTSTR)csPassPhrase, new HexEncoder());
encryptor.Put((byte *)(LPCTSTR)csInStr, unLen);
encryptor.Close();
unsigned int unOutputLength = encryptor.MaxRetrieveable();
szOutstr = new char[unOutputLength+1];
encryptor.Get((byte *)szOutstr, unOutputLength);
szOutstr[unOutputLength] = 0;
CString csRet = szOutstr;
return csRet;
}
CString CLogIt::DecryptString(CString csInStr, CString csPassPhrase)
{
unsigned int unLen = csInStr.GetLength();
char* szOutstr;
DefaultDecryptorWithMAC *p;
HexDecoder decryptor(p=new DefaultDecryptorWithMAC((LPCTSTR)csPassPhrase));
decryptor.Put((byte *)(LPCTSTR)csInStr, unLen);
decryptor.Close();
assert(p->CurrentState() == DefaultDecryptorWithMAC::MAC_GOOD);
unsigned int unOutputLength = decryptor.MaxRetrieveable();
szOutstr = new char[unOutputLength+1];
decryptor.Get((byte *)szOutstr, unOutputLength);
szOutstr[unOutputLength] = 0;
CString csRet = szOutstr;
return csRet;
}
That's it!
I was asked by someone why I am posting this information (Encrypt/Decrypt) source that could prove to be dangerous to what I write at home, and my reply was "I got this code from the web and I just simply added a GUI to it, so all I am doing is reposting something that has already been done (just with a different look)".
In my version (at home), I used the CFileChangeEvent class written by Franky Braem (also found here at CodeProject) that monitors the current log file for changes. When it is changed (by someone else using the program) and if I am currently viewing that log file, it refreshes it with the new information. (If you want that added, let me know).
I would like to say at this time that without all of you out there (and Chris Maunder for CodeProject) who are willing to share your ideas (and code), some of us beginner programmers would never be able to develop our skills so quickly and more important so efficiently...On that note, I basically just created something you folks already have, and if that is the case, I am always willing to learn different (possibly the correct) ways to do things. So please let me know if it can be done easier/more effectively/or just that you liked it!!!! Thanks again! Dan
Obtaining the Crypto++ Library
Now I am only a beginner in C++ programming (approx. 1 yr.) and I would never be able to make a class for encryption at this stage of my C++ playing, so I surf'd until I found some source code that does the job. The code I found was source called "Crypto++ v3.2". I basically added the library (and all necessary header files) to get the En/Decryption working. The source also contains an example (Console App) called "Cryptest", and as with any open source site, it is below (in it's entirety). In it you will find code for "DES, MD2, MD5, RC2, RC5, RC6, RSA (to name a few)" encryption. There is even code to "Zip (gzip/gunzip), In/Deflate, etc...".
The simplest way to compile the demo application, having downloaded the Crypto++ files, is to provide the compiler with the paths needed to find the header files and the compiled library. You can set these up using the Tools | Options | Directories page from the VC IDE.
Download Crypto++ v3.2.
Acknowledgements
Along with the Crypto++ library (see above), the demo also makes use of Robert Pittenger's CRegistry class. This class has been included in the demo download.