Shareware license key
This article will describe how I have implemented license keys in jsiPodFetch. I hope it will help someone else trying to do this. It would also be nice if someone reading this gave me feedback if this solution doesn’t work in practice since I haven’t analyzed this solution thoroughly enough to swear by it, but I think it will work.
Through out this code there are places that are open for variation. Most important if you reuse my code here is that you use your own unique strings.
Most payment processors (SWReg, Plimus, and so on) will be able to query a URL of your choice to create a license key. This solution uses a PHP-script to create a license key that can be validated by code written in any .NET-language. I will use C# for my examples.
The solution uses a multi part license key so that you can change the application code that checks the license when/if it gets cracked or keygened.
Let’s start with the PHP-code that creates the license key.
I start by creating three unique strings. Let’s use ‘AAA’, ‘BBB’, ‘CCC’. (I use more than three, but it will be enough to make my point.)
$g1 = 'AAA';
$g2 = 'BBB';
$g3 = 'CCC';
…then I create a hash from the unique string concatenated with the e-mail address used for registering the application.
By the way; I am constantly truncating the values at five characters to make the key a bit smaller. It will make the hash values weaker, but I think it will OK anyway.
$key1 = substr(md5($g1 . $_GET["email"]), 1, 5);
$key2 = substr(md5($g2 . $_GET["email"]), 1, 5);
$key3 = substr(md5($g3 . $_GET["email"]), 1, 5);
… and that’s about it. Now I can concatenate the individual hashes and the e-mail address.
$license = $_GET["email"] . "-" . $key1 . "-" . $key2 . "-" . $key3;
…then I create a hash of the license and concatenate that with the license.
$hash = substr(md5($license), 1, 5);
$license = $license . "-" . $hash;
Finally I return the license key:
echo ($license);
The result is this:
foo@foo.com-fb821-90d34-8b8c6-ca6ab
Now it’s time for some C# code. The main obstacle was getting a PHP compatible hash value out of strings in .NET. I googled a bit and found this (I’m not sure where it came from though so I can’t give proper credit.):
public static string Md5Hash (string pass)
{
MD5 md5 = MD5CryptoServiceProvider.Create ();
byte[] dataMd5 = md5.ComputeHash (Encoding.Default.GetBytes (pass));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < dataMd5.Length; i++)
sb.AppendFormat("{0:x2}", dataMd5[i]);
return sb.ToString().Substring(1, 5);
}
This method will return the same string as the PHP md5() method given the same input.
Since I hashed all concatenated sub keys I can now validate a given license key with this:
public static bool LicenseIsValid(string license)
{
int lastHyphen = license.LastIndexOf("-");
if(lastHyphen < 4 )
{
return false;
}
string l = license.Substring(0, lastHyphen);
string hash = Md5Hash(l);
string[] lines = license.Split('-');
return (hash == lines[lines.Length -1]);
}
I could include a fourth secret string when I do the hash of the full key, but at this stage I only want to validate that it is a license key for my program. I don't want to check its authenticity yet.
To authenticate a key I get one of the hashed sub keys. With this function:
public static string GetKey(int n, string license)
{
string[] lines = license.Split('-');
return lines[n];
}
I then hash the secret string I used for the n'th value together with the email and compare the result with the sub key from the license.
string email = GetKey(0);
string validHash = Md5Hash ("AAA" + email);
if(validHash == GetKey(1))
{
//Allow registered stuff
}
else
{
//Inform user that thy have to pay.
}
To make it a little bit harder to crack this, make sure to write this code in several places. If you encapsulate it in a method there is only one place to bypass.
When someone has created valid keys you can recompile the application and use your second secret key so that the key maker has to restart his work. You could also move the checking code around a bit so the cracker has to redo his work.
That's all there is to it.
One thing I miss with this solution is the ability to encode data, like a date, into the key.
Other search terms:
- crack shareware license
- For the license key use the MD5 hash of the e-mail address
- php generate md5 license key
Encourage users to pay
I will probably start differencing the functionality for registered and unregistered users of jsiPodFetch. Since it doesn’t do much there is not many functions to take out. I will start by directing unregistered users to a downloading page when there are upgrades instead of downloading the new installer automatically. Nag screens are also a viable solution, but I will give that a second thought. Nag screens has converted me from a free rider to a paying customer some times. I have on the other hand completely abandoned software that was a bit too intrusive.
jsiPodFetch is a utility for getting podcasts to your phone or ipod clone. It will create a well ordered playlist and keep track of what shows can be deleted from the media player.
jsiPodFetch 7.37
I just did a new release of jsiPodFetch.
Unless I get distracted by user reported errors the next release will include support for downloading media via BitTorrent.
CHANGE LOG
7.37
- Fixed an error because of mismatch between the meta data and the file system that could happen if a user for some reason killed the process in the wrong millisecond.
- Added call in uninstaller to remove jsiPodFetch related data
- Added -uninstall as a commandline argument to remove all jsiPodFetch related data. (To be used by the uninstaller.)
- Fixed a bug that left done files on the player.
- Now detects when a USB device is added or removed and does a refresh automatically.
New release of jsiPodFetch
I encountered a couple of severe errors in jsiPodFetch this week so there was a new release yesterday.
Changes in 7.36
- When adding new feed it didn’t show up in the list.
- Don’t download items marked as done.
- Woops; If a feed was deleted while one of its files were on the player; the app couldn’t display any items.
- Added a content menu to the tray icon.
- Added a play button when an item is selected so that one can listen to the media on the PC
- Extended tooltip on ‘blue light’ when downloading content.
Official release of jsiPodFetch
At last I have released a beta of jsiPodFetch:
Make it easier to listen to podcasts with your phone or media player.
jsiPodFetch will download the audio files from your podcast RSS feeds and create a playlist for optimal listening order.
Downloaded media is stored on your PC until you mark them as done.
jsiPodFetch is in beta and can be downloaded here.
More information and documentation will be provided shortly.
jsiPodFetch is freeware now, but please take a look at my advertisers to support the future development.
Shareware licensing
My upcoming shareware application is almost ready. There is some more testing to be done in Windows 2000 and Windows XP. I am also going to try to run it in Ubuntu using Mono, but that will come after the initial release. I’m arguing with myself about whether I should implement the GUI in WPF in a future release or if I should stay with WinForms so that I can run with Mono.
Apart from testing I still have to implement some sort of licensing system. I would prefer having the keys generated by the PayPal manager I have in PHP so that the sales process can be fully automated. It will take some extra care since an issued key has to work in the future. I can’t upgrade that part of the code without invalidating all issued keys.
My first attempt created a key based on the customers email address. The big flaw with it was that it was only possible to do one check so if someone figured out the algorithm for creating the key I would have free keys online forever. I need to create a license key that I can do several different checks on in different versions of my program.
At the moment I’m thinking of using hashes of GUID’s. That way I can incorporate different GUID’s in different compiles of the program. It will also be possible to include lists of invalid GUID’s both in the application and as part of the automatic upgrade manifest.
The next problem will be to inline the validity checks in my c# code so that the potential cracker has more than one place to shortcut. I don’t believe it will be cracker proof. It just has to be hard enough to stand the first attempt at cracking it.
Hopefully I will make the release early September.
Moving to SharpDevelop from Visual Studio Express
In light of the recent controversy of using plugins in Visual Studio Express and getting some inspiration after listening to the DotNetRocks episode with Christopher Wille on SharpDevelop I thought I should give SharpDevlop a chance again. I am working on two utilities that I plan to release as shareware and as I do not want to rely on tools supplied by my employer I have been using Visual Studio Express until now. I haven’t done any real work in #Develop yet, but I’ve got both projects up and running.
The first thing that bit me was the lack of a typed dataset designer. I was on the way to move that structure into a List<T> anyway so it doesn’t bother me that much right now. I’ll write about the progress of each project this week.
Other search terms:
- dataset designer sharpdevelop
- типизированный dataset sharpdevelop
- sharpdevelop or visual studio express
Hobby project part 3
Since I’m going to release the software as shareware I have to come up with a good incentive for the users to pay for it.
At the moment I’m trying to decide if I should start showing ads when the trial period is over or if I should just make it obvious that they are using unpaid software. Ads could create som revenue, but it might equally well make people sick of the application.
If I stop the application from working then the trial period is over it will probably be cracked in an afternoon even if the user base is small so I think I’ll let people use it even if they don’t pay. Perhaps conscience will win eventually.
Discoverability and findability
I’ve been hearing, reading and thinking a bit about discoverability lately.
This essay sums it pretty well. He goes into some discussion about limiting the choices by prioritizing different features and making basic decisions for the user. Like making the stearing wheel more discoverable than the fuse box.
I think that making these decisions are not only about usability they are really the decisions that differentiates you from your competition.
You can have one million features but in the end it is your default feature set that identifies your product. If you decide to turn all those little design decisions into options for the user your product will either be identified as the power users dream or an unfocused mess.
Since you only get one shot at the first impression it’s a tough choice for a small shop. Should you aim at the small population that likes your way of solving the specific problem or should you aim at the small population of users that will really investigate your product and tweak it to their liking?
If you’re selling to ‘ordinary’ consumers my guess is that there are more people who will like to have a guided experience than there are curious explorers. The curious explorers are probably divided in two camps; The backpackers who want lots of low cost choices, and the expeditioners who will pay whatever it costs if it gets them where they want.
Hobby project part 2
I’ve got a couple of ideas for other programs so I registered a domain
(jsisoft.com) where I can host them instead of one domain per application which probably would be better from a marketing perspective. I will prefix all the program names with ‘jsi’ to (hopefully) avoid other peoples trademarks.
It’s probably a couple of weeks of development time left before I make it public, but I have got the plumbing with paypal from jsisoft.com done and there is a forum here.
It is possible to make a donation for logview4net from the site.
I was thinking about submitting the software to as many shareware/download portals as I can find without spending any money.
