5,448,416 members and growing! (19,034 online)
Email Password   helpLost your password?
General Programming » Cryptography & Security » Security     Intermediate License: The Code Project Open License (CPOL)

A simple but robust software protection and activation

By BruceWang_korea

A simple but robust software protection and activation.
C#, Windows, .NET 2.0, .NETVisual Studio, VS2005, Dev

Posted: 6 Oct 2006
Updated: 18 Jun 2007
Views: 84,599
Bookmarked: 157 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
20 votes for this Article.
Popularity: 5.72 Rating: 4.40 out of 5
1 vote, 5.0%
1
0 votes, 0.0%
2
0 votes, 0.0%
3
4 votes, 20.0%
4
15 votes, 75.0%
5

Regarding sample application

In the original article, I posted a code snippet of "encrypt and sign" and "decrypt and validate." However, this was not enough to solve our friends' difficulties. Because of a lack of time, I couldn't make a fully working server and client test application. Nor could I even cut and paste some code from my current products. Instead I decided to post my old application, which was just for my learning purposes. It turned out to be very simple, so I think my new application samples will give you a clearer understanding. My new samples enable you to select a certificate from your machine's certificate storage, show the information of the selected certificate, encrypt a given string with the certificate and then decrypt the encrypted string.

Introduction

Protecting desktop applications has been a kind of "hide and seek" game so far. Even though you twist and add protection methods, crackers may still find a "jump" command from your compiled binary and change it to "nothing." As a result, protection techniques have become more painful and much too sophisticated. The situation became somewhat different for programmers when Microsoft's .NET Framework came out. If we can utilize the new security infrastructures that the .NET Framework provides, we can protect our desktop applications very, very easily. You don't need to twist your final assembly codes or install special device drivers or kernel level hooks.

The security level of the techniques in this article is not very high, but it is good enough I think. I summarize this issue as a conclusion at the end of this article. We can still discuss and find better solutions, I hope. I didn't attach any proper "executable binaries" for instant testing because I do not believe it is that difficult for you to just copy and paste my code to where you want it. If you read my article once, then you should have no problems using my code. I hope you understand that this is just a conceptual introduction.

Background

For your ease of understanding, it will be better if you know some basic concepts of PKI and "Strong names" in the .NET Framework. I also have a basic understanding of PKI, but not a full mathematical understanding of how RSA works. So, I previously asked some stupid questions like, "Can I decrypt a message with a public key instead of a private key? I don't mean 'Sign'..." At that time, everybody asked me in turn, "Why do you want to do that?" and "You just sign/verify, man."

However, I wanted to know whether it was possible in C# or mathematically impossible. That's OK, though. You don't have to worry too much. ;) I will try to explain briefly and plainly.

Strong name

You can think of "Strong names" in the .NET Framework as being a little bit similar to "Authenticode." It is signing your assembly files. Once your main .NET Framework application is signed, the loader of the application -- i.e. the .NET Framework -- will check file integrity. So if a hacker changes code in that file, the application loader will just show an error and will not start the application. You can check it by building with Strong name and then editing the code area of your application.

One thing you need to know is that if your main application refers to other assemblies, then those other assemblies need to have Strong names as well. Maybe some of you will feel overly constrained about this restriction. However, it is not actually a restriction and is quite reasonable.

Flows

This scenario requires a server and a client. The server can be a web service or your own network service. The client here is a desktop application.

1. Distribute keys

First of all, you need to issue two certificates either from the "Certificate service" of Windows 2003 Server or by using MakeCert.exe from the .NET Framework SDK. One is for the server and the other is for the client. Then you enroll and you also need to make a private key. I prefer making those certificates as *.pfx files because loading private key information from a *.pvk file seems very difficult in C# right now. For more information, please refer to MSDN.

Now in your server side, please register the two certificates. The server should be able to use its own private key and should use only the public key of the client. Distribute the server's certificates with only the public key (i file) and the client's private key.

2. Register a customer on your server side

You can make your own customer DB containing the customer's ID and a serial number. When a customer buys your software, register that person to your database.

3. Client side

Now when your application starts, send the "S/W activation request" to the server. Maybe your application shows the "Registration Form" asking for the serial number and user ID information. To make this session safe, perhaps you can use a web service with HTTPS. When you send the request, you can specify your hardware information, like CPU ID, etc. Note: For getting the CPU ID information, please refer to Get System Info using C# from Nitin Kunte. I didn't attach his code here in my document; I just added my Sign/Verify/Enc/Dec code.

4. Server side

If the serial number and user information is found on your "Registered customers" DB and the person is "Not validated yet," then make a 'Validation confirmed' message. In it, please specify the "Hardware information" from that user. ;) That's my tricky point here. Finally, encrypt that message with the user's public key and sign it with the server's private key. Send the encrypted and signed message back to the client.

5. Client side again

Now that the client has received the server's reply, verify the message with the server's public key. Then decrypt the original message from the server with the client's private key. Please see the "Points of interest" section of this article for more details.

If you decrypt the message from the server side, you will find the CPU ID that you have just sent, plus any "validation confirmed" messages (any string you decided). You should check the two pieces of information. If everything is correct, then save the message to your local folder and run the application. From now on, whenever you start the application you load that message file -- this is the license file -- and check the validity, i.e. verify, decrypt the message, check validation message and check CPU ID.

How to crack this security: Is it possible?

We can think of several ways.

1. Crack the client S/W by skipping the activation check routine?

THe client software uses Strong name. The software is signed, so if any hacker changes the code of the software, the integrity (hashed value) of the software itself changes. The loader of the client software is the .NET Framework. The .NET Framework checks the integrity of loading the software. If it is changed, the .NET Framework fails to load the software. So if the hacker wants to hack the client software, he must also crack the .NET Framework, which is tightly bound to the Operating System. This is extremely difficult.

2. Copy the license file?

The CPU ID number is written and encrypted in the license file. The client software checks the CPU ID number written in the license file. If the number written in the license file and the number that the client software found on the fly when it was executed are different, then the client software closes itself. So if user A sends his license file to user B who is using a different computer, the client software won't run because of the CPU ID difference. To skip this procedure, the hacker must crack the software and the .NET Framework, which is extremely difficult.

3. Regeneration of a fraud license file?

To make fake a license file, the hacker must have the server's private key. However, the server's private key resides only on the server. So there must be one spy in the server area to steal the server's private key. This is not a technical problem, but a so-called "Social Engineering" problem. Therefore we can neglect this method because we are talking only about the technological viewpoint here. The client software uses the server's public key inside the code. So, if the hacker uses his own private key, he also must change the client software, which is extremely difficult.

4. Disclosing the serial number and the user ID information?

If anyone reveals the serial number and user ID, then the person receiving that information can type it in when the client software asks the user for it. However, if the user ID and serial number are already "Activated," then the server denies reactivation and replies to the client that it is already activated. So, the client fails to continue. To activate it again, the user should call the vendor to enable software reactivation. User identification should be done on the phone.

Using the code

You need to refer the following namespaces:

using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Pkcs;
using System.IO;

You will use EncryptAndSign and VerifyAndDecrypt. These functions use the "AES encryption/decryption" routine, which is from the MSDN sample. Please refer to my code attachment for more details.

public string EncryptAndSign(string strOriginalMessage, 
    X509Certificate2 sender, X509Certificate2 receiver)
{
    ...
}

public string VerifyAndDecrypt(string strOriginalMessage, 
    X509Certificate2 sender, 
    X509Certificate2 receiver, ref bool Verified)
{
    ...
}

If you look at my code file, you can see the VerifyAndDecrypt() function. Currently, it shows the Certificate list dialog and lets you select one of the options. However, you can easily change the function to find a certificate without showing any dialog and return the certificate by referring the Subject Name of the Certificate. I think this is easy for you. Perhaps on your server side, you can use my code like this:

// Server's certificate

X509Certificate2 Cert_sender = SelectCertFromTheStore();
// Client's

X509Certificate2 Cert_receiver = new X509Certificate2(@"c:\receiver.cer");
string strResult = EncryptAndSign("hello world!!! 30 Days trial, " + 
    "CPU ID = asdfasdf, SerialNumber", 
    Cert_sender, Cert_receiver);

Points of interest

One thing I need to tell you is that when you use the client's private key and the server's public key in the client side, I recommend that you to use the data directly from your source code -- i.e. hard-coded -- and not from a certificate file or from certificate storage. This is because when you load them from the file, you need to be very careful about the possibility of a hacker making a different certificate and overwriting them on the client machine. With that, they can cheat your application. Even if you load them from "Certificate storage," which is very secure, my code for selecting the certificate from Certificate storage via the Subject Name of the certificate is not so safe. If you can provide safer code for selecting the certificate, I will appreciate it very much.

I and my friend faced some problems on the server side when my friend implemented the web service on a Windows 2003 server. There was no problem selecting a certificate from Certificate storage on a Windows 2000 server, but when we moved the web service to Windows 2003, it always failed to load the certificate from Certificate storage. We tried "Impersonation" and then applied some solutions for "Setting access rights to the Certificates on the machine" that we found here on CodeProject.com, but we still couldn't solve it. So, we used the FromXmlString() function of RSACryptoServiceProvider and used the private key data in XML format. (Hard-coded -o-;;;)

History

  • 18 June, 2007 -- Updated
  • 6 October, 2006 -- Original version posted

License

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

About the Author

BruceWang_korea


12 years Experienced Developer for Hire
Occupation: Software Developer (Senior)
Location: Korea, Republic Of Korea, Republic Of

Other popular Cryptography & Security articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 46 (Total in Forum: 46) (Refresh)FirstPrevNext
Subject  Author Date 
GeneralhostsmemberV. Svetoslavov3:39 9 May '08  
GeneralRe: hostsmemberBruceWang_korea19:51 9 May '08  
GeneralDistributing keysmembermjmim2:34 6 Mar '08  
AnswerRe: Distributing keysmemberBruceWang_korea18:42 6 Mar '08  
Questionusing makecertmemberjohanm_23:32 31 Jul '07  
AnswerRe: using makecertmemberBruceWang_korea20:46 31 Jul '07  
GeneralPossible Crack: remove the strong name and hack the clientmemberMartinSchmidt23:47 18 Jun '07  
GeneralRe: Possible Crack: remove the strong name and hack the clientmemberBruceWang_korea23:53 18 Jun '07  
GeneralProblem with implementing this solutionmemberGoran _5:33 13 Jun '07  
AnswerRe: Problem with implementing this solutionmemberBruceWang_korea15:21 13 Jun '07  
GeneralRe: Problem with implementing this solutionmemberGoran _0:24 14 Jun '07  
QuestionUsing just one key pair isn't good enough?memberbarbq200010:10 26 Mar '07  
AnswerRe: Using just one key pair isn't good enough?memberBruceWang_korea15:16 26 Mar '07  
GeneralExcellent Solutionmembervangarapav16:13 11 Oct '06  
General<--- This is my friend implemented the WebServicememberBruceWang_korea16:17 11 Oct '06  
GeneralGood Solutions But what to protect whole source in .Net ?memberVBNewComerVBDOTNET5:56 11 Oct '06  
GeneralRe: Good Solutions But what to protect whole source in .Net ? [modified]memberBruceWang_korea15:02 11 Oct '06  
GeneralRe: Good Solutions But what to protect whole source in .Net ?memberVBNewComerVBDOTNET17:39 11 Oct '06  
GeneralRe: Good Solutions But what to protect whole source in .Net ?memberBruceWang_korea17:56 11 Oct '06  
NewsRe: Good Solutions But what to protect whole source in .Net ?memberJeremy L-T17:27 11 Oct '06  
GeneralRe: Good Solutions But what to protect whole source in .Net ?memberBruceWang_korea17:33 11 Oct '06  
GeneralRe: Good Solutions But what to protect whole source in .Net ?memberJeremy L-T17:36 11 Oct '06  
GeneralRe: Good Solutions But what to protect whole source in .Net ?memberVBNewComerVBDOTNET17:44 11 Oct '06  
GeneralRe: Good Solutions But what to protect whole source in .Net ?memberBruceWang_korea17:48 11 Oct '06  
GeneralRe: Good Solutions But what to protect whole source in .Net ?memberJeremy L-T17:52 11 Oct '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 18 Jun 2007
Editor: Genevieve Sovereign
Copyright 2006 by BruceWang_korea
Everything else Copyright © CodeProject, 1999-2008
Web20 | Advertise on the Code Project