Like a lot of modern software companies, my company uses product keys to check what contract a user has for a piece of software. When parsing the product key, I can check what type of product someone has (trial/full version, etc). We'd like users to be able to upgrade from free versions to paid versions of the code library and want trial versions that check if the product key is valid.
The trial version doesn't include all the code of the full version. The product keys are checked using an algorithm (it doesn't use web services or something like that), so that can be done very fast.
There are two sub-problems here:
- Going from a trial version to a full version. I'm thinking about solving this with MSI upgrades, but am not sure how this can be achieved. (using WIX)
- Making a trial build that includes extra code for checking if it's a trial version. I know this is possible using #if statements, but am wondering if it's also possible to change a DLL - more precisely: add static constructors for every type that check for a trial version.
My questions are: is this the right way to do this? And if so, are there standard ways (or tools) of achieving this kind of functionality? And if not, what is the best way of doing this?
update
Thanks for all the great answers so far. I think it's time to explain more of the context judging from the answers - fortunately it seems like we're more or less on the right track.
For our products it makes sense to install it on a private (non-internet connected) VLAN, so that makes product keys the way to go... and I really don't want to go to the trouble of 'phone activation' like Microsoft did :-). Therefore, as suggested, I'm currently using product keys that encrypt a bit of data, which is decrypted to see if the key is valid for the given product. Sure, I can be a victim of software piracy, but I suppose we'll consider that as a "marketing instrument" for now.
As suggested in one of the answers, I'm currently generating multiple MSI files: One for x64 and one for x86. And then one for a trial, a full version and a blueprint version. That makes a total of 6 MSI files (pfff). During the process obfuscation, strong naming and code signing takes place. The blueprint version includes the full source code.
I am rather concerned about trial builds. Sure, I can add some checks here and there, but I'd rather just put checks in every class, automatically... I've thought of copying all the CS files and adding / changing static c'tors (f.ex. using the cecil or nrefactory.. or just a couple of regex...). It just seems to me that I'm not the only guy that wants this. There has to be a better way, right?
Further, I really don't want to think about updates and upgrades, because it seems like reinventing the MSI wheel. From a trial to a full version seems to me like an MSI upgrade, just like a full version to a blueprint version feels like an MSI upgrade. However, combined with normal upgrades I'm concerned if this is possible at all?
Mixing trial and production environments can get messy. If possible make two separate installers for each.
There are some prerequisites to making your protection as strong as possible:
Scenario with Activation:
Upon installation or within some time after it you can require users to "Activate" your product. When activating you can generate a plaintext XML file with some components identifying the system - CPU ID, HDD ID, domain name, user name etc. Send said XML to your web service.
The service can then append a random tag, hash the data together and have it signed with a private key and return the signature and the random tag.
Your client software will have the matching public key built-in and will store the random tag and signature locally.
To check if the license file is valid the app will hash the plaintext data and random tag together and check if the signature matches that hash.
This gives you a very reliable way for determining if the instance your client is running is purchased and pretty much guarantees they can't just modify the XML itself.
Scenario without Activation:
Upon purchase send a file with some customer data, such as their name, email, phone etc - make it somewhat personal so the user will be reluctant to share their own license file.
Include a random tag and hash all the data together. Sign the hash and store it in the file as well.
The user will have to save the file at a predetermined location or paste it inside a textbox in your app.
Try Rhino Licensing (open source)
To solve this issue with our application we used a Guid and selected set points in the Guid to let us know what version they are using. After that we just installed the full system and used bool values when the software starts up.
You can just release the full version and disable some functionality for the trial version. When the user upgrades his license, he need not download anything. Don't worry too much about cracks and keygens. If someone makes a crack for your software, it means that you're successful, and you're already making a lot of money.