License key / Serial number generator and checker
I need a serial number generator and accompanying checker. I would like to be able to set a salt (and maybe a length). The generator should only produce serial numbers that pass the test of the checker. Those numbers should only account for a small fraction of all the possible numbers of the given length.
To clarify: If you buy commercial software, it is sometimes protected with a serial number/a key. If you type it in, the software verifies it algorithmically (by checking whether it fulfills certain properties), rather than looking up a huge database. I'm also pretty sure that the keys were all generated algorithmically rather than by hand. And only a small fraction of all the possible keys of a given length are actually valid so it's hard to guess keys.
Salt: I don't know whether salt is the right word, but the algorithm should have at least one parameter, whose choice alters the generated keys (so that multiple people can use the same algorithm and needn't fear collisions).
That's pretty open-ended. What sorts of properties do you want the numbers to have? And what it the salt about and where would it be saved?
I'm not clear about this, if you're asking for a cryptographically secure random number generator - even with certain additional constraints - then that's easy, just tell us which platform/language you're on. If you're asking for something else - then it's not clear, and why would you ask on ITsec?
Here is an article I find very informative regarding generating secure license keys: How to Generate License Keys Securely It's about using elliptic curve cryptography to generate license keys. The generated keys can be as small as 20 characters and still secure.
If there is no real need for security, then here is a very fast serial number generator, with a checker:
- User a counter. Initialize it at 0. When you want a new serial number, increment your counter by 1000; the new counter value is the serial number. The checker works like this: a serial number is valid if it ends with three zeros. Only one of every 1000 numbers will be accepted by the checker.
If this solution does not please you, then you do have a need for security, and this calls for cryptography.
Even with both uppercase letters and digits (36 possible characters, and there you have both 'I' and '1', and also 'O' and '0'), a 160-bit signature will use 31 characters. Along with the payload, you will end up with serial numbers of length 35 or so, which is probably too much for an average user to type in (but not by a large margin; an 80-bit signature would fit nicely).
If you do not use a signature scheme, then you must be aware that a reasonably determined attacker will be able, through some disassembly, to circumvent the checker, or even to learn enough to be able to produce his own serial numbers (which the checker will happily accept). At that point, you will not get quantified security: you will not be able to say: "my scheme is secure up to a budget of 3.8 billion dollars". Rather, it will go as: "my scheme is secure until a sufficiently witty and bored student comes along, reverse-engineers the checker code, and publishes the result on Facebook".
The classical not-really-secure scheme would look like this:
- Use the counter from the previous scheme (the one with ends with three zeros). Encode it as a 64-bit block. Encrypt that block with some hardcoded symmetric key, using a block cipher. The checker knows the key, and verifies the serial number by decrypting it (with the same hardcoded symmetric key) and looking at the final zeros.
This is not really more secure than the plain counter, but at least the serial numbers will be random-looking. With an alphabet of 34 characters (digits and uppercase letters except 'O' and 'I'), a 64-bit block requires 13 letters, which is probably acceptable (a typical Microsoft serial number has 25 letters). For the 64-bit block cipher, I recommend XTEA, which should be fast and simple enough to implement.
thank you for your answer. I'm trying to understand the cryptographically secure solution. By giving the generator a private key and the checker a public key, the checker could make sure that the messages it gets actually come from the generator. But what would be the content of these messages? Could you please explain what you mean by payload and signature of the payload or give a very simple example? Thx in advance.
You want several serial numbers, I think. The "payload" is whatever makes them distinct from each other. Say, it is a counter. Or it could be a customer identifier.
If you want the cryptographically secure method you won't get around an internet connection to verify the serial. This means that such a protection scheme is better suited for subscription based software than it is for traditional shelf software.
With internet connections it's simple (since you use JS, I assume that's the one you want):
- Someone creates a key, that party has to know the secret
- Server knows secret and is able to decode the data
- Client sends the key, which is a binary blob encoded in Base32 (also see this)
- Server decrypts the key and checks whether it's valid (either just syntactically or also semantically)
Without internet connection you can still use a scheme similar to PGP signing in order to verify that the blob that the user enters was created by you. Encryption won't work the same, because the decryption always requires to know the secret and the big issue here is:
- you don't trust the user (otherwise you wouldn't need the protection scheme)
- you give the user the secret, compiled into your binary
Obviously both points contradict each other. On one hand you don't trust the user, on the other hand you have to deploy the secret used for decryption.
All in all I have to conclude that without the internet connection and the server-based validity check that results in the revelation of some knowledge (e.g. content that is useful only for so long) any protection scheme I have seen so far is more or less an arms race between crackers and vendors.
Now, if it isn't important to have a cryptographically secure system, I'd still go for any binary data that you can secure by means of a simple CRC or so. What comes to mind would be:
- Have a monotonically increasing serial number
- XOR it with your salt value (or any other reversible operation)
- Take the CRC32 of that value (or Adler32 or whatever) - add more salt here if needed
- Encode it with Base32 (aids readability etc)
- Only check that the CRC32 for validity ...