# Implementation of the Licensing System for a Software Product

By , 5 Aug 2010

## Introduction

This article is devoted to the development of the key licensing system for the applications. In the theoretical part of the article, we will examine the cryptography methods, which can be used while implementing the licensing system. Also, we will discuss all pros and cons of these methods and select the possible ones for using in the application. In the practical part of the article, we will provide the implementation of the simplest licensing system, which guaranties the protection from cracking even if a hacker knows the source code of an algorithm.

## Types of Algorithms

The cryptographic algorithm, also called cipher, is a mathematical function used for encryption and decryption. Usually, these are two interconnected functions: one is used for encryption, another is for decryption.

If the reliability of the algorithm is based on keeping the algorithm itself in secret, then this algorithm is limited. Limited algorithms do not correspond to the nowadays standards and represent only the historical value.

The modern cryptography solves these problems with the help of the key. The key can be of any value selected from a wide range of values. The set of possible keys is called the key space.

There are two main types of algorithms based on the key usage: symmetric-key algorithm and algorithm with the public key.

Symmetric-key algorithms, sometimes called the conditional algorithms, are the algorithms where the encryption key can be calculated by the decryption key and vice versa. The encryption and decryption keys are the same in most symmetric-key algorithms. These algorithms, also called one-key or secret-key algorithms, require that the sender and the recipient reconcile the used key before the beginning of the secure message exchange. The safety of the symmetric-key algorithms is defined by the key. The key disclosure means that anyone can encrypt and decrypt messages. The key must be kept in secret as long as the transmitted messages should be secret.

Algorithms with the public key, also called asymmetric-key algorithms, are developed in a way that the key used for the encryption differs from that for decryption. Moreover, the decryption key can't be calculated by the encryption key (at least, during the reasonable period of time). These algorithms are called “algorithms with the public key” because the encryption key can be open: anyone can use the encryption key for the encryption of the message but only one concrete person can decrypt the message with the corresponding decryption key. In these systems, the encryption key is often called the public key and the decryption key is called the private key. The private key is sometimes called the secret key.

It is obvious that the only type of the algorithm which suits us is the algorithm with the public key because we have to store the key in the program for the authentication of the entered serial key. When choosing these algorithms, we have the guarantee that the intruder, having the public key and the source code of the algorithm, won't be able to make the key generator and create serial keys for another program copies.

There are many computer algorithms. The following three algorithms are most frequently used:

• DES (Data Encryption Standard) is the most popular computer encryption algorithm. It is the American and international standard. It is the symmetric-key algorithm where one and the same key is used for encryption and decryption.
• RSA (which stands for Rivest, Shamir and Adleman who first publicly described it) is the most popular algorithm with the public key. It is used both for the encryption and for digital signature.
• DSA (Digital Signature Algorithm, is used as the part of the Digital Signature Standard) is another algorithm with the public key. It is used only for the digital signature and can’t be used for the encryption.

DES does not suit us because it is the symmetric-key algorithm.

Two algorithms are left: RSA and DSA. It is easy to choose between them if we look at the structure of the work of these algorithms.

RSA uses the public key for the creation of the cipher text from the source text. We don't need it as it is supposed that we create and send keys and they will be decrypted and compared with the source value on the client side. As it was mentioned above, we can use only the public key on the client side in order not to compromise the licensing system.

Now some words about the work of DSA. Using the source text, DSA calculates the hash code and then “decrypts” it using the private key and receives the required serial key. It “encrypts” the received value on the client side and receives the hash code. Then it calculates the hash code from the source text in the usual way and compares two values. If these values coincide, then the serial key is valid.

The Crypto++® Library contains the implementation of many algorithms. I used this library in the example. For more information, see http://www.cryptopp.com/.

```................................
bool RsaVerifyVector(const std::string & publicKeyStrHex,
const std::string& source, const std::vector<char>& sign)
{
CryptoPP::HexDecoder decoder;
decoder.Put( (byte*)publicKeyStrHex.c_str(), publicKeyStrHex.size() );
decoder.MessageEnd();

CryptoPP::RSA::PublicKey publicKey;

// Verifier object
CryptoPP::RSASS<CryptoPP::PSS, CryptoPP::SHA1>::Verifier verifier( publicKey );

std::vector<char> rawSignature;
std::string signStr(utils::GetBeginOf(sign), sign.size());
utils::FromHexString(utils::string2wstring(signStr), &rawSignature);
// Verify
const char * pData = utils::GetBeginOf(source);
return verifier.VerifyMessage( (const byte*) pData,
source.size(), (const byte*) utils::GetBeginOf(rawSignature),
rawSignature.size() );
}
………………………………………………
void RsaSignVector(const std::string & privateKeyStrHex,
const std::vector<char> & vec, std::string & sign)
{
// Pseudo Random Number Generator
CryptoPP::AutoSeededRandomPool rng;
// Generate Parameters
CryptoPP::InvertibleRSAFunction params;
params.GenerateRandomWithKeySize( rng, 1536 );

CryptoPP::HexDecoder decoder;
decoder.Put( (byte*)privateKeyStrHex.c_str(), privateKeyStrHex.size() );
decoder.MessageEnd();

CryptoPP::RSA::PrivateKey privateKey; // Private

CryptoPP::RSASS<CryptoPP::PSS, CryptoPP::SHA1>::Signer signer( privateKey );

size_t length = signer.MaxSignatureLength();
CryptoPP::SecByteBlock signature( length );

// Sign message
signer.SignMessage( rng, (const byte*) utils::GetBeginOf(vec),
vec.size(), signature );

sign  = utils::wstring2string
(utils::ToHexString<byte>(signature, signature.size()));
}
………………………………………
void RsaGenerateStringKeys(std::string & publicKeyStr, std::string & privateKeyStr)
{
// Pseudo Random Number Generator
CryptoPP::AutoSeededRandomPool rng;

// Generate Parameters
CryptoPP::InvertibleRSAFunction params;
params.GenerateRandomWithKeySize( rng, 1536 );

CryptoPP::RSA::PrivateKey privateKey( params );
CryptoPP::RSA::PublicKey publicKey( params );

CryptoPP::HexEncoder encoder;

// save public Key
encoder.Attach( new CryptoPP::StringSink( publicKeyStr ) );
publicKey.Save( encoder );

// save private Key
encoder.Attach( new CryptoPP::StringSink( privateKeyStr ) );
privateKey.Save( encoder );
}
………………………………```

## Hardware Serial Key

We need to have the unique identifier of the computer in order to make sure that our serial key is used on the computer where we granted a license. There are many methods of its obtaining. But we chose HardDisk Serial Key for this case. It has a rather readable form and small size, but the probability of collisions is very low.

```BOOL CSmartReader::ReadSMARTInfo(BYTE ucDriveIndex)
{
HANDLE hDevice=NULL;
WCHAR wTempDriveName[MAX_PATH]={0};
BOOL bRet=FALSE;
DWORD dwRet=0;

wsprintf(wTempDriveName,L"\\\\.\\PHYSICALDRIVE%d",ucDriveIndex);
FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM,NULL);
if(hDevice!=INVALID_HANDLE_VALUE)
{
bRet=DeviceIoControl(hDevice,SMART_GET_VERSION,NULL,0,
&m_stDrivesInfo[ucDriveIndex].m_stGVIP,sizeof(GETVERSIONINPARAMS),&dwRet,NULL);
if(bRet)
{
if((m_stDrivesInfo[ucDriveIndex].m_stGVIP.fCapabilities &
CAP_SMART_CMD)==CAP_SMART_CMD)
{
if(IsSmartEnabled(hDevice,ucDriveIndex))
{
bRet=CollectDriveInfo(hDevice,ucDriveIndex);
}
}
}
CloseHandle(hDevice);
}
return bRet;
}
……………………
{
BOOL bRet = FALSE;
SENDCMDINPARAMS stCIP = {0};
DWORD dwRet = 0;
char szOutput[OUT_BUFFER_SIZE] = {0};

stCIP.cBufferSize=IDENTIFY_BUFFER_SIZE;
stCIP.bDriveNumber =ucDriveIndex;
stCIP.irDriveRegs.bFeaturesReg=0;
stCIP.irDriveRegs.bSectorCountReg = 1;
stCIP.irDriveRegs.bSectorNumberReg = 1;
stCIP.irDriveRegs.bCylLowReg = 0;
stCIP.irDriveRegs.bCylHighReg = 0;
stCIP.irDriveRegs.bCommandReg = ID_CMD;

bRet=DeviceIoControl(hDevice,SMART_RCV_DRIVE_DATA,&stCIP,
sizeof(stCIP),szOutput,OUT_BUFFER_SIZE,&dwRet,NULL);
if(bRet)
{
CopyMemory(&m_stDrivesInfo[ucDriveIndex].m_stInfo,
szOutput+16, sizeof(ST_IDSECTOR));
ConvertString(m_stDrivesInfo[ucDriveIndex].m_stInfo.sSerialNumber, 20);
}
else
{
dwRet=GetLastError();
}
return bRet;
}```

As can be seen, we receive the information about hard drives, including the `sSerialKey`, which was mentioned above.

So, we have the algorithms of signing, verification, and acquiring of the disk serial number.

## The Scheme of the Licensing System

We can see the common scheme of the work of the licensing system.

The `LicenseManager `source code is the following:

```……………………………………………………
std::string publicKey;
std::string privateKey;

std::vector<char> vecPrivate;

utils::SaveResToVector(L"PRIVATE_KEY", IDR_FILE_PRIVATE_KEY, &vecPrivate );

//this is an example of how to generate public and private keys
//you need to save them in .rc files or somewhere else after they are first generated
if (vecPrivate.empty())
{
utils::RsaGenerateStringKeys(publicKey, privateKey);
std::vector<char> vecPublic(publicKey.begin(), publicKey.end());
vecPrivate.assign(privateKey.begin(), privateKey.end());
utils::SaveVectorToFile(L"keys\\private.bin", vecPrivate);
utils::SaveVectorToFile(L"keys\\public.bin", vecPublic);
}
else
{
privateKey.assign(vecPrivate.begin(), vecPrivate.end());
}

std::string sign;

std::vector<char> smallFile;
std::string serialKey;

//Input the hardware serial key, that your client application will give you
std::cout << "Input your serial key here : ";
std::cin >> serialKey;

//make it vector and sign using utils
std::vector<char> hardwareSerialKey(serialKey.begin(), serialKey.end());
utils::RsaSignVector(privateKey, hardwareSerialKey, sign);

//save signed value to the file and send the file to user
std::vector<char> vec(sign.begin(), sign.end());

std::cout << "Your license.dat file was saved in program's directory" << std::endl;
std::cout << "Press any key...";
std::cin.get();

return 0;
……………………………```

The client side looks like the following:

```………………………………………
std::string publicKey;
std::vector<char> vecPublic;
utils::SaveResToVector(L"PUBLIC_KEY", IDR_FILE_PUBLIC_KEY, &vecPublic);
if (vecPublic.empty())
{
std::cout << "Cant find public key\nPress Any key..." << std::endl;
std::cin.get();
return 0;
}
publicKey.assign(vecPublic.begin(), vecPublic.end());

ST_IDSECTOR *pSectorInfo = NULL;

std::string str(pSectorInfo->sSerialNumber);

std::stringstream trimmer;
trimmer << str;
trimmer >> str;

std::cout << "Your hardware Serial Key is : " << str << std::endl;

try
{
std::vector<char> vec;

if (utils::RsaVerifyVector(publicKey, str, vec))
{
std::cout << "License is valid. Continue working" << std::endl;
}
else
{
std::cout << "License is invalid. Program is being closed" << std::endl;
}
}
catch(const std::logic_error& ex)
{
std::cout << "You do not have license.dat file installed.
Please put it in program dir." << std::endl;
}

std::cout << "Press any key...";
std::cin.get();
……………………………………………………```

## The Folders Structure

• .\ClientTest – The client side
• .\DigitalSignature – The License Manager side
• .\Utils – Utilities and wrappers for the Crypto++® Library
• .\ cryptopp560 – Crypto++® Library

## Bibliography List

1. C.M. Adams and H. Mailer, "Security Related Comments Regarding McEliece's Public-Key Cryptosystem" Advances in Cryptology CRYPTO '87 Proceedings, Springer-Verlag, 1988, pp. 224-230.
2. Cylink Corporation, Cylink Corporation vs. RSA Data Security, Inc., Civil Action No. C94-02332-CW, United States District Court for the Northern District of California, 30 Jun 1994.
3. G.I. Davida, "Chosen Signature Cryptanalysis of the RSA iMITJ Public Key Cryptosystem," Technical Report TR-CS-82-2, Department of EECS, University of Wis- consin, 1982.
4. I.M. DeLaurentis, "A Further Weakness in the Common Modulus Protocol for the RSA Cryptosystem," Cryptologia, v. 8, n. 3, Jul 1984, pp. 253-259.
5. Schneier, Bruce. Applied Cryptography, Second Edition, John Wiley & Sons, 1996. ISBN 0-471-11709-9.

## History

• 5th August, 2010: Initial post

 Apriorit Inc Apriorit Inc. Ukraine Member Organisation 31 members
ApriorIT is a Software Research and Development company that works in advanced knowledge-intensive scopes.

Company offers integrated research&development services for the software projects in such directions as Corporate Security, Remote Control, Mobile Development, Embedded Systems, Virtualization, Drivers and others.

Official site http://www.apriorit.com

 Sergii Bratus Software Developer Apriorit Inc. Ukraine Member
No Biography provided

Votes of 3 or less require a comment

 Search this forum Profile popups    Spacing RelaxedCompactTight   Noise Very HighHighMediumLowVery Low   Layout Open AllThread ViewNo JavascriptPreview   Per page 102550
 First Prev Next
 Windows 7 Compatibality Issues Rajan Paudel 17 Sep '12 - 21:23
 This is great article. I tried this in windows XP and it works well. Does this code works well in windows 7? What should I do to use this code in windows 7? Sign In·View Thread·Permalink
 My vote of 5 gndnet 11 Sep '12 - 0:23
 My vote of 5 gndnet 18 Jul '12 - 0:02
 My vote of 5 gndnet 17 Jul '12 - 15:35
 Possible hack for this implementation Nizam11 15 Feb '12 - 0:21
 Hi Sergii. Thanks for this informative article. Really appreciate it. I would like to find out if is it possible to hack the software implementing this algorithm by shipping the software with the public key replaced with a copy of the hacker's self-generated public key. That way, when a user sends the harddrive serial key to the hacker, he can generate the license.dat file using his private key since the public key shipped with the software to the user is the public key pair generated by the hacker. Am I right to say so? This is partly due to the fact that your code load the public key from a file. As far as I know the public key should be at least hard-coded in the software right? Sign In·View Thread·Permalink
 Question about self-decryption yasihunter 13 Apr '11 - 3:28
 Re: Question about self-decryption Sergii Bratus 13 Apr '11 - 23:00
 This is very complicated task and it requires a lot of research - first of all I wouldn't recommend you to store PRIVATE key in the code anyhow. You can use reverse scheme and use private key for crypting and public for decrypting ( this is described in the article ) and you'll be able to save public key, but this all just sounds bad for me. Thanks to the internet we can find a lot of info - and first you probably want to look at is Polymorphic Encryption Methods with it's key techniques such as saving a static key, or saving the key that is changing all the time, or еру key that has external dependencies or even without a key - using just bit operations. Hope you'll find there answer you need. Good luck ) Sign In·View Thread·Permalink
 My vote of 5 gndnet 8 Jan '11 - 20:45
 Multiple application [modified] aldo hexosa 5 Oct '10 - 23:41
 How to implement this licensing system if i have 2 application? I need different license key for each application. Thanks for your great article modified on Wednesday, October 6, 2010 5:47 AM Sign In·View Thread·Permalink
 My vote of 5 vcop25 4 Oct '10 - 5:27
 how to avoid if(A==B)? NewttleLi 1 Sep '10 - 20:50
 Re: how to avoid if(A==B)? Chris Losinger 17 Jan '12 - 3:59
 there is no way to avoid it. at some point you have to compare the two values, either directly or indirectly. image processing toolkits | batch image processing Sign In·View Thread·Permalink
 why is 1536? ftai 24 Aug '10 - 20:48
 My vote of 5 Member 4320844 15 Aug '10 - 11:17
 Timed License JeffBilkey 11 Aug '10 - 14:33
 Have you given any thought to a Timed License such as one the lasts for seven days. I believe you would need to hide something on the computer with the start or expirey date. However with the later versions of windows it is getting more and more difficult to hide a file or something in the registry, that can't be easily found and deleted. Sign In·View Thread·Permalink
 Suggestions.... VaKa 11 Aug '10 - 9:06
 Very interesting topic. But with good start we have bad finish... or didnt get it at all   I think, it will be more useful explain what you do but not paste here blocks of uncommented code.   For example, only from function headers I know that you use RSA (or i miss something )   What coder should do to change you code if he (or she ) want deal with, mmm, "login name" in corporate network or whatever...?   Good start anyway   --------------------------------------- Aaaah, my pure english Sign In·View Thread·Permalink
 Need more explanation PatLeCat 9 Aug '10 - 23:18
 I like the topic very much and I thought you started well with explaning at the beginning. Unfortunately you stop explaining once the 1st line of code appears. You could for example explain the steps in your nice looking scheme diagram and also add more explanation to the code and why you did what you did. After all, an expert in the field doesn't need to read your article, us novices do   How to protect the client AND the license manager from being hacked to easily would also be an important chapter to add - methinks. Sign In·View Thread·Permalink
 My vote of 3 PatLeCat 9 Aug '10 - 23:14
 Good start. John M. Drescher 8 Aug '10 - 4:29
 However I would caution the readers that this is only a start. Any successful licencing system has to protect the client application from tampering otherwise it would take 5 minutes to remove the licence check for even a novice hacker. John Sign In·View Thread·Permalink
 Re: Good start. S.H.Bouwhuis 9 Aug '10 - 22:22
 I agree. I've been in software development for well over 10 years now and I have come to realize that (software) protection doesn't work. It just keeps honest people honest. Any determined hacker can decompile your application and remove the triggers. Apps like Windows and Photoshop, games like GTA and COD:MW2, machines like Xbox and Nintendo DS, carriers like DVD and BluRay, ... everything has been cracked. Sign In·View Thread·Permalink
 Re: Good start. VaKa 11 Aug '10 - 9:08
 Excellent Article! -- My vote of 5 Sharjith 6 Aug '10 - 11:17
 Great, Well explained article on licensing. This kind of knowledge is seldom exposed by professionals to the common world. Regards N. Sharjith Sign In·View Thread·Permalink
 great work mounte@cognimatics 6 Aug '10 - 2:52
 Great work explaining a basic licensing scheme. Do you have any suggestions on revoking a license, protect it from spoofing (if a user can spoof the hardware information from an authorized user he could use the same license key)? Sign In·View Thread·Permalink
 My vote of 5 emilio_grv 6 Aug '10 - 2:18
 COOL! LoveVc 5 Aug '10 - 15:58
 Re: COOL! rmarion 6 Aug '10 - 7:13
 Re: COOL! LoveVc 8 Aug '10 - 14:49