Click here to Skip to main content
15,894,539 members
Articles / Desktop Programming / MFC
Article

Encrypting Log Files

Rate me:
Please Sign up or sign in to vote.
4.69/5 (4 votes)
16 Jul 2000CPOL 181.9K   2.1K   46   26
Demonstrates using encryption to protect sensitive application log file data.

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).

LogDemo Passphrase Screen Image

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)

LogDemo Change Password/Passphrase Screen Image

What does the application look like (you ask).......

LogDemo Main Screen Image

Here is what the log file looks like.......

LogDemo Log File Image

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  // highly unlikely to exceed 512 bytes

    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) {
            //
            // attempt to open the process token, since no thread token
            // exists
            //
            if(!OpenProcessToken(GetCurrentProcess(), 
                              TOKEN_QUERY, &hToken )) {
                csMsg.Format("Error(%u): OpenProcessToken: %s", 
                   GetLastError(), DisplayError(GetLastError()));
                WriteLog(csMsg, 0);
                return FALSE;
            }

        } 
        else {
            //
            // error trying to get thread token
            //
            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 {
                // fill the variable with the Domain\User Data
                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:

//*********************************************************************
//
// nEntryType:
//
//        0 = Error
//        1 = Warning
//        2 = Information
//        3 = Lock (Secure)
//        4 = Dir Folder (Closed)
//        5 = Dir Folder (Opened)
//        6 = Paper (Log)
//        7 = User (incognito)
//        8 = Note
//
//**********************************************************************
void CLogIt::WriteLog(CString csMsg, int nEntryType)
{
    // We don't want to write to it 
    // if it's being writing to!
    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); // Give it time to close

        }
        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; // Cryptlib.zip source uses a namespace

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Product Manager
Germany Germany
I have been programming (as a hobby) for 20+ years (Unix C, Scripting, VB, C/C++, C#). I am getting too old to talk about it and been in the Security line of work (both Military/Civilian) for 25+ years.

Comments and Discussions

 
General[SOLVED] Can't compile cryptopp in Visual Studio 2010 Pin
hjkhjghjk18-May-10 9:55
hjkhjghjk18-May-10 9:55 
GeneralRe: [SOLVED] Can't compile cryptopp in Visual Studio 2010 Pin
Dan Madden30-May-10 1:20
Dan Madden30-May-10 1:20 
QuestionWont work in Unicode builds. Pin
Canacourse5-Nov-09 1:10
Canacourse5-Nov-09 1:10 
Questionhow to use this to encript RDPClient password for ".rdp" connection file? Pin
some1One120-Aug-08 2:07
some1One120-Aug-08 2:07 
GeneralQuestion Pin
nadfibra28-Mar-07 7:32
nadfibra28-Mar-07 7:32 
GeneralRe: Question Pin
Dan Madden29-Mar-07 9:31
Dan Madden29-Mar-07 9:31 
GeneralCrypto++ Integration Article Pin
Jeffrey Walton8-Dec-06 18:40
Jeffrey Walton8-Dec-06 18:40 
GeneralHelp me!!! Pin
Tuan, Nguyen Hoang9-Dec-03 7:19
Tuan, Nguyen Hoang9-Dec-03 7:19 
GeneralRe: Help me!!! Pin
Dan Madden9-Dec-03 19:24
Dan Madden9-Dec-03 19:24 
Hi Nguyen Hoang, go see another post I made here http://www.codeproject.com/samples/cryptest_(mfc_style).asp ...this will help you out.


Regards,

Dan
Questioncrypto++ help?? Pin
xxhimanshu11-Nov-03 20:39
xxhimanshu11-Nov-03 20:39 
AnswerRe: crypto++ help?? Pin
Dan Madden11-Nov-03 20:50
Dan Madden11-Nov-03 20:50 
GeneralThis is not secure! Pin
Johan Fernberger14-May-01 11:15
Johan Fernberger14-May-01 11:15 
GeneralSave the digest of the password Pin
Jim Howard14-May-01 12:21
Jim Howard14-May-01 12:21 
GeneralRe: Save the digest of the password Pin
Dan Madden14-May-01 19:18
Dan Madden14-May-01 19:18 
GeneralRe: Save the digest of the password Pin
Jim Howard15-May-01 4:18
Jim Howard15-May-01 4:18 
GeneralRe: Save the digest of the password Pin
28-Aug-01 4:02
suss28-Aug-01 4:02 
GeneralRe: This is not secure! Pin
Dan Madden14-May-01 19:19
Dan Madden14-May-01 19:19 
GeneralRe: This is not secure! Pin
Anonymous24-Oct-02 0:07
Anonymous24-Oct-02 0:07 
GeneralRe: This is not secure! Pin
Pete Bassett24-Oct-02 0:10
Pete Bassett24-Oct-02 0:10 
GeneralRe: This is not secure! Pin
Dan Madden24-Oct-02 3:46
Dan Madden24-Oct-02 3:46 
GeneralRe: This is not secure! Pin
Anthony_Yio15-Oct-03 1:48
Anthony_Yio15-Oct-03 1:48 
GeneralFiles missing Pin
4-Mar-01 2:56
suss4-Mar-01 2:56 
GeneralRe: Files missing Pin
Dan Madden4-Mar-01 10:51
Dan Madden4-Mar-01 10:51 
GeneralDeveloping New Crypt++ v3.2 Project Pin
daniel madden18-Jul-00 9:41
daniel madden18-Jul-00 9:41 
GeneralRe: Developing New Crypt++ v3.2 Project Pin
Chris Maunder19-Jul-00 19:46
cofounderChris Maunder19-Jul-00 19:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.