Click here to Skip to main content
Click here to Skip to main content

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

, 6 Aug 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
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. 

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: 

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:

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

See, when you use...

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)

Share

About the Author

dawmail333
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? PinmemberMember 1015806316-Jul-13 4:26 
SuggestionWrong Validating PinmemberChristianirwan27-Jun-13 1:42 
QuestionCovert to C# Pinmemberch_adnan25-Aug-12 0:44 
AnswerRe: Covert to C# Pinmemberdawmail33325-Aug-12 1:01 
GeneralRe: Covert to C# Pinmemberch_adnan25-Aug-12 2:47 
GeneralRe: Covert to C# Pinmemberdawmail33325-Aug-12 6:06 
GeneralRe: Covert to C# Pinmemberch_adnan25-Aug-12 7:44 
GeneralRe: Covert to C# Pinmemberch_adnan25-Aug-12 9:17 
GeneralRe: Covert to C# Pinmemberch_adnan31-Aug-12 23:27 
GeneralRe: Covert to C# Pinmemberdawmail33331-Aug-12 23:31 
GeneralRe: Covert to C# Pinmemberch_adnan7-Sep-12 12:45 
GeneralRe: Covert to C# PinmemberEddie Y Chen22-Sep-12 23:22 
GeneralRe: Covert to C# [modified] PinmemberEddie Y Chen23-Sep-12 0:52 
GeneralRe: Covert to C# Pinmemberdawmail33323-Sep-12 1:50 
GeneralRe: Covert to C# PinmemberEddie Y Chen23-Sep-12 3:36 
GeneralRe: Covert to C# Pinmemberdawmail33323-Sep-12 3:50 
GeneralMy vote of 4 PinmemberDisactive17-Aug-12 3:51 
QuestionGood but Old PinmemberTarun Y Mangukiya9-Aug-12 22:40 
GeneralMy vote of 4 PinmemberMuhammad Shahid Farooq8-Aug-12 22:18 
SuggestionOutdated PinmemberMember 93351848-Aug-12 9:26 
GeneralGood information and enlightening Pingroupmachv520-Jul-12 18:03 
GeneralMy vote of 5 Pingroupmachv520-Jul-12 17:33 
GeneralRandom Ain't Random PinmemberSimon Bridge29-May-11 16:20 
GeneralRe: Random Ain't Random Pinmemberdawmail33329-May-11 21:35 
QuestionC# Version Pinmembersome-_16-Nov-10 9:56 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.1411023.1 | Last Updated 7 Aug 2012
Article Copyright 2009 by dawmail333
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid