Click here to Skip to main content
15,884,537 members
Articles / Desktop Programming / Windows Forms

How to Generate (and Validate) CD-Keys for your Software

Rate me:
Please Sign up or sign in to vote.
4.22/5 (31 votes)
6 Aug 2012CPOL6 min read 250.4K   20K   188   58
An example of how to implement and validate non-personal CD-Keys (ideal for distribution on the back of CD cases)

WARNING WARNING WARNING: 

There is a flaw in this implementation: please do not use the inbuilt .Net Random class, as it could possibly change depending on your .Net version installed! Find a secure third party random number generator for more reliable results. 

NOTE: Code(B)lock is a fictional codename I came up with, and any references to any existing companies or products are purely unintentional. 

Image 1

Introduction 

The purpose of this article is to provide examples on how to implement a CD-Key system into your software. I've currently done everything in VB.NET, but I will get C# examples here sometime.

By way of example, here's six keys that my little generator has made:

VRW2Z-S4AUU-SNQN1-C2DYA-BFOML
2B49S-120SK-8AZR6-RH4SX-ALXDS
ON7R2-NAAN6-NMX5B-5FGO6-5FBQO
QS8ND-G0W76-BTSQO-WAAJA-6LCD3
KOPV3-400IV-AXQ46-BQBEJ-O1IQN
D8TVZ-80AGU-6T2QA-FCZJV-1GXFE

Background

Anti-piracy is a major part of any commercial software design cycle. I'm not going to talk about what you should and shouldn't do (which is covered in an excellent article, Piracy and Unconventional Wisdom), but rather demonstrate an unobtrusive but effective system to distribute protected software through CDs. Please note that this system is not the best choice if your users are downloading the application: a signed XML licence or an activation based licence are better choices in this case.

The Theory

Each key is generated from a random number between 0 and 60466175. This means there are 60466176 unique codes! This number was chosen for the simple fact that it is 36^5: the highest number of possibilities if you have five characters that are anywhere from A-Z or 0-9. After using this key, I then created a base-36 conversion system (you might know its relatives, hexadecimal (e.g. #FFCC00) or octal). I won't discuss bases or how I did the conversion here, but you can look at the demo source if you are interested.

The number that is generated (which from now on I will call the ‘key’), is then converted to Base-36 (e.g. 14624617 becomes “8PGFD”), and then made the first five characters of the serial code. This will allow us to verify and/or reconstruct the code, if we know the key at the start.

The Non-Random Random (Integer)

If you've ever used random numbers in your applications before, you'll probably have used something like this: 

VB.NET
Dim Pickle as New Random
Dim rnd as Integer
rnd = Pickle.Next(0,9)

What you might not have realized though is that it is equivalent to:

VB.NET
Dim gherkin as New Random(TruelyRandomNumber)
Dim rnd as Integer
rnd = gherkin.Next(0,9)

See, when you use...

VB.NET
Dim r as new Random(Integer)

... it initializes it with a seed, meaning if you do the exact same steps in the exact same order, you will get the exact same (not random) result.

So this is how we confirm and generate our serials: we get the key, use it to initialize the random, and then we put it into the serial (or the regular expression when checking). Then the rest of the serial is generated using the random we made from the key, and the usage of the arrays as we now discuss.

The Arrays and You

These arrays are one of the most powerful things about this protection system. The idea comes from a particular method of validating keys, called 'Partial Key Verification'. (It used to have a Wikipedia page, but it doesn't now). The theory behind partial key verification is that it only validates (surprise surprise), part of the key. For example, you could use regular expressions to validate the key like this:

Code:
G9QT1-P31UN-K2MB9-J3DE5-2UCTO

Validating String:
G9QT1-P...N-.....-...E.-2....

Also termed as correct:

G9QT1-PLXMN-HAHAH-AHAES-2IEVE

You may consider this strange, and believe it works like a sieve, but it all works out in the long run: say if you validate five characters, that means the pirate still has to get 10 characters correct: the first five (the key), and another five. This means they'll have a chance of 1 in 36^10 (1 in 3656158440062976) of actually entering a working key. This effectively eliminates brute-force methods. And if you make the program pause for about two seconds (or even better, take longer for each attempt), brute-force attempts become pathetic jokes.

You'll probably still be wondering what the big idea is though. Why only validate a few characters?

What the Pirates (Th/S)ink

How does a pirate go about pirating your software? Well it depends: if you haven't obfuscated/bootstrapped or otherwise protected your .NET app, they can simply decompile the source-code, and build a keygen. Ouch. But if you have taken these precautions, they generally will be reduced to going through every byte of your program (at runtime if necessary). Ouch! Now pirates aren't necessarily lazy, but they're not (generally) stupid either. If it is too hard to build a working keygen, they'll simply create a patch that will remove your checking code. Unfortunately, there is no real way to protect against this. And if you don't believe me, see how many patches there are for various editions of Windows that remove activation. However, this means (not in the case of Windows though), that they have to make a new patch for every version of your program. This is what we are aiming for. After all, as that page I linked to earlier says, the goal of anti-piracy is to make it easier to buy your program than pirate it.

Now, to tie this with the arrays: say if a pirate finds your checking code and reverses it. Great, they now have a keygen. This is the last thing you want, because that makes it simpler to pirate than to buy it now. So what do we do when this happens? The answer is, we either cycle or add arrays to check. If you add one array, the chance of producing a working key now becomes 1 in 36. Two arrays? 1 in 1296. You get the idea. So if you add two arrays, it's once again easier to buy than pirate it again! The pirate might then go and build a later keygen, and so the cycle continues. Hopefully, by the time you run out of arrays (REMEMBER TO KEEP 2 or 3 for yourself/your website!!!), you should be up to another paid version, which would use different keys. Make sense? This is the essence of partial key verification.

Using the Code

If you want to use the code, just grab the demo project's source, then copy, but make sure to change the arrays!

You'll also want to try making some things different. For example:

  • Use modulus (Mod) to split your 'key' between the five clumps (of five characters), making it less obvious.
  • Invert the number used as a key.
  • And plenty more things (which I won't mention, so that they'll be unique to your program)

But the main idea is, the more unique it is, the better it is for you.

Points of Interest

You do need to be fairly careful when using this code: under a base-36 system, you will (eventually) end up generating serial codes that start with obscenities: you'll probably have to remove somewhere up to 200 possible codes. This won't really do much though, as this only drops the maximum to somewhere around 60465900, which should (hopefully) be enough.

History

  • 5th of April, 2009 - v1.0 - First edition 

License

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


Written By
Student
Australia Australia
I'm current a university student, studying for a Bachelor of IT. I have learned to work with many languages, love a good challenge, and a witty repartee.
I've been programming since 2006.

Comments and Discussions

 
Questioncould you update a C# version? Pin
Member 1015806316-Jul-13 3:26
Member 1015806316-Jul-13 3:26 
SuggestionWrong Validating Pin
Christianirwan27-Jun-13 0:42
Christianirwan27-Jun-13 0:42 
QuestionCovert to C# Pin
ch_adnan24-Aug-12 23:44
ch_adnan24-Aug-12 23:44 
AnswerRe: Covert to C# Pin
dawmail33325-Aug-12 0:01
dawmail33325-Aug-12 0:01 
GeneralRe: Covert to C# Pin
ch_adnan25-Aug-12 1:47
ch_adnan25-Aug-12 1:47 
GeneralRe: Covert to C# Pin
dawmail33325-Aug-12 5:06
dawmail33325-Aug-12 5:06 
GeneralRe: Covert to C# Pin
ch_adnan25-Aug-12 6:44
ch_adnan25-Aug-12 6:44 
GeneralRe: Covert to C# Pin
ch_adnan25-Aug-12 8:17
ch_adnan25-Aug-12 8:17 
GeneralRe: Covert to C# Pin
ch_adnan31-Aug-12 22:27
ch_adnan31-Aug-12 22:27 
GeneralRe: Covert to C# Pin
dawmail33331-Aug-12 22:31
dawmail33331-Aug-12 22:31 
GeneralRe: Covert to C# Pin
ch_adnan7-Sep-12 11:45
ch_adnan7-Sep-12 11:45 
GeneralRe: Covert to C# Pin
Eddie Y Chen22-Sep-12 22:22
Eddie Y Chen22-Sep-12 22:22 
GeneralRe: Covert to C# Pin
Eddie Y Chen22-Sep-12 23:52
Eddie Y Chen22-Sep-12 23:52 
GeneralRe: Covert to C# Pin
dawmail33323-Sep-12 0:50
dawmail33323-Sep-12 0:50 
GeneralRe: Covert to C# Pin
Eddie Y Chen23-Sep-12 2:36
Eddie Y Chen23-Sep-12 2:36 
GeneralRe: Covert to C# Pin
dawmail33323-Sep-12 2:50
dawmail33323-Sep-12 2:50 
GeneralMy vote of 4 Pin
Disactive17-Aug-12 2:51
Disactive17-Aug-12 2:51 
QuestionGood but Old Pin
Tarun Mangukiya9-Aug-12 21:40
Tarun Mangukiya9-Aug-12 21:40 
GeneralMy vote of 4 Pin
Muhammad Shahid Farooq8-Aug-12 21:18
professionalMuhammad Shahid Farooq8-Aug-12 21:18 
SuggestionOutdated Pin
Member 93351848-Aug-12 8:26
Member 93351848-Aug-12 8:26 
GeneralGood information and enlightening Pin
machv520-Jul-12 17:03
machv520-Jul-12 17:03 
GeneralMy vote of 5 Pin
machv520-Jul-12 16:33
machv520-Jul-12 16:33 
GeneralRandom Ain't Random Pin
Simon Bridge29-May-11 15:20
Simon Bridge29-May-11 15:20 
GeneralRe: Random Ain't Random Pin
dawmail33329-May-11 20:35
dawmail33329-May-11 20:35 
QuestionC# Version Pin
Ashley_H6-Nov-10 8:56
Ashley_H6-Nov-10 8:56 

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.