Listing 1: LSystemApp.cpp — The client program for the License Granting Authority system

#include "stdafx.h"
#include <windows.h>    //For registry functions
#include <iostream.h>   //For cout
#include <time.h>       //For time()
#include "Crypto.h"     //For Encrypt, Decrypt, and ComputeCRC

#define REG_PATH    "SOFTWARE\\LicenseDemo"

bool CheckLicenseTime(HKEY MyKey);
bool CheckCurrentTime(HKEY MyKey);
bool SetCurrentTime(HKEY MyKey);
void GetCookie(char *cookie);

int main(int argc, char* argv[])
{
    char cookie[64];
    ZeroMemory(cookie,64);
    char value[64];
    ZeroMemory(value,64);

    //Create or open the LicenseDemo registry key
    HKEY MyKey;
    if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, REG_PATH, (DWORD) 0,
        NULL, 0, KEY_ALL_ACCESS, NULL, &MyKey,NULL)
        != ERROR_SUCCESS)
    {
        return -1;
    }

    cout << "Checking license\n";

    if (!CheckLicenseTime(MyKey) || !CheckCurrentTime(MyKey))
    {
        cout << "Your license has expired!\n";
        cout << "Visit the LGA to obtain a new license\n";

        GetCookie(cookie);

        cout << "Your cookie is " << cookie << "\n\n";
        cout << "Please input your new license:";

        cin >> value;

        //Set the LICENSE_TIME registry key
        if(RegSetValueEx(MyKey, "LICENSE_TIME", (DWORD) 0,
            REG_SZ, (LPBYTE) value, 64) != ERROR_SUCCESS)
        {
            RegCloseKey (MyKey);
            return -1;
        }

        cout << "Set LICENSE_TIME\n";

        //Set the CURRENT_TIME registry key
        if (!SetCurrentTime(MyKey))
            return -1;

        cout << "Set CURRENT_TIME\n";

        RegCloseKey (MyKey);

        //Recursively call main to check the new license
        main(0,NULL);

        return 0;
    }

    cout << "License validated\n";

    //Set CURRENT_TIME to prevent back clocking
    if (!SetCurrentTime(MyKey))
        return -1;

    cout << "Set CURRENT_TIME\n";

    RegCloseKey (MyKey);

    return 0;
}

//Verifies the license by checking LICENSE_TIME
bool CheckLicenseTime(HKEY MyKey)
{
    long lTime = time(NULL);
    long lLicenseTime = 0;
    unsigned short crc = 0;
    char szReg[64];
    ZeroMemory(szReg,64);
    char szLicense[64];
    ZeroMemory(szLicense,64);
    unsigned long length = 64;
    DWORD type = REG_SZ;

    //Query the LICENSE_TIME registry key
    if(RegQueryValueEx(MyKey, "LICENSE_TIME", NULL, &type, 
        (unsigned char *)szReg, &length) != ERROR_SUCCESS)
        return false;

    //Decrypt the license
    if (!Decrypt(szReg,"UnbreakableKey",szLicense,64))
        return false;

    sscanf(szLicense,"%08X%04X",&lLicenseTime,&crc);

    //Validate the crc
    if (ComputeCRC(lLicenseTime) != crc)
    {
        cout << "Error: LICENSE_TIME crc is invalid\n";
        return false;
    }
        
    if (lTime > lLicenseTime)
        return false;

    return true;
}

//Verifies the license by checking CURRENT_TIME
bool CheckCurrentTime(HKEY MyKey)
{
    long lTime = time(NULL);
    long lCurrentTime = 0;
    unsigned short crc = 0;
    char szReg[64];
    ZeroMemory(szReg,64);
    char szCurrent[64];
    ZeroMemory(szCurrent,64);
    unsigned long length = 64;
    DWORD type = REG_SZ;

    //Query the CURRENT_TIME registry key
    if(RegQueryValueEx(MyKey, "CURRENT_TIME", NULL, &type,
        (unsigned char *)szReg, &length) != ERROR_SUCCESS)
        return false;
    
    //Decrypt the license
    if (!Decrypt(szReg,"UnbreakableKey",szCurrent,64))
        return false;

    sscanf(szCurrent,"%08X%04X",&lCurrentTime,&crc);

    //Validate the crc
    if (ComputeCRC(lCurrentTime) != crc)
    {
        cout << "Error: CURRENT_TIME crc is invalid\n";
        return false;
    }

    if (lTime < lCurrentTime)
        return false;

    return true;
}

bool SetCurrentTime(HKEY MyKey)
{
    long lTime = time(NULL);
    char szReg[64];
    ZeroMemory(szReg,64);
    char szCrypt[64];
    ZeroMemory(szCrypt,64);
    DWORD type = REG_SZ;

    //Append a CRC to the current system time
    sprintf(szCrypt,"%08X%04X",lTime,ComputeCRC(lTime));

    //Encrypt the current system time
    if (!Encrypt(szCrypt,"UnbreakableKey",szReg,64))
        return false;

    //Set the CURRENT_TIME
    if(RegSetValueEx(MyKey, "CURRENT_TIME", (DWORD) 0, REG_SZ,
        (LPBYTE) szReg, 64) != ERROR_SUCCESS)
    {
        RegCloseKey (MyKey);
        cout << "Error: RegSetValueEx failed on CURRENT_TIME\n";
        return false;
    }

    return true;
}

void GetCookie(char *cookie)
{
    long lTime = time(NULL);
    char szCrypt[64];
    ZeroMemory(szCrypt,64);

    //Append a CRC to the current system time
    sprintf(szCrypt,"%08X%04X",lTime,ComputeCRC(lTime));

    //Encrypt the current system time
    Encrypt(szCrypt,"UnbreakableKey",cookie,64);
}