Click here to Skip to main content
15,902,445 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 251.3K   20.1K   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

 
GeneralRe: [My vote of 2] what if some one has a key? Pin
Priyank Bolia5-Apr-09 18:41
Priyank Bolia5-Apr-09 18:41 
GeneralRe: [My vote of 2] what if some one has a key? Pin
dawmail3335-Apr-09 20:40
dawmail3335-Apr-09 20:40 
GeneralRe: [My vote of 2] what if some one has a key? Pin
Scott Barbour7-Apr-09 12:39
Scott Barbour7-Apr-09 12:39 
GeneralRe: [My vote of 2] what if some one has a key? Pin
dawmail3337-Apr-09 20:37
dawmail3337-Apr-09 20:37 
GeneralRe: [My vote of 2] what if some one has a key? Pin
jweinraub18-Nov-11 10:00
jweinraub18-Nov-11 10:00 
GeneralRe: [My vote of 2] what if some one has a key? Pin
dawmail3335-Apr-09 20:40
dawmail3335-Apr-09 20:40 
GeneralRe: [My vote of 2] what if some one has a key? Pin
jedCodeProject15-Jul-09 21:41
jedCodeProject15-Jul-09 21:41 
GeneralRe: [My vote of 2] what if some one has a key? Pin
Priyank Bolia15-Jul-09 22:36
Priyank Bolia15-Jul-09 22:36 
Well, I think I had already explained why the method given in the article is so inferior that it won't be used in any professional code, in my message above.

Now, regarding what should be done. This is a big article in itself, and also as some of my programs uses some advanced anti piracy measures I don't wanna disclose all those details.

But there are few general things, that would be helpful:

1.) Identify how much you want to frustrate your users and how much time you want to spend on anti piracy measures. Most commercial programs that uses machine ID, etc. would definitely raises users eyebrows, but given enough development effort and better design this limitation can be also be overcome. Given enough time, every software is breakable, its just matter of how good your software is to be of any interest to an hacker. Unethical pricing and software patents doesn't help business grow.
2.) Release early and frequently, is also one policy that keep piracy away. Companies who releases often, feels less piracy heat, as users want to upgrade to the latest software ASAP. Change registration algorithm in every major release, to keep more pressure on hackers.
3.) Piracy protection is not about keys and blocking them. It consists on n number of things performed in sync to achieve any meaningful results. Like for .NET obfuscation, anti assembly tampering, and user keys management all forms a single atomic component.
4.) Protection doesn't mean spending additional money or resources and time. E.g. you don't need to spend on digital certificates for anti-tampering, etc. As removing a digital certificate is an script kiddie job. Also there are tons of anti-piracy components available promising big things. But, I couldn't find even a single one that is good enough and goes well with the overall software. Spending money on those things is a waste IMHO.
5.) Instead of putting a simple key based security, where if your key is known the battle is lost, you can choose to go for more advanced algorithms, like region based protection, validation against server, RSA cryptographic keys, etc.
6.) My question at http://stackoverflow.com/questions/506282/protect-net-code-from-reverse-engineering will help you to learn more.

That's all for the day.


GeneralRe: [My vote of 2] what if some one has a key? Pin
dawmail33315-Jul-09 22:45
dawmail33315-Jul-09 22:45 
GeneralRe: [My vote of 2] what if some one has a key? Pin
Priyank Bolia15-Jul-09 23:01
Priyank Bolia15-Jul-09 23:01 
GeneralRe: [My vote of 2] what if some one has a key? Pin
dawmail33316-Jul-09 20:59
dawmail33316-Jul-09 20:59 
GeneralRe: [My vote of 2] what if some one has a key? Pin
kelvin199715-Sep-09 17:38
kelvin199715-Sep-09 17:38 

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.