Poor man serial number generation scheme

2019-03-31 18:02发布

问题:

I would like to get some simple scheme / algorithm for generating serial numbers based on some unique hardware id (cpu id or ethernet mac address or hard disk serial number).

I would like scheme to work only in one direction - so application on client machine can verify serial number but not generate one. (So it would not be simple to crack).

Now most probably most of you will recommend some sort of RSA public / private key pair encryption, which can work reliably enough - client does not have private RSA key, so he cannot "generate" serial number.

But main problem with RSA signature is that it's too big - it's signature size is 128 or 256 bytes depending on RSA key size (RSA signature size?)

  • I want serial number to be simple copy paste from mail to registration form - so maximum 64 characters, ideally 32 bytes.

Ok, now you will probably say that this kind of protection is not good enough against brute force kind of hacking - where you simply try out all combinations in order to determine correct serial number.

But I would say that typically you need to hire "expensive" hacker or hacker team to create such brute force cracking application.

Also I think it's possible to change serial number generation algorithm for next versions of application, or use multi-round passing to slow down brute force dramatically.

As a base I would prefer to use plain C or C++ (not C#), preferably Windows / wincrypt.h or any existing plain C source code (Preferably not huge 3-rd party libraries).

Is it possible to create RSA public / private key pair so signature size would be 32 characters long ?

回答1:

You might want to check out ECDSA.

ECDSA is a public key algorithm like RSA, but with a shorter key and signature size than RSA to provide the same level of effective security. ECDSA is based on a elliptic curve cryptography. Both the integer factorization problem used in RSA and elliptic curve used in ECDSA reduce to discrete logarithm problem, which is believed to be difficult to solve.

For example, for a security level the same as 1024-bit RSA, which is estimated to have approximately 80-bit of security, you can use a 160-bit ECDSA key, which produces a 320-bit signature. You can base64 encode a 320-bit signature into a 54 characters string or ascii85 encode into a 50 characters string.

Alternatively, if you want to keep 32-characters with base64 encoding, which can hold at most 192-bit of data, you can use ECDSA with 96-bit key size. The effective strength of 96-bit ECDSA is 48-bit, which is generally not strong enough for proper encryption, but in your case it may still be easier for the attacker to reverse engineer the program to remove your license key checks rather than trying to generate a forged key.



回答2:

You're looking for a cryptographic hash function. A good example, which fits in your desired 32 characters, would be md5.



回答3:

I've decided to post my own solution, which is using now proposed on this forum ECDSA private / public key pair, and includes usage of two-way encrypting algorithm about which I have asked in here: Poor man serial number generation scheme, part 2

It's possible that code still contains some bugs, but I've tried to do my best and test everything that I've could.

It uses also managed code part and C# code to test C++ code, but depending on your implementation you might want to drop out managed parts completely.

Because size of answer is limited here, I had to put my code on external url - so size of answer would be small enough.

Here are my code snipets:

  • SerialNumberRegister.h
  • SerialNumberRegister.cpp
  • DemoForm.cs

Third code is incomplete - it's only demo code how it could be coded. If you don't use C#, then upper layer could be something else.

For EDSCA signing algorihtm I have used https://github.com/esxgx/easy-ecc with rather little fix - to shorten size of signature:

/* Curve selection options. */
#define secp128r1 16

#ifndef ECC_CURVE
    #define ECC_CURVE secp128r1
#endif
  • so smallest possible signature size.

And now when you start to check out the code -you will notice that public and private key pairs are not initialized - since they are tightly bound to my product. But let me post some demo key here (I have used current code to initialize them)

unsigned char publicKey[] = {
    0x03, 0x7A, 0x0E, 0xE4, 0x2C, 0xC1, 0x29, 0x1D, 0x22, 0xCF, 0x6F, 0xCE, 0x03, 0x5F, 0xBF, 0x31, 0xDD, 
};
unsigned char encryptedPrivateKey[] = {
    0x9E, 0x8C, 0x4C, 0x8F, 0x02, 0x1D, 0x7E, 0x34, 0xA0, 0xDB, 0xBC, 0x45, 0xD8, 0x1A, 0x57, 0x7A, 
};

So with current public / private key pair - for hardware id 000000000000 (derived from network card mac address) - following serial key is valid:

pc000000000000-NnE84PSfl8nFxmhpHn+gvNFwZNkwuEFKAzu/yEmDohc=

This now contains signed part ("pc000000000000") and signature itself ("NnE84PSfl8nFxmhpHn+gvNFwZNkwuEFKAzu/yEmDohc=").

Now the best part from this is that you now have full source code of my solution, including public and private key. What is missing is password which I have used to encrypt administrator private key - but without it you cannot generate serial numbers. I now challenge now hackers to hack this solution - create serial key generator to my software. Quite interesting dilemma - you have full source code, but it's useless to you. :-)

I think cracking software is still possible (Asm's jump short, no-operation), but this is something that always possible to perform.

Target is to make hacker's life bit harder by introducing simple, small and pretty solution for serial key generation - solution which can be simply copy pasted from one product to another.