Generating License Keys in 2023
Generating and validating license keys is a common
requirement for commercial desktop applications. This
article shows a state of the art implementation in
2023. It is simple and cryptographically secure.
Mục lục bài viết
Scope
When you browse
StackOverflow
for licensing implementations, you frequently read the
following warning:
No license scheme is 100% secure.
It is true. So, given that our task is ultimately
impossible, we don’t want to think about it for too long.
At the same time, we want something that is reasonably safe.
This article is about registration codes that work
offline. No phoning home to a license server. Even
if you use a server, you likely don’t want your app to stop
working just because your user doesn’t have internet for a
brief while. To achieve this, you will need an offline way
of validating licenses.
Cracks vs. keygens
There are several ways in which people can work around the
copy protection in your software. The most common are
cracks. These usually patch your application’s
executable, to trick it into believing that there is a valid
license. Every desktop application can be fooled in this
way. Fortunately, cracks usually only work for specific
versions of an app (eg. 5.1.2 but not 5.1.3).
The worst case for software vendors are
key generators. They can be used to create
arbitrarily many valid serial numbers. If a keygen exists
for your app, then your licensing algorithm is compromised
beyond repair.
Partial key verification
To prevent keygens from working for all versions of your
software, a commonly used technique is
partial key verification. Under this scheme, you
only use some bits to check the validity of a license key.
For example, the first version of your app might only check
the first character in each group of a product key:
TEM8S2-2ET83-CGKP1-DPSI2-EPZO1
If someone publishes a keygen for your app, then you can
release a new version that checks the second character (say)
for a different requirement:
TEM8S2-2ET83-CGKP1-DPSI2-EPZO1
This limits the potential damage of a single key generator.
But it doesn’t prevent other keygens from appearing for your
new app version.
Key length
Historically, license keys had to be entered manually.
For instance, when you bought Windows XP, you received
a CD-ROM and a printed product key that you had to type in
upon installation:
Source: wikiHow – How to Clean Install Windows XP
To make this workable, license keys had to be short and
consist of simple characters such as A – Z and 0 – 9.
Nowadays, hardly anyone types in license keys by hand. When
a user purchases your software, you send them an email.
They either download the license key, or copy/paste it into
your application. Because of this, the length of license
keys has little practical relevance today.
Older articles about license verification spend a lot of
brainpower on 1) encoding information in the limited-length
license key, such as a maximum app version, and 2) on partial
key verification. If we drop the requirement that license
keys be easy to type, we can get a simpler and more
secure solution.
A modern approach
At the end of the day, a license check boils down to code
like the following:
if license_key_is_valid(): # start the application else: # alert user
Note that this even applies to more exotic solutions. For
example, say your app’s binary is encrypted and only
valid license keys can “decrypt” it somehow. Then
license_key_is_valid()
amounts to asking
“can this key be used to decrypt the binary?”.
We thus need to choose an implementation for
license_key_is_valid()
. Fortunately, modern
cryptography gives us
just the right tool
for this: We can use RSA signature verification to
sign the licensing data with a private key, then
verify the signature with an associated public key.
Below is an example in Python that uses the
rsa library.
Because RSA is so ubiquitous, you should be able to easily
port this to another language if required.
First, create an RSA key pair on your development machine.
We use 512 bits here because it leads to shorter signatures.
In practice, you probably want 2048 bits or more.
import rsa pubkey, privkey = rsa.newkeys(512)
When a user purchases, generate a license key:
data = '[email protected]' signature = rsa.sign(data.encode('utf-8'), privkey, 'SHA-1') from base64 import b64encode print(data + '\n' + b64encode(signature).decode('ascii'))
This prints the following:
[email protected] ejp2RYhgI5p43n80BB311Ck32umDmqoezLkfOJmqIgNvHfux9Wm8bYtZJIAciet/Ef0ORo49JHr6zYwnTq6g7w==
Send this to your user. Then, in your application, check the
validity of the license key as follows:
try: rsa.verify(data.encode('utf-8'), signature, pubkey) except rsa.VerificationError: # invalid license key - refuse to start else: # start application
Once execution reaches the last line, you can trust that
data
was not tampered with. This lets you
include information relevant to licensing in the data, such
as a maximum app version to which your user is entitled.
The above code works as-is when you type it into one
interactive Python interpreter session. In practice, you
will have to ship the public key with your app and decide
where the user will put the license key. These are just
details however. The important parts of the implementation
are all here.
Caveats & Summary
Assuming you use a large enough bit size, the above
implementation should be safe from key generators. It is not
immune to cracking however – as mentioned above, no desktop
app is. If you want to make your app even more secure, you
could look at
obfuscation.
This makes reverse-engineering and thus circumventing your
copy protection more difficult.
Michael is the creator of
fman, a cross-platform
file manager. Frustrated with how difficult it was
to create this desktop application, Michael open
sourced
fman’s build system (fbs). It saves you
months when creating desktop apps with Python and
Qt. A few days of these
months come from using fbs’s well-integrated
licensing implementation.