SIGPIPE 13

OpenSSL for License Keys

September 5th, 2004

In this article I will give an example of how one can generate and verify license keys (also known as serial numbers) using the tools included with Mac OS X, and in a way which should make it difficult for the cracker to generate his own fake license key(s).

Let us first consider what the license key actually is. Since it will be used to unlock an application, it needs to contain an identifier which the application can recognize. But giving all users the same license key (e.g. "42") is not a good idea, since if one user leaks his license key, everybody will be able to use the program, and we won't be able to tell which user actually leaked the license key.

To remedy this problem we can store a checksum of the users name in the license key, and let our application verify this checksum. So if a user wants to leak his license key, he also needs to include his name, which would probably discourage most.

To ensure that he cannot easily construct another name with the same checksum, we should use a cryptographic hash function to generate the checksum, and to ensure that he does not simply overwrite the checksum in his license key (with a checksum for a name he made up himself), we should give him the license key in an encrypted form, so that he would need to decrypt the license key, make the change, and then encrypt it, in order for him to spread a fake license key (i.e. with a modified user name checksum.)

Using symmetric encryption (like XOR, ROT13, or even DES/AES) the above won't help much, since the user will only need to run our program through the debugger to see how it decrypts the license key, and from this, he can probably figure out how he should encrypt it (after making his changes to the checksum.)

But with asymmetric encryption this becomes much more difficult, because one cryptographic key is used for encryption, and another is used for decryption, and given one of them, you cannot easily find the other. You probably know this as public/private key encryption, which is currently supported by Mail.app in the form of S/MIME, where you can send a letter to your friend using his public key, and only he will be able to read it, using his private key to decrypt it.

So with these things in place, let's try it out. We are using the openssl command which comes with OS X and supports a great number of functions related to cryptography, from their website:

The OpenSSL Project is a collaborative effort to develop a robust, commercial-grade, full-featured, and Open Source toolkit implementing the Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) protocols as well as a full-strength general purpose cryptography library.

To get an idea of the functionality supported you can run man openssl from the command line.

The first thing we need is a checksum on the users name, we'll choose SHA-1 as our cryptographic hash function, and since this is implemented by openssl, we can write the following in our shell:

% echo -n "Allan Odgaard" | openssl dgst -sha1
e9b6b54ba43bfd664cfbd2974272c0f98a3c2463

By default openssl outputs the checksum in hexadecimal notation, but you can add -binary to change that (but then you should send the output to a file instead of using the terminals standard output.)

The next step is the public/private key encryption. We will use RSA as our cryptographic algorithm. Again openssl lets us perform this, but first we need to decide the key size (in bits). The higher key size we use, the harder it is to attack the system (see notes at the end of this article for more on this). The key size dictates the minimum size of the encrypted data (i.e. our license key), so in this example we will use a key size of 248 bits (but for real world security this is not adequate, more on this later), because the checksum is 160 bits, and the default padding added in front of our data is 11 bytes (padding can be disabled using the -raw switch (when encrypting/decrypting), but the data size still needs to be a few bits less than the actual key size due to how RSA works.)

To generate a key we run the following command:

% openssl genrsa -out private.pem 248
Generating RSA private key, 248 bit long modulus
.....+++++++++++++++++++++++++++
.+++++++++++++++++++++++++++
e is 65537 (0x10001)

It generates the file private.pem which contains both the public and the private key. To encrypt something with this key, we run the following command:

% echo -n "Allan Odgaard" \
 | openssl dgst -sha1 -binary \
 | openssl rsautl -sign -inkey private.pem -hexdump
0000 - 2b 30 7e 47 c3 48 61 a2   +0~G.Ha.
0008 - 4a d5 27 9a f0 fa 2a f0   J.'...*.
0010 - c9 03 83 6e c8 f8 97 d4   ...n....
0018 - 92 7b 59 e9 04 00 4e      .{Y...N

This is a hex dump of an RSA encrypted SHA-1 message digest (checksum) of my name, using a randomly generated private key. In order to send this as a license key to the user, we could base64 encode it, which is also something openssl can help us with:

% echo -n "Allan Odgaard" \
 | openssl dgst -sha1 -binary \
 | openssl rsautl -sign -inkey private.pem \
 | openssl enc -base64
KzB+R8NIYaJK1Sea8Poq8MkDg27I+JfUkntZ6QQATg==

And now we have our license key, which can easily be transmitted using E-mail and entered (pasted) into a text field, though it doesn't really look like a standard license key, to achieve that we could instead use base32, which consists only of A-Z and 2-7, and perhaps even insert some dashes in the string.

So now to verify this license key. As mentioned earlier, private.pem also contains the public key, so we need to extract this first:

% openssl rsa -in private.pem \
 -out public.pem -outform PEM -pubout
writing RSA key

This gives us a public key which we can embed in our program w/o the fear of anyone being able to calculate the private key from it (at least not w/o spending a lot of computer cycles doing so.)

So our application needs to base64 decode the license key, decrypt the result using our public key and then run SHA-1 on the users name and compare it with what we have decrypted.

From the shell we can base64 decode and decrypt it like this:

% echo KzB+R8NIYaJK1Sea8Poq8MkDg27I+JfUkntZ6QQATg== \
 | openssl enc -base64 -d \
 | openssl rsautl -verify -inkey public.pem -pubin \
 | xxd
0000000: e9b6 b54b a43b fd66  ...K.;.f
0000008: 4cfb d297 4272 c0f9  L...Br..
0000010: 8a3c 2463            .<$c

This is a hex dump of the decrypted license key (courtesy of xxd), and if you scroll back, you'll see that it does in fact match the SHA-1 checksum for my name given above.

So the only thing missing is doing the above in code, since we do not want to call an external shell script to do our license key validation.

Luckily all the functionality of openssl is also available in C using libcrypto, which needs to be added to your Xcode project, or you can add -lcrypto to the linker options. Then to calculate a SHA-1 message digest on buffer with length buffer_size we do:

#include <openssl/sha.h>
⋮
uint8_t md[SHA_DIGEST_LENGTH];
SHA1(buffer, buffer_size, md);

And to "load" a public key (from memory) and decrypt a message with it (given as data with length data_size), we use the following:

#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/bio.h>

uint8_t pub_key[] = { ... };
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))
   {
      assert(data_size == RSA_size(rsa_key));
      uint8_t* dst = new uint8_t[data_size];
      RSA_public_decrypt(data_size, data,
               dst, rsa_key, RSA_PKCS1_PADDING);
      ⋮
      RSA_free(rsa_key);
   }
   BIO_free(bio);
}

I have left out the part about base64 decoding in code, but apart from that, you should be set to experiment with this on your own!

Some final random notes:

On signing being the same as encrypting with a private key Carey Underwood makes the following point (May, 2009):

Because the public key is intended to be public, its creation is optimized for performance, not security. This makes it important to remember that the public key isn’t just called public, it is intrinsically and unavoidably public. Make sure you understand the implications of that before applying your understanding of RSA to other tasks.

When it comes to the choice of key size, Nicko van Someren writes:

I can factor 512-bit keys in about four weeks using a rack full of G5 X-servers, which is less resource than many university computer labs have on tap. At this time 576-bit keys have been factored and 768-bit is considered suspect for any long term security. Ultimately it boils down to how much effort you think your attacker will put in and for how long you want your software to be secure. At the moment we are still some way from anyone getting close to factoring 1024 bit RSA moduli or breaking 1024 bit discrete logs (used in DSA) so if you are willing to risk fake license keys turning up in a decade or so I'd go with 1024 bit keys.

[by Allan Odgaard]


83 Responses to “OpenSSL for License Keys”

  1. Ed Silva Says:
    October 3rd, 2004 at 23:28

    I have been trying to get what you describe working as a part of my SSCrypto class with no luck.

    The main problem seems to be in this line:

    int len = RSA_public_decrypt([decoded length], [decoded bytes], dst, rsa_key, RSA_PKCS1_PADDING);
    

    I am pretty sure I have everything else set up correctly. I don't suppose you'd care to have a look at the code?

    SSCrypto is a Cocoa wrapper around OpenSSL symetric ciphers and digests. I'd like to be able to add basic RSA functionality as well. You can find it here: http://septicus.com/products/opensource/, minus the RSA methods. Please let me know if you are interested in looking at what I have got so far.

  2. Jax Says:
    July 30th, 2005 at 06:41

    I'm interested in learning how to use this Open SSL library funcitons.Plz suggest me how to get the functions that can be used for the encryption and decryption purposes.

  3. Allan Odgaard Says:
    July 30th, 2005 at 10:14

    Jax: not really sure what you're asking.

    If you add #include <openssl/rsa.h> to your source, you have the functions.

    Add -lcrypto to the gcc options to actually link with the library.

  4. Steve Checkoway Says:
    August 16th, 2005 at 13:29

    While this is a very clever scheme for protection, it has one fatal flaw. The purpose of signing and verifying with public key cryptography is to allow one person to verify that a message was actually written by the person who sent it. It does not prevent one person from lying to herself that a fake message is real.

    More concretely, all an attacker has to do to defeat this is to generate a private/public key pair exactly as you have demonstrated, sign her name (or the hash of her name) using the generated private key, and replace the public key in the program with the one she just generated.

    Unfortunately, I have no solution.

  5. Allan Odgaard Says:
    August 20th, 2005 at 09:29

    Steve: In theory you'll always be able to modify the binary to disable the protection scheme.

    However, you'll have to do that for each new release, and that's probably why binary cracks are close to non-existing among typical Mac users, where few doesn't know how to search one of the many fake serial number collections for a serial number.

    So I don't consider this a fatal flaw.

  6. Steve Checkoway Says:
    August 25th, 2005 at 05:44

    In theory, one can always rewrite the software without the protection.

    In this case, it would take a little been of snooping with gdb to figure out which bit of memory it was passing to openssl for the public key, write a small bit of code to find and replace that (assuming that sed cannot already do that with binary data). In future versions, if the public key has been maintained, it's a simple matter of finding/replacing again. If the public key changed, it's back to gdb for a few minutes.

    This could be made more difficult by doing some reversible mathematical operations before embedding the public key and then the reverse before handing it off to openssl. This would be far more time consuming to crack–at least time consuming enough that I wouldn't bother attempting, I suppose I cannot speak for other people.

  7. aa Says:
    September 28th, 2005 at 13:21

    how to validate the keys through program.

  8. renju Says:
    September 28th, 2005 at 13:23

    I want a Licence key for my product which can be used to on/off certain functionalities. How can wevalidate the key for eacxh user.

  9. Madmax Says:
    March 31st, 2006 at 18:31

    Is there no simpler way for decrypting a crypted message than to write a C program like above ? e.g. a shell command like "openssl [somecommand] -inkey private.pem -in crypted_message.bin" ?

  10. Allan Odgaard Says:
    April 20th, 2006 at 04:28

    Madmax: You can use openssl. See man enc.

    Here’s a short example:

    echo "secret" \
     |openssl des3 -k bla \
     |openssl des3 -k bla -d
    

    First we write out secret, then we encrypt it with des3 (with bla as password) and then decrypt it again.

  11. Pablo Says:
    May 29th, 2006 at 16:58

    Hi, great work.

    I've a little doubt about the public key in memory:

    uint8_t pub_key[] = { ... };
    

    What format is the key defined in? Base64? Hex? The same as the the file .pem one?

    Thanx a lot !!

  12. Allan Odgaard Says:
    May 30th, 2006 at 08:47

    Pablo: That would just be the contents of the public.pem file.

  13. Pablo Says:
    May 30th, 2006 at 11:24

    I see. You mean a simple fread from the whole pem file would get the good and real public key, or should I avoid the /r and /n characters in the file?

  14. Allan Odgaard Says:
    May 30th, 2006 at 12:42

    PEM_read_bio_RSA_PUBKEY reads the pubkey from a “bio” and expects it exactly as it exists in public.pem.

    Bio’s are I/O abstractions and can map to a file, memory buffer, or similar.

    In the example above, they map for a memory buffer which must contain the public.pem exactly as it exists on disk.

    See “man bio” for more information.

  15. Pablo Says:
    May 30th, 2006 at 13:54

    Thanks a lot, Allan.

    I've just got to make the full example run, with BIOs an so that with memory-based keys.

    I've got even have the key in binary format in the file, creating the real key with base64 encoding functions.

    Thanx again Pablo.

  16. ron Says:
    June 7th, 2006 at 01:21

    hi

  17. toxicsoftware.com » AquaticPrime Warning Says:
    June 8th, 2006 at 03:41

    [...] Aquatic Prime uses a technique similar to one discussed by Allan Odgaard on his blog. Public Key cryptography techniques are used to generate linked public and a private keys. The private key is kept by the software developer and the public key is shipped inside the application's binary. When a user buys a copy of the software, a license file is signed using the private key. The software can then use its public key to verify that the license key was signed by the public key. Someone trying to steal a copy of the software would be unable to forge their own license files because the public key works with one and only one private key. [...]

  18. Mate Master: Allan Odgaard Says:
    June 13th, 2006 at 03:24

    [...] In a word, no. ‘My only concern is fake serials,’ he explains, ‘since if someone can generate a fake serial, black-listing would only be temporary as a new fake serial would just be generated. For this reason I went with a public/private key based system described here.’ [...]

  19. Edouard Fischer Says:
    July 5th, 2006 at 22:50

    Hi,

    Here is a sample xCodeProject that demonstrate this method. Comments would be apreciated.

    I obfuscated the public key in order to avoid the attack Steve Checkoway pointed out (but i don't give the source code of the obfuscation technique : it is hidden in a static library ckeck.a)

  20. Edouard Fischer Says:
    July 5th, 2006 at 22:52

    Oops : I forgot the link. http://homepage.mac.com/edouard.fischer/

  21. Claudio Says:
    October 2nd, 2006 at 01:25

    Thanks for this precious tutorial, Allan. I've recently written my first shareware app and I found that my registration scheme has been hacked, so I decided to give RSA encryption a try. I'll treasure your guide!

  22. Adam Says:
    October 12th, 2006 at 01:07

    Steve Checkoway was right on his post on August 16, 2005. Digital signatures are only effective when transferring data over non-secured connections and we need to verify if the data have not been tampered with. Unless the public key is stored in a safe place, this kind of protection scheme can be breached when attack locally. The public key must be off limits when using this type of protection scheme in your application.

  23. Dennis Says:
    November 6th, 2006 at 01:27

    Adam says: "Steve Checkoway was right on his post on August 16, 2005." [etc.]

    I think that you missed the point of the responses to Steve Checkoway. He is right that someone can go in with gdb, figure out where the signature check is, and modify the binary to circumvent it. He suggests substituting a known key for the public key, but why even go to that trouble, just make the validation function always return true!

    The point of using the digital signature is not that it makes the program uncrackable. It clearly doesn't and in fact I don't know of any scheme that is guaranteed to make an application uncrackable as long as the cracker can observe it under a debugger.

    What a digital signature scheme does for you is:

    1) Gives you a fairly rock solid way of generating valid keys that can't be duplicated by crackers; that is, they can modify your program to crack it, but they can't generate valid keys to distribute. Any crack has to be duplicated for every version update of the software, and the entire cracked binary has to be distributed.

    For many inexpensive shareware programs, this might be considered enough protection. You know it may be cracked but at least you can be sure that no one will be able to generate an infiinite number of valid keys that can't be distinguished from genuine ones.

    2) Even if you go further than this to try to make it more difficult for your software to be cracked (as I said, there is no guaranteed foolproof method but there are various ways to make it harder), you will have to start with a solid way of generating keys that can't be reproduced as a first step. In other words, even if your needs for protecting your software are such that the digital signature scheme is not sufficient, it is at least necessary. If you have a key generation method which can be cracked to allow the crackers to generate keys indistiguishable from your valid keys, then it is game over: any attempts to make your binary harder to crack/modify are moot at that point.

  24. Marc Charbonneau Says:
    February 25th, 2007 at 18:09

    Thanks for posting this!

  25. Adolfo Says:
    April 22nd, 2007 at 18:12

    Edouard Fischer entered the following comment:

    "Here is a sample xCodeProject that demonstrate this method. Comments would be apreciated.

    I obfuscated the public key in order to avoid the attack Steve Checkoway pointed out (but i don’t give the source code of the obfuscation technique : it is hidden in a static library ckeck.a)"

    He pointed to a link (http://homepage.mac.com/edouard.fischer/) but it is no longer active. Does anyone have a copy of the XCodeProject he references or have the contact details for Edouard?

    Thanks,

    Adolfo

  26. Aldo Says:
    May 1st, 2007 at 00:49

    Dennis says: "He suggests substituting a known key for the public key, but why even go to that trouble, just make the validation function always return true!"

    Ideally, a digital signature for the application could help to prevent application tampering. A developer could acquire a private key from an online authority, then digitally sign the application with it and dsitribute it. Then, before allowing the app to run, the local O/S would be responsible for retrieving the corresponding public key (from the online authority) and validating that the app has not been tampered with.

    I believe cell phone operators use something similar to prevent ensure only legit 3rd party applications run in their devices.

  27. Mike Says:
    May 3rd, 2007 at 19:47

    Two questions really.

    1) If we are going to end up signing the license key, what is the significance of the hash? Above it explains that we don't want the user to easily generate a new name/hash and just overwrite it in the license key. But if we are signing it with the private key, the user will never see his/her name, so why hash it. In other words, how less secure would it be to simply use RSA to "sign" the raw name without hashing it first.

    2) If I'm using DSA with openssl, there is no DSA_decrypt function from what I can tell. While the verify function does most of what I need, if there no way to gain access to the embedded hash during the verification step with openssl? On the command line, openssl has a -verify option in rsautl which will output the embedded hash. There doesn't seem to be equivalent functionality for DSA in the command line or in the C APIs. Any ideas?

    Thanks! Mike

  28. Allan Odgaard Says:
    May 3rd, 2007 at 23:15

    Mike: The reason for the hash is only to get a fixed length version of the users name. In most practical scenarios, the user name would actually be shorter than the hash, but I like to play it safe, i.e. with the hash I have a known upper limit on the length of the users name (without using truncation).

    As for DSA: DSA is the Digital Signature Standard, so the purpose here is only to create a signature. This is done by hashing the full data and then asymmetrically encrypt that hash. This is then the signature. So the signature itself only holds an (encrypted) hash of the original data, not the actual data, thus DSA signatures alone are not really useful as license keys.

  29. Kevin Ballard Says:
    June 17th, 2007 at 05:38

    Given this information, if I were to attempt to break your app the first thing I'd try is simply injecting a custom library which overrides the used openssl functions to return canned responses. This technique would work across version upgrades as long as you use the same algorithm. Sure, it's a bit more work to set up, but it only has to be done once.

    Do you have any way of protecting against that?

  30. Allan Odgaard Says:
    June 17th, 2007 at 16:24

    Kevin: The canned response should include filling in a decoded license key in the buffer handed to RSA_public_decrypt — if you don’t already have a license key for the program then this will require some tedious debugging (depending on how convoluted the integrity checks are) so I wouldn’t classify it as an easy attack vector.

    But definitely it can be done, and from a purely theoretical point of view the only way to guard against this is code signing.

    One thing to keep in mind though; the program may use libcrypto for more than just license key management. For example I sign my updates and use libcrypto to verify them, and something like WebKit could also use it (but seems to link with Security.framework).

  31. diciu Says:
    July 16th, 2007 at 10:39

    Thanks for sharing – I wonder if 10.5 does code signing based on this very concept.

  32. selling waves » Blog Archive » links for 2007-08-01 Says:
    August 1st, 2007 at 04:31

    [...] SIGPIPE 13 » Using OpenSSL for license keys Interesting discussion of how to use public-key encryption tools to create software serial numbers (and, incidentally, another object lesson in why SHA-1 being broken is important). (tags: encryption security osx mac textmate ssl) [...]

  33. Daniel Says:
    January 15th, 2008 at 09:34

    "it doesn’t really look like a standard license key, to achive that we could instead use base32." How do you do that (I am very new to this)? It does not seem that openssl enc -base32 works.

  34. Allan Odgaard Says:
    January 19th, 2008 at 07:38

    Daniel: You’ll have to write your own base-32 encoding/decoding functions (or search Google Code or similar).

  35. Brad Brighton Says:
    March 25th, 2008 at 03:08

    Daniel,

    I have some code on my site (check out the article: http://www.sentientfood.com/display_story.php?articleid=3 ) which I wrote back in January of '05, based on this very article. The sample code links are at the bottom.

    I hope you find it useful.

    -brad

  36. John Bridges Says:
    June 14th, 2008 at 18:43

    Well in response to Kevin Ballard's custom lib approach it seems that as Allan says using libcrypto elsewhere in your program would be an important way to perform an integrity check against those decoding functions.

    Please correct me if i am wrong but according to this method, once a liscence key has been sent out, it will remain useable forever (for that version of the /sw). And if i did need to change the application's public key (in a future version) to invalidate that user's key, wouldnt it also invalidate the liscence keys of all the other users aswell ?

    So the application's public key can be moved / split and obsfrucated in the application binary. But if someone hid their true identity from you when they purchased your product e.g. by using a stolen credit card and someone elses' real address? They would be free to distribute that authentic lisence key to anybody, whilst also maintaining their anonymity. So what if you wanted the ability to revoke / disable further uses of a compromised lisence key ?

    Wouldnt I want a 2nd layer of authentication for each lisence key? I suggest that the user could still activate their software by your method. Exept that when they type their lisence key it does not activate the app. Instead it is sent straight back to the webserver and a second liscence key provided quietly (and without user interaction). To be any better it must remain always hidden to the user because it cannot be revoked. Then revocation would occur by the webserver denying the real key if the user-provided key were compromised. But then this transmitted key would have to be obsfrucated somehow also. Which is difficult if it can be peeked in the http request, or debug in the app, or read on the disk : (

  37. Allan Odgaard Says:
    June 14th, 2008 at 23:32

    John Bridges: Effectively what you describe is product activation.

    Personally I discourage people from using such systems because there is a very good chance it will badly affect honest users.

    You can always do product de-activation based on the serial number embedded in the key, the key’s finger print, or similar. This can be done by call-home or have a list of disabled serial numbers in the application (though older versions would still work with the disabled serial).

    In my experience the number of serials that needs to be recalled are in the order of 1:10,000 — so don’t waste too much time worrying over this :)

  38. John Bridges Says:
    June 15th, 2008 at 19:13

    Thank you Alan, that is very helpful to know.

  39. Uli Kusterer Says:
    August 15th, 2008 at 12:42

    Alan, sorry to do this here, couldn't find contact info here. Great article, thanks for sharing this! But there seems to be a formatting issue: The includes for openssl/rsa.h and openssl/bio.h are missing their # and are HUGE. Also, an include for openssl/pem.h seems to have gone missing.

    Still, great docs, and a useful outline for implementing one's own scheme. Thanks!

  40. Allan Odgaard Says:
    August 25th, 2008 at 08:15

    Thanks Uli, I updated the post.

    The problem is that I have been updating WP since I wrote the post, and the rendering pipeline in WordPress has changed a few times…

  41. Matt Says:
    August 31st, 2008 at 23:27

    This was great, and very clever. Thanks!

  42. Dragan Says:
    September 2nd, 2008 at 23:45

    Hi, I recently also decided to go RSA route to generate license keys, I even wrote my own code to do Base32 encoding and decoding. I've got one problem though… Using 1024 bits long key on hashed user info and then encoding it using Base32 produces license codes that are really LONG! I know it's not caused by my Base32 code, as I've tested it against some already existing solutions doing the same task. Of course, going with shorter keys produces license codes less long (but still too long), but that compromises security.

    Is there any known technique to shorten license codes generated the way explained above that you can recommend? Or am I perhaps doing something wrong and get this long codes as result?…

  43. Jerry Krinock Says:
    September 4th, 2008 at 22:57

    Dragan, I have not run through all the theory, but when I sign a message with a 1024-bit RSA key I get a signature (which is what you'd use as the license key ) that is 1024 bits long. Since Base32 encodes log2(32) = 5 bits per character, the license key length is 1024/5 = 205 characters, plus maybe a few more for padding. If you used Base64 instead of Base32, you'd encode 6 bits per character so the license key length would be a little shorter, 172 or so characters. Using a 2048-bit RSA key with Base64, I get a key length of 345 characters.

  44. Allan Odgaard Says:
    September 5th, 2008 at 07:13

    Dragan: You say “hashed info”, so I assume you are interested in a real signature, as opposed to encrypting the user info (such as a serial number).

    In that case, you can use the Digital Signature Algorithm. It generates a 368 bit signature from a message and a 1024 bit key. A 368 bit signature will encode as 74 bytes using base-32 (62 bytes using base-64).

  45. Joe Discenza Says:
    October 13th, 2008 at 16:11

    I also had a problem with

    unsigned char licenseKey[500]; //which I read from file int len, length;

    . .

    length = RSA_public_decrypt(len,licenseKey,dst,rsa_key,RSA_PKCS1_PADDING);

    The compiler says

    error: expected primary-expression before 'OTHER' token error: expected ';' before 'OTHER' token.

    Any ideas?

  46. jacopo Says:
    November 5th, 2008 at 16:40

    I'm integrating the OpenSSL api with the apple native SecKey* API and I'm having some little problem.

    I generate a keypair using SecKeyGeneratePair and I obtain a persistence reference of the self generated Public key calling the SecItemCopyMatching.

    (sample code using the SecKeyWrapper provided by Apple in a sample iphone application) [[SecKeyWrapper sharedWrapper] generateKeyPair:kAsymmetricSecKeyPairModulusSize]; NSData *publicKey = [[SecKeyWrapper sharedWrapper] getPublicKeyBits];

    The keys are generated using RSA with 1024 keylen and this is a dump of the obtained public key in PEM format

    —–BEGIN PUBLIC KEY—– MIGIAoGAUHmlTMGzxJ8Q+M3hlqSiZmn0wKKYqaih9gGfMkRPXBT4jpOiE6VOVuWN jedIs97H4GRe4ZlmGAqMD5BK9NztHVOGPPYYjXT7u02kppkgYDoOhI7iYFJ/iHGi eDwzUzCo5QEjeateX1fNVNhXzLs3T45/YVN3ezRqOmjJqs31cvUCAwEAAQ== —–END PUBLIC KEY—–

    Then I pass the public key to the OpenSSL api but when I try to use the public key, for example encrypting something with that, I obtain an error

    BIO publicBIO = BIO_new_mem_buf((unsigned char)[[self publicKey] bytes], [[self publicKey] length]); RSA *publicRSA = NULL; PEM_read_bio_RSA_PUBKEY(publicBIO, &publicRSA, NULL, NULL) <==== ERROR

    If save the PEM to a file a gave it as input to the following OpenSSL command: openssl rsa -pubin -in pubkey.pem -text -inform PEM I obtain the following error:

    unable to load Public Key 49893:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:tasn_dec.c:1007: 49893:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:tasn_dec.c:305:Type=X509_ALGOR 49893:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_D2I:nested asn1 error:tasn_dec.c:567:Field=algor, Type=X509_PUBKEY 49893:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:pem_oth.c:82:

    Can anybody please give me any help ?

    Thanks, jacopo

  47. jacopo Says:
    November 5th, 2008 at 16:42

    I'm integrating the OpenSSL api with the apple native SecKey* API and I'm having some little problem.

    I generate a keypair using SecKeyGeneratePair and I obtain a persistence reference of the self generated Public key calling the SecItemCopyMatching.

    (sample code using the SecKeyWrapper provided by Apple in a sample iphone application) [[SecKeyWrapper sharedWrapper] generateKeyPair:kAsymmetricSecKeyPairModulusSize]; NSData *publicKey = [[SecKeyWrapper sharedWrapper] getPublicKeyBits];

    The keys are generated using RSA with 1024 keylen and this is a dump of the obtained public key in PEM format

    —–BEGIN PUBLIC KEY—– MIGIAoGAUHmlTMGzxJ8Q+M3hlqSiZmn0wKKYqaih9gGfMkRPXBT4jpOiE6VOVuWN jedIs97H4GRe4ZlmGAqMD5BK9NztHVOGPPYYjXT7u02kppkgYDoOhI7iYFJ/iHGi eDwzUzCo5QEjeateX1fNVNhXzLs3T45/YVN3ezRqOmjJqs31cvUCAwEAAQ== —–END PUBLIC KEY—–

    Then I pass this public key to the OpenSSL api but when I try to use the public key, for example encrypting something with that, I obtain an error

    BIO publicBIO = BIO_new_mem_buf((unsigned char)[[self publicKey] bytes], [[self publicKey] length]); RSA *publicRSA = NULL; PEM_read_bio_RSA_PUBKEY(publicBIO, &publicRSA, NULL, NULL) <==== ERROR

    If save the PEM to a file a gave it as input to the following OpenSSL command: openssl rsa -pubin -in pubkey.pem -text -inform PEM I obtain the following error:

    unable to load Public Key 49893:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:tasn_dec.c:1007: 49893:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:tasn_dec.c:305:Type=X509_ALGOR 49893:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_D2I:nested asn1 error:tasn_dec.c:567:Field=algor, Type=X509_PUBKEY 49893:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:pem_oth.c:82:

    Can anybody please give me any help ?

    Thanks, jacopo

  48. Shaun Says:
    November 13th, 2008 at 18:04

    Steve Checkoway talks about using gdb to find the area of memory that the public key is stored in, even if obfuscated it has to be de-obfuscated before sending it off to openssl, would you still be able to find the de-obfuscated public key in memory?

  49. David Schwartz Says:
    November 18th, 2008 at 04:11

    This method is useless for its intended purpose because it solves the wrong problem. The problem is not "how can someone who genuinely wants to know if a license is in fact valid tell if a license is valid or not, such that he cannot be fooled into accepting an invalid license". The problem is how you can prevent someone without a valid license from accessing software functionality.

  50. Allan Odgaard Says:
    November 18th, 2008 at 08:56

    David Schwartz: The intended purpose is to make it practically impossible to generate fake serials, since obtaining a fake serial is the popular way to avoid having to pay for software.

    It sounds like you think this post is about something completely different and is commenting on that.

  51. David Schwartz Says:
    November 18th, 2008 at 17:54

    Allan Odgaard: Obtaining a fake serial is one way to avoid having to pay for software. Just as popular is modifying the program to not require a license or to accept an invalid license. People who wish to avoid paying for software will use whatever technique works best against a particular program. Patches are as popular as serials.

  52. Allan Odgaard Says:
    November 18th, 2008 at 18:22

    David: I disagree with you, and I have my reasons for that. But I don’t want to get into that old debate unless you actually have some hard proof to backup your claims.

  53. David Schwartz Says:
    November 18th, 2008 at 18:36

    Allan Odgaard: Huh? What old debate? What do you want proof of exactly? That cracks are as popular as serial numbers? Google for "crackz", you get 3.5 million hits. Google for "serialz", you get 4 million hits. That's not exactly scientific proof, but I'm arguing for a null hypothesis, so I don't have the burden of proof.

    This article solves the following problem: "How can I create a license that is unforgeable. That is, an honestly interested individual cannot be fooled into accepting an invalid license."

    This articles does not solve the following problem: "How can I create a licensing scheme such that my software will not work without a valid license". It doesn't even attempt to.

    If you read the article carefully, it is quite clear that this is what it's doing, and nowhere does it claim that it provides any resistance to the software accepting an invalid license.

    Then, for some reason, people tried to graft this capability onto a scheme that was, fundamentally, not designed to provide it. They talked about obfuscating the public key and all kinds of other things. If they wanted this capability, why pick a scheme that is fundamentally not designed to provide it?

  54. Allan Odgaard Says:
    November 18th, 2008 at 18:55

    Whether or not casual users will use fake serials versus cracks has been argued to death. All my anecdotal evidence (and statistics collected by having software for sale) points to most users at one time having used fake serials and on Mac there are half a dozen fake serial database distributions.

    As for your crackz, if you google for textmate crackz you find Windows .exe files claiming to be crackz for various versions of TextMate. TextMate is a Mac program, most likely the .exe files are trojans/spyware or worse, and that is why most casual users stay the hell away from binary cracks obtained from shady sites, despite the internet being full of them.

    Entering a license code though is unlikely going to install spyware on the users system (even if that license code is fake — yes, I know there have been one or two exceptions).

    But given your last paragraph, maybe I misread your first comment, I thought it was directed at the article, but it seems that it was directed at some of the comments that seem to have missed the difference between making it impossible to fake a serial number versus making a binary crack impossible.

  55. David Schwartz Says:
    November 18th, 2008 at 19:14

    Allan: Maybe we agree more than we disagree. However, your anecdotal evidence is answering the wrong question. How many of those "fake serials" are real serials? I have seen quite a few "fake serials" that were clearly real serials, some of them even included the name of the poor schmuck they were stolen from.

    You have a good point though that the Windows world and the Mac world see a very different mix of pirating techniques and there is inherent risk in using a crack that doesn't exist (at least, is not perceived to exist which is what matters here) with a serial.

  56. Allan Odgaard Says:
    November 19th, 2008 at 17:21

    David: If a real serial is leaked, it can be revoked (either using a rbl or in the next update).

    If however people are able to generate fake serials, you are screwed because there is nothing to blacklist and changing registration scheme will invalidate all existing serials.

  57. David Schwartz Says:
    November 19th, 2008 at 19:32

    Allan: True, a real serial can be revoked in the next version. But people can simply continue to use the old version of the program. (And it is quite common to distribute a specific executable version along with a serial for it.)

    Using RBL-style invalidation only works for some types of programs. It is very hard to do that for a program that doesn't normally use or need network access. Yes, it's much simpler for programs that require Internet access.

    As for you being screwed if people generate fake serials, no that's not true. In fact, you can easily stop them in the next version. You follow this approach: 1) You generate a new serial scheme. All future serials come from this scheme. 2) You embed a one-way hash of all existing valid serials in the next version. 3) You accept either existing valid serials whose hash is embedded in your application or serials generated by the new scheme.

  58. Allan Odgaard Says:
    November 19th, 2008 at 19:50

    David: The tagline for this blog is “Programming and using OS X” — on OS X it is not common to ship binaries with serials.

    It is however common to be connected to the internet when using OS X.

    And as for your approach by hashing all existing serials, that seems extremely tedious, why not just use a secure serial scheme, as is the point of the article your are commenting on? And didn’t you just say people can just stay with the old version?

    I think you are just arguing for the sake of the argument…

  59. David Schwartz Says:
    November 19th, 2008 at 20:18

    Allan: I am replying to your arguments to show where they are incorrect. For each argument, I make the assumptions that your argument makes.

    As for hashing all existing serials, that was a counter-argument to your argument. You said "If however people are able to generate fake serials, you are screwed because there is nothing to blacklist and changing registration scheme will invalidate all existing serials." I simply presented hashing serials as a way to show that you are incorrect. I never said it was the only way or the best way. It is simply an existence proof. You said there was no way. I showed a way.

    As for arguing for the sake of argument, no. I am arguing for the sake of showing where I think you are right and where I think you are wrong. People are likely to follow your advice, so it's important for them to know the gaps in your arguments.

    As for your new argument about being connected to the Internet being common, I think you may be assuming that what is common for you is common for everyone else. Are there really no OSX machines in offices without Internet access? On military bases on semi-secure networks? In rural areas? In the third world?

    I know I personally get very upset when a program that has no special reason to use the Internet 'phones home' without my knowledge or consent. I routinely firewall off programs that have no special business using my Internet access.

    I originally found this article because the second time it was cited by someone who was using it for a PC application. So if nothing else, I think there's value in pointing out the PC world is very different. Perhaps in terms of how many are Internet-connected (less in the PC world, I would guess) and definitely in terms of the kinds of piracy you currently see.

  60. Allan Odgaard Says:
    November 19th, 2008 at 21:02

    Replying to my arguments? I am not trying to argue anything here other than how pointless it is to argue over stuff that none of us have hard data for… as I have already said, this has been done to death!

    Though I feel I should just mention as for “phone home”, not that I do so myself (and the article is not about ways to make your software uncrackable, it is about how to use asymmetric encryption for license keys), the link I gave for RBL explains how DNS blacklists work. You only have to perform one DNS lookup to figure out if a license has been blacklisted, that is a check that would generally succeed even with firewalls — you imply there might be a problem with military bases or maybe in Africa, well… are you in all seriousness going to argue that this undermines the RBL scheme as a way to revoke leaked serials¹? Because then I think I was right in calling you out on just in it for the argument.

  61. David Schwartz Says:
    November 20th, 2008 at 17:40

    Allan: I honestly cannot figure out where your hostility is coming from. You are making arguments, and when I reply to them, you are accusing me of arguing just for the sake of arguing. I'm arguing because I disagree with you, and because people are following your advice without realizing the problems with it.

    By making this post, you are at least implicitly advocating that other people use this licensing scheme. That's fine, so long as those people understand its weaknesses. Otherwise, they can't make a rational decision for whether to use it or not.

    You brought up an RBL scheme as a way of saying that leaked real serial numbers are not a serious problem. I pointed out the various weaknesses with an RBL scheme. These include invasion of privacy and being ineffective for machines that don't have Internet connectivity. (In fact, I honestly don't think an RBL scheme is at all a realistic option. I don't know of any applications that use it.)

    In any event, I think we at least agree that the use of algorithmic serial numbers (serial numbers that are generated by some symmetric encryption-like algorithm) are a very poor choice. They are generally cracked within a week and an unlimited number of bogus serials can be generated.

    On the OpenSSL mailing list, on USENET, and other places, there are a lot of people, however, who think that this page completely documents a usable licensing scheme. In fact, you can see people who are confused in the comments on this very page. People have characterized Steve Checkoway's comment as a way to "attack" this scheme. In fact, it doesn't attack the scheme at all, because it doesn't in any way prevent the 100% accurate detection of fake versus real serials by code that follows the algorithm, which is the only problem this method is designed to solve.

    This scheme does one thing, and only one thing. It presents an algorithm for generating and validating licenses. Not following the algorithm is not an attack on the algorithm.

  62. Allan Odgaard Says:
    November 20th, 2008 at 18:33

    To run a RBL scheme requires that the software author setup (and maintain) a name server — something probably not for everyone, and that might be why you don’t see it — or maybe it is widely used, but no-one has said so until now. I actually had second thoughts about dropping this pearl here, because really, I think it’s quite ingenious to use such scheme, as programs designed to firewall applications are likely not going to see this DNS lookup (as the program asks the OS, and the OS, on behalf of the app, will send the UDP), plus you can argue that the “privacy invasion” is negligible.

    There btw are several Mac applications that “phone home”. There are also other schemes to deal with leaked serials, for example some only allow a license to be used to register an application up to a month after it has been issued (so the user needs to re-request it if he needs to re-register his app e.g. after OS upgrade), etc.

    As for coming of as hostile, keep in mind that text is bad at conveying emotions and not everyone has English as their first language.

    As for people misunderstanding the purpose and claims of the article, I don’t think your first post was a good way to try and remedy that.

  63. David Schwartz Says:
    November 20th, 2008 at 23:13

    I don't think the privacy invasion of an RBL scheme is negligible. Reason people can disagree. It reveals what software you are using and what license you have to it. It is specifically picked because it defeats many reasonable attempts to stop just this kind of reporting. Again, I don't know of any application that uses this technique.

    If I saw an application doing DNS lookups without me having requested any network operation, I would be upset and I would firewall off that application. I'd also publicly complain about it. I'm probably not typical.

    I like the idea of time limited installation licenses. But it shares another problem with RBL schemes. What happens if the company goes out of business? Worse, what happens if the company goes out of business and someone else takes over the domain names or IP address or whatever that the application uses to phone home? Depending on how the scheme is designed, there may be serious security issues there.

    Of course, if the designers knew this and planned for it, it's not hard to mitigate these risks. For example, the 'kill license' DNS reply can be a cryptographically-strong counter- response. So even if someone hijacks the DNS or takes over the domain, he can't invalidate a license.

    A problem with just the time-limited installation license is that if the company goes out of business, people rapidly lose the software rights that they paid for. You have only to look at the recent backlash surrounding Spore to see how this can play out. (Though it ultimately had little to no effect, so you can consider that too.)

    We're getting off-topic. But I strongly caution people designing licensing schemes to be careful what they make their customers go through. Too much, and they won't bother.

  64. Lord Anubis Says:
    November 30th, 2008 at 16:58

    Hi Gents, David and Allan,

    Why did you both stop? It was, or still is, very interesting both sided arguments. Maybe you should sit to gether and set up an article about this. It will be very welcome.

    And of course last but not least, it is a good article you wrote Allan.

    Greetz from another dimension

  65. David Schwartz Says:
    December 5th, 2008 at 02:47

    I kind of got the feeling that we both got our points across. We don't really disagree over anything specific, we just have different points of view. His points are completely valid for the types of problems he typically solves, most of my disagreements with him come from the fact that I solve a different set of problems than he does.

    I'm glad I could point out that taking Allan's suggestions outside of the scope in which they're valid can get you in trouble. And I'm glad Allan pointed out many of my criticisms don't apply strongly inside the scope he intended.

  66. Sohail Says:
    December 23rd, 2008 at 03:56

    Great article. Really helped me though I am neither using OpenSSL nor Mac OS X. Hopefully you won't hold it against me.

    How do you do N-day trials with this sort of setup? The only thing I can think of is that you have a license file generator somewhere and when you do the install, you hit that server for the license.

    TIA!

  67. David Schwartz Says:
    December 23rd, 2008 at 23:41

    Sohail: The basic idea is that you include an issue and expiration date in the signed license text. You then compare the current date/time to the expiration date in the certificate.

    If you do this the simple, obvious way, someone can set their clock back and continue using their certificate. There are several ways to get around this:

    1) Most web servers will send you the data and time when they send you a page. So you can request any web page from any web server. If the time is way off, you can tell. (Note that the server's time may be off, so you shouldn't 100% trust one server.)

    2) You can keep track, in a file or someplace appropriate, of the last time the program was used or how much cumulative time it has been running. If you were last used January 18th, 2008 and it's now December 12, 2007, you can tell. Or if your total use time exceeds the apparent clock time, you can tell.

    3) You can use your own secret time check. For example, if you have the domain 'example.com', you can make 'date.example.com' resolve to the current date encoded like an IP address. Then just lookup 'date.example.com' and you can tell the date.

    4) You can require the program to validate the current time and the license on startup. You can use a specific web page just for this purpose that runs your own program. Have them submit their license information and you reply with a signed "okay".

    There are lots more ways. It depends on your exact requirements.

  68. Mac Developer Network » Blog Archive » » Mac Software Business Year 1 Episode 2 Says:
    December 30th, 2008 at 18:33

    [...] rolled his own licensing engine using openssl based on this post by Allan [...]

  69. Marcus B. Says:
    January 13th, 2009 at 23:53

    David: To a great extend, I agree to Allan's statement that you are just argueing for the sake of argueing. Although it is important to reveal weaknesses, it is always much more difficult to establish "ingenious" things than to break them down.

    Surely, Allan's approach has some major weaknesses, but not in the algorithm itself but in keeping the algorithm intact.

    The things David pointed out, mainly apply to mass end-user software. But there is also costy (business) software for professional use, where most of the people will not use cracks or serials.

    I am amazed how simple the approach works, and keeps 80-90% of the (business) users from "accidentally" extending the license.

    The artwork is in my opinion to have a simple-to-use licensing schema that bothers users as little as possible.

    If you really want to contribute some useful things "to the comunity", then would you mind to share some of your good ideas that do not incorporate obvious weeknesses at first sight?

    P.S.: Thanks to all who contributed to this post. This also applies to David ;-)) And of course, not to forget Allan who started this great posting!

  70. David Schwartz Says:
    January 19th, 2009 at 15:18

    Marcus: I mostly agree with what you say. The problem is that Allan's original article was horribly misleading and led a number of people to choose a licensing scheme that was completely inappropriate for their needs. For example, if you read the original article, you will see that there is no mention whatsoever of the need to protect the licensing public key from tampering or to protect the OpenSSL libraries from being replaced.

    The problem with the original article is that it explains how difficult the scheme is to break in certain very particular ways without pointing out that it is very unlikely that anyone would ever attempt to break the scheme that way in the first place.

    Maybe Allan thought all of that was obvious, and thus there was no need to mention it. But if you look at the nonsense this generated on the OpenSSL support mailing list, you will quickly see that for many people it is not obvious.

  71. Allan Odgaard Says:
    January 19th, 2009 at 15:50

    No, it is not “horrible misleading”. Nothing at all is misleading about it.

    It states (in first paragraph): “[…] which should make it difficult for the cracker to generate his own fake license key and in the fourth comment posted for this article I say: “In theory you'll always be able to modify the binary to disable the protection scheme”.

    If people get the impression that this article is about protecting your binaries from tampering, then they must have been on drugs when reading it; if people are unaware that binary tampering is possible, then they are both rather unimaginative and didn’t read the first few comments, so not sure what your further comments repeating this fact benefits.

    If there really is this much confusion about the stated goal of this article, I can update it to put a disclaimer at the top, do you have any links to the confused OpenSSL mailing list threads so I can better understand what exactly the misconceptions are?

  72. David Schwartz Says:
    January 20th, 2009 at 19:10

    I don't want to get into this again. But what's misleading is that it talks about how difficult it is to create a fake license key, but nobody would ever try to do that to a program that uses asymmetric encryption for the license keys. That's like talking about how hard your car is to steal because it cannot be concealed in a pocket.

  73. Allan Odgaard Says:
    January 20th, 2009 at 19:56

    David: I realize that you find it useless to protect against fake serials, but that does not make the article “horribly misleading” — maybe you should lookup the word. As for your analogy, a more apt one would be an article about how to make a car door lock that can’t be picked, and you coming along claiming it is horribly misleading because a robber can still smash the windshield.

    You didn’t address my suggestion of putting in a disclaimer to help with the confusion you say you have observed, how about being constructive for a change?

  74. David Schwartz Says:
    January 20th, 2009 at 22:18

    "As for your analogy, a more apt one would be an article about how to make a car door lock that can’t be picked, and you coming along claiming it is horribly misleading because a robber can still smash the windshield."

    Exactly. That would be a horribly misleading article if it wasn't generally understood that no matter how secure a door lock is, a robber can break in the windshield. An article that claimed to provide a car security policy that only talked about secure door locks would be very misleading.

    Specifically, the articles says, "… in a way which should make it difficult for the cracker to generate his own fake license key(s)." This is true in a very technical sense — they cannot create fake license keys that will be accepted by the unmodified software. It is not, however, true in the more important practical sense, there is no assurance they cannot run the software without a valid license.

    As for a disclaimer clearing up the confusion, I don't think that's needed. I think the comments have cleared up the misunderstandings. It might be helpful to put somewhere something like: "Generating licenses that are difficult to forge is only one part in a licensing scheme. No matter how difficult it is to generate a fake license that will be accepted by the unmodified software, one can modify the software to accept an invalid license. Defeating such attempts is outside the scope of the license generation scheme."

  75. Marc Says:
    March 8th, 2009 at 18:48

    Thanks for the post Allan. However, there appears to be an error in your code. If data_size is supposed to be the length of the encoded message, then the assert statement is incorrect. data_size in this case is the same as RSA_size(rsa_key), and the decoded data that dst points to will have length data_size – 11. So assertion should be:

    assert(data_size == RSA_size(rsa_key));

    If you meant data_size to be the length of the unencoded message, then the assertion is correct, but data_size is not the length of the encoded message, so it is the incorrect argument to pass to RSA_public_decrypt. In this case you would pass data_size + 11 to RSA_public_decrypt.

    I think your post would benefit from a more complete working example because there are a few things that are not obvious, like this issue with padding, the format of the public key, etc. Also, you never free the memory pointed to by dst.

    Marc

  76. Serial codes vs. license files - Marc Charbonneau’s Blog Says:
    March 22nd, 2009 at 20:26

    [...] updates and blacklists, a serial number generator can be especially damaging. As far as I know, using OpenSSL it’s possible to create a licensing scheme that can not be beat by serial [...]

  77. Allan Odgaard Says:
    May 23rd, 2009 at 08:41

    Marc: I removed the ‘+11’ from the assertion. As for a more complete (working) example, the AquaticPrime framework is a F/OSS implementation of the scheme described in this article — I hope people can settle with that (I probably should make a habit out of providing downloadable source when I post articles :) ).

  78. Allan Odgaard Says:
    May 23rd, 2009 at 08:44

    As for never freeing dst, that is because dst points to the decrypted license key, so we want to further work with that (like validate the license key).

  79. Frederik Says:
    May 29th, 2009 at 06:54

    Thank you for the great article.

    Did anyone ever try to use Elliptic Curve Cryptography (http://en.wikipedia.org/wiki/Elliptic_curve_cryptography) instead of RSA for this? Supposedly one can use smaller key lengths with similar security, which could result in shorter license keys. Crypto++ (http://www.cryptopp.com) is a crypto-library supporting ECC.

  80. Alex Ross Says:
    June 3rd, 2009 at 23:35

    Researchers have used collision attacks on MD5 to produced forged SSL certificates [1]. Research on SHA-1 has advanced to the point where collisions can be found in about 2^52 operations, and it is reasonable to think that this number will continue to drop. Thus, it may soon be possible to forge license-keys generated by the scheme discussed in this article as well. If you have the option, I would suggest using the “whirlpool” hash function (to be included in openssl 1.0), until the SHA-3 hash function becomes available.

    [1][http://www.schneier.com/crypto-gram-0901.html#3]

  81. Allan Odgaard Says:
    June 24th, 2009 at 21:29

    Frederik: Have a look at this project.

    Alex: The SHA-1 is just an example payload here, not very essential, i.e. I would suggest (also) including a serial number (32 bit integer) to uniquely identify the key rather than rely on the hash to be the only unique identifier (as people/companies/IT departments do request name changes).

    Which is something those of you wanting a short key should consider, simply providing an encrypted hash is not ideal as at least I include the following info in the license key: Serial number, date issued, number of seats (for site licenses), type of license (academic license, evaluation/NFR, gift, etc.), and maybe a few other things.

    But ECDSA can still work for this requirement e.g. by prefixing the signature with this info (compacted into a long integer) but remember to also have the actual signature be on this data, so that altering this prefix invalidates the key.

  82. No One Says:
    March 21st, 2010 at 22:01

    Or maybe you can make another tut for ECDSA or other ECC scheme examples since it's hard to find such thing today on for Mac. (I know windows app use it a lot)

    I learn a lot from your post above, thx a lot :)

  83. Generate reasonable length license key with asymmetric encryption? | Webmaster Forum Archive Says:
    June 1st, 2010 at 16:02

    [...] fooled around with OpenSSL for a while but couldn't come up with anything of a reasonable [...]


Leave a Reply