Using OpenSSL for Software License Keys, revisited

[Please note this article originally appeared on sentientfood.com 15-Jan-2005. It has been updated to make links current for the new publishing system, where necessary.]

Be sure to read the 2-Feb-2005 update to this article.

For small software developers, especially shareware developers, creating and managing software license keys can be a real hassle. Most solutions require significant investment in commercial software or in hardware dongles. The freely (or cheaply) available solutions tend to be complicated or incomplete. This article describes what will be, for many, a complete license solution. It is suitable for all types of software, and since most of the sources are included, it is open for inspection/review prior to incorporation.

This article also alludes to (in places) and directly describes (in others) a service built around the concepts presented here. This service brings license management into an affordable realm for even the smallest of development organizations. Relevant information is scattered throughout the article and more details are available at the end, or you can just go straight to the service.

What has gone before

First things first – acknowlegement of the originator of this idea (or at least the concepts this code is derived from) is in order. The article “Using OpenSSL for license keys” from the site SIGPIPE 13 was the most cogent source of information found when the author of this article was researching licensing solutions for his own use.

Without the foundation established by that article, this one (and the functionality it provides) would not exist. Please read that article for more detailed background on the reasoning behind some some of the approaches implemented here. It should be noted that there are no connections between the previous author and this one and the previous author should not be held accountable for any errors in this article.

Why use software license keys?

Any discussion of how to use/create software licenses benefits from including a companion overview of why and when to use software licenses. Not all software demands this level of protection and some that do may not warrant the time, effort, and infrastructure support required. Code development time, testing time, and purchase-completion time all factor into the puzzle. Free software should almost never include a license; there has to be a compelling reason to do so, as you will never recoup the costs involved from the software itself.

Shareware would seem an obvious target for licenses; one of the biggest factors in driving registrations (and hence, revenue) from shareware is enforcing the registration without hampering the “shareware” aspect beyond usability. It’s the case, though, that most shareware probably doesn’t need a license either when seriously considered. If you are only going to have 50 people using software that, when registered, will bring in $10/copy ($500 total), it might be reasonable to decide to leave the license out. Sometimes, though, including the license will dramatically improve registrations, so it is up to the developer to honestly assess how likely the license will positively or negatively impact the overall profitabilty of your product. This is one area where the cost of integration of a license solution is critical to the overall decision. For example, volume license management through License Services approaches fifty cents per copy of your software; generally a managable price for even inexpensive share.

Commercial software might be considered an “always” case; it certainly would be the most expected of the categories for a license. Typically, the cost of including the license will be small compared to the development costs of the overall product, so there is little fiscal argument up-front against the use of a license. A commercial application would have a much larger expected user-base, though, so the costs of incorporating the license fall mostly on the back-end, the support and retrieval side of things. Are you, as a developer or organization, prepared to handle the support issues that come with including licenses? Do you have restricted distribution or phone-home communications or account-managed access that would otherwise serve the same purpose? If so, you need to weigh any added (and possibly redundant) benefits of the license against the costs involved.

Whatever the level of your software and your desire to ensure that every copy is being used validly, it is important to give the use of software licenses an objective evaluation as a tool to achieve your goals and understand that like anything, there are benefits and drawbacks to their use.

Software license keys in applications

So,… how does all this come together? Let’s assume we will be putting a license into a desktop application. The code is easily added into other types of code should the need arise.

We will also assume that functionality in your application is easily segregated into two categories: unlicensed and licensed. (Defining what features belong in a demo version and what belong under license is beyond the scope of this article.)

Typically, your application will be set up in one of two ways; “enter license info prior to use” or “enter license info to unlock full functionality”. (In this article, we will use the term “license” as shorthand for license key, to avoid confusion with the RSA keys we will generate.) The “license document” generally consists of some plain-text information (such as name and email address) and the encoded license, a string of letters and numbers (and sometimes symbols) that will be used to verify the user has access to whatever features are protected by the license. This plain-text information (plus any additional static information you choose to include) will be used to “recreate” the value to compare to your decrypted license.

Pre-planning

It pays to plan ahead, especially when it comes to licenses. If you will be using licenses in multiple applications, or you expect to have a high-volume of registrations, you want to:

  • fully document the exact information you use to generate your license
  • fully document the process you use to generate your licenses
  • track carefully any delivered licenses
  • backup (in multiple manners) the keys used to create the licenses

Nothing will be worse once your software is released than if you are unsuccessful in assisting your customers with a lost license or are suddenly unable to generate valid licenses for an existing product. (One way to reduce the cost and effort involved with managing software licenses is to use a 3rd-party service like License Services to do most of the work.)

What goes into a license?

Of course, there are many, many different schemes to create, encode, and encrypt license information. This is just one of them, but it can be used as is or as the basis for extending it into your own scheme.

Assuming you have collected your information as mentioned in the previous section, you now have the basis for your license. Let’s assume that you’ve decided to include the user’s given name, email address, and product name into your license. (You might also include product version – or some form of it – if you want to restrict your licenses to a given major version.)

So, for our fictional product “LicenseGen”, you might have the following information:

Name: Brad Brighton

Email: bogus@sentientfood.com

Product name: LicenseGen

Let’s pack this information into one string, using a ‘*’ as a separator to give:

Brad Brighton*bogus@sentientfood.com*LicenseGen

What you use for a separator is arbitrary and not strictly required. It is handy, though, for making this information a little more human-readable (that is, readable for you, since the user will never see this full string).

Making the RSA Keys

Before we go any further, it makes sense to go ahead and get our RSA keyfile set up so that we have it ready for later use. In order to utilize the public/private key structure, we have to generate both the private key which will be used to encrypt any license information and the public key, which will be embedded in your application and used to decrypt the license.

Fortunately, it’s easy under Mac OS X to make these using the following on the command line:

% openssl genrsa -out myapp_keyfile.pem 248

where myapp_keyfile.pem is the name of the output file (it makes sense to name these in relation to the application you will be generating the license for) and 248 is the keysize (which can, and should, be replaced by a larger number – see the original author’s article for more discssion on keysize and its impact on real-world security).

Be careful, though, not to make the number too large, as this will significantly impact the length of your resulting license string. This isn’t a problem for cut-and-paste but could make the license strings unusable if you expect your users to type them. You want to strike a balance between security and usability. (License Services defaults to a keysize larger than 248 and allows keysizes up to 4096.)

Now, extract a copy of the public key:

% openssl rsa -in myapp_keyfile.pem -out myapp_public_key.pem -outform PEM -pubout

Now you have the private key (in myapp_keyfile.pem) to encrypt and the public key (in myapp_public_key.pem) to decrypt the license. cat or more the public key file to see the public key that will need to be embedded into your application later.

Make a checksum of the license information

Making a checksum of the information that you tie to your license helps ensure that users (hackers) cannot easily substitute information of their own for the license.

The checksum can be made via the OpenSSL tools, either in code or on the command line. Obviously, you will have to make it in code for full license support, but if you want to see this in action on the command line, use the following (courtesy of the original article linked above):

% echo -n "Brad Brighton*bogus@sentientfood.com*LicenseGen"
| openssl dgst -sha1

This will return the hex checksum for the string you entered. Try it with different strings (vary the email address or the name, for example, and look closely at the results). This is the value that, ultimately, the license will have to match.

In C++ code, it’s almost as simple to create the checksum (and you’ll need to do this in code at least once to verify the license later):

// this example assumes c++ types available
// unsigned char would work as well

#include 

// put your code here (assuming you have any ;-)

uint8_t md[SHA_DIGEST_LENGTH];
SHA1(buffer, buffer_size, md);

Encrypting the checksum

The checksum is only the first step. Next, we need to encrypt that checksum using the RSA private key we created earlier. From the command line:

% echo -n "Brad Brighton*bogus@sentientfood.com*LicenseGen"
 | openssl dgst -sha1 -binary
 | openssl rsautl -sign -inkey myapp_keyfile.pem

This is an important result, but not the final result. The encryption gives a binary string that is unsuitable for use as a license. For that, encoding the string into a more human-friendly version is required.

Encoding the encrypted checksum

The final step in making the license that can be distributed to the users of your application is making it human-readable. In the previous article, base-64 encoding is used. OpenSSL provides support for that directly and hence, is easy to use. That article also mentions using base-32 encoding and that is what is used here.

IMPORTANT: You are free to use any encoding scheme you like to transform the encrypted license into a human-readable form. The previous article uses base-64; this article uses base-32. Whatever you choose, remember that you MUST use the same scheme to decode your license that you used to encode it or the license check will fail. (Note that, while it might seem obvious, whatever scheme you use to encode the license string, it must be reversible.)

Once you include your encoding scheme into the process, you have something like this on the command line:

% echo -n "Brad Brighton*bogus@sentientfood.com*LicenseGen"
 | openssl dgst -sha1 -binary
 | openssl rsautl -sign -inkey myapp_keyfile.pem
 | sf_base32enc
HYEYP3JZWH552QZJM6NSAA7WVSRDQNVLSI5A2QINJUTPYTES2E======

in order to generate the basic license string that can be delivered to your end users.

In the above example, sf_base32enc is a Sentient Food-specific utility application used to generate the base32 encoding. This command takes the place of the base64 generation in the original article. (Please note that if you use the base64 encoding as described in the original article, the sample programs listed at the end of the article will require modification to decode/decrypt the license properly.) The example license string (“HYEY…”) generated will be different on your system because you will be using a different RSA key to encrypt your license information hash.

If desired, the license string can be modified to make it still more human-readable by adding dashes between chunks of characters and stripping the equals signs from the end. (Changes like these are not part of the base-32 encoding scheme, so if you decide to modify the string, make sure your base-32 decoding code can handle these changes or undo the changes before decoding the string.)

You now have data suitable for sending to the end-user in the form of a license document, including some portion of the data used to generate the license, the license string itself, and any additional information you desire.

Registering the license with your application

Logically, the next thing done with your license would be to register it with the application, to activate the product or unlock protected features. In that vein, here is a brief suggestion of how to incorporate the license into your application.

Whether you require a license to run the product or only to unlock features, typical information to gather would be the “registered name” and the “registered email address”, as is the case in this example. Present a dialog (or a preference panel) to capture the user-visible portions of the license information. Combine that information with any application-specific data to check the validity of the license when editing of the license information field has ended. (More on the validity check later.)

It is not recommended that you expose all the license information to the user. While “security by obscurity” is not a good plan to rely on solely, having non-obvious information in the license string (like what you choose for a separator character, for example) can help discourage casual hacking attacks.

Be sure to respond to the user appropriately if the license is valid (by, for example, disallowing editing of the fields once the value is correct). If the license is invalid, decide how you want to handle that too. Notify the user based on that decision. (Doing nothing is one option, simply leaving a registration status message as “unregistered” is another.)

Once you have verified license information, it needs to be stored in a proper location. When you choose where to store it, consider the benefits and drawbacks of any place you choose. Is the license meant to be system-wide or limited to a specific user? Will more than one license exist on a given system? If the application is copied to another location, user, or system, should the license go with it?

Verifying the license

Ok, at this point, we have an application, an encrypted, encoded license based on information particular to that application, and license information stored within the application in some manner. What we don’t have are details of the verification process.

To do that, we have to:

  • recreate the application information and hash it
  • decode and decrypt the license
  • compare the recreated hash to the resulting “original” hash – a match verifies the license

Recreating the hash from at least some user-provided data helps ensure that the user actually possesses a license. Some information comes from the application, some from the user. Both are used to recreate the hash which will be compared to the original hash to ensure all the information is both present and correct.

Since the license was base32-encoded (in our example) to make it more human-readable, it must be decoded prior to decrypting. Pass your stored license through that decoding (including any cleanup if you added dashes or other changes) to get the encrypted hash.

Decrypt that hash using the public key that you’ve stored in your application. The result should match your recreated hash created above.

Assuming you’ve decoded the license text into a uint8_t buffer named decodedLicense of size data_size, the code would look like this:

	// NOTE: check out the newlines in the string - these are important
    uint8_t pub_key[] =
{ "-----BEGIN PUBLIC KEY-----nYourPublicKeyHeren-----END PUBLIC KEY-----n" };

    if (BIO* bio = BIO_new_mem_buf(pub_key, sizeof(pub_key)))
    {
        RSA* rsa_key = 0;
        if(PEM_read_bio_RSA_PUBKEY(bio, &rsa_key, NULL, NULL))
        {
            int returnedRSASize = RSA_size(rsa_key);
            uint8_t* destination = new uint8_t[returnedRSASize];

			// returnedDigestSize should be the length of the returned
			// information -- look for -1 for an error. Check the man page
			// for additional details.
            int returnedDigestSize = RSA_public_decrypt(data_size,
            				decodedLicense, destination, rsa_key,
            				RSA_PKCS1_PADDING);

            //... more code here if desired

            // something to look at if things go wrong
            char *errorString = ERR_error_string(ERR_get_error(),0);

			// if you want to have your comparison of the checksum to happen
			// right away, this is a good place to put it

			// In this example, compare the contents of md[] to destination
			// If they're the same length and the bytes are the same, ...
			// the provided license information is correct.

            RSA_free(rsa_key);

        }
        BIO_free(bio);
    }

You can test in one place (or many) in your application for the match between the hashes; enable or disable functionality (or the application, based on your needs) based on the validity of the registration.

Managing the licenses

Providing details of specific mechanisms for tracking and managing delivered licenses is beyond the scope of this article. However, a general overview is in order to complete the “license for your software” discussion.

If you’re going to the trouble of protecting your software with a license, you expect your customers to actually have a need for your software (i.e. to use it). You don’t want to inconvenience your customers more than necessary when the occasion arrises that they need a copy of their license key. (Yes, there will be people who need copies of it. You need to expect to support those people.)

Whether you use an automated or manual license retreival system, you have to keep track of certain pieces of information to generate new licenses and to support older licenses:

  • the public and private keys in the keyfile
  • the information the user initially provides to generate the license
  • preferably the license information itself, as a short-cut to ensuring the user gets exactly what they received originally

Depending on what information was used to generate the license, other information may also be required in order to determine the requestor is the actual user and is entitled to a new copy of the license. As a developer, you don’t want random people claiming to have lost a license when they didn’t pay for one or someone licensed for one product requesting a “replacement” license for a different product.

Once you’re confident that you have the information to provide, you actually have to provide it. The most fundamental license support system would be the one where a user emails you (the developer) and you send a copy of the original license to the user. Simple, effective,… and seriously labor intensive if there are any number of users needing licenses.

The more data you store on your generated licences, the less labor is required to re-send (or re-create) your licenses. In the extreme case, you could provide a user-accessable interface to your license database (properly secured in some fashion) to allow for self-service license retrieval.

A wish for wings (or license management systems) that work

There can be quite a bit of work involved supporting license management and retrieval. A new service is being launched in conjunction with this article to provide these functions. Create, manage, distribute, retrieve software licenses generated using the techniques described here, for a one-time fee per product keyset and a small per-license charge. A number of user licenses are even included in the base cost!

Please see the Sentient Food License Services Home Page for full details on this exciting new service which reduces the total cost to incorporate licenses into a product to levels that make it affordable for even the most inexpensive software projects (including free software, in certain instances).

The code below is offered without obligation to use License Services. (Some of the code does not belong to this author – please see the license details below for full details.) Once you start incorporating licenses into your products, it will become clear that some management system is required and this new service is specifically designed to satisfy those needs at a reasonable price per unit.

If you find this article useful but don’t wish to use License Services, please consider donating in whatever amount you found this article and sample code useful.

Conclusion

In order to use OpenSSL and its RSA key support to create and maintain licenses for applications, you:

Do the initial setup:
  • create your application information string
  • hash, encrypt, and encode that information to generate the user-deliverable license
Make your application license aware:
  • embed certain information and your public key into the application
  • capture registration and license information from the user
  • decode and decrypt the user-provided license
  • hash the combination of user-provided and embedded application information
  • compare the resulting license and the newly hashed information to verify the license
Track and manage generated license:
  • keep secure, recoverable copies of your keyfiles
  • keep secure copies of your users’ licenses
  • provide some mechanism for your users to retrieve lost licenses from you

That’s all there is to it!

The Code

Warranty information

This code is provided as-is with no warranty or support of any sort.

It has been tested on Mac OS X 10.3.5 (Panther) and Xcode 1.2. It may (or may not) work on other versions of Mac OS X or other operating systems.

License information

The code original to the author of this article may be reused and redistributed for any purpose (including commercial), as long as the copyright notice remains intact in the code and that the copyright notice is visible in documentation/about box for your product (such as “Portions (c) Brad Brighton, software@sentientfood.com, http://www.sentientfood.com/software/”).

For example code that is not original to the author of this article, please see that code or contact the code’s author for any license restrictions. This author makes no claims with repect to that code.

Any services referenced by this article are licensed separately. Please see any accompanying license agreements for those services for full details.

Example applications: (NOW! No login required!)

These demo applications require the License Services support code linked below.

Want two free keysets (a $50 value)? Submit sample applications that mimic one of these two in other languages/environments. Java, RealBasic, COBOL, Visual Basic, whatever. The keysets go to the first person who sends in acceptable demos in each environment (the article author determines acceptability). To be eligible, any code must be redistributable under no more restictive terms than the existing examples. Questions or submissions should be sent to software at sentient food dot com.

Raw code:

License Services support code (11k, .tar.gz) – Objective-C and C++ code and the CyoTec utilities (Source: Sentient Food and CyoTec)

Even though these routines are included above, the direct link is provided as a courtesy to the third-party vendor.

CyoDecode – routines for base32 and base64 decoding (Source: CyoTec – http://www.cyotec.com)