Serial Key Generation and Validation in Java

In this post, I am going to show how to write a very basic serial key generation module for any Java based application - Same algorithms can be used for any programming language. The module consists of three parts.

  1. Algorithm for Serial Generation
  2. Generating the Serial
  3. Validating the Serial

1. Algorithm for Serial Generation

The following can be used as a simple algorithm for generating serial keys with 18 digits. In this method we are generating the serials based on the input the user gives, which can be the name of the user, company name etc. So most of the times the serial will be unique (based on the input).  We get the name of the user as the input and generate the  MD2, MD5 & SHA1 hashes for the string and concatenate together. This will generate a total of 104 digits, since we need only 18 of them, we can use a set of pre defined numbers to select the 18 digits.

The below figure explains the algorithm. I have selected some random numbers to pick the 18 digits from 104 character hash, you can use any number you like which makes the serial unique.

2. Generating the Serial

To generate the serial, we need a input string and based on the input string we will be generating MD2, MD5 and SHA1 hashes. The method calculateSecurityHash takes the input string and the hashing method as input and generates the hash based on the method.

String serialNumberEncoded = calculateSecurityHash(fullNameString,"MD2") +  calculateSecurityHash(fullNameString,"MD5") +
 calculateSecurityHash(fullNameString,"SHA1");

Generating the Hash for the input string based on the type.

private String calculateSecurityHash(String stringInput, String algorithmName)
 throws java.security.NoSuchAlgorithmException {
 String hexMessageEncode = "";
 byte[] buffer = stringInput.getBytes();
 java.security.MessageDigest messageDigest =
  java.security.MessageDigest.getInstance(algorithmName);
 messageDigest.update(buffer);
 byte[] messageDigestBytes = messageDigest.digest();
 for (int index=0; index < messageDigestBytes.length ; index ++) {
  int countEncode = messageDigestBytes[index] & 0xff;
  if (Integer.toHexString(countEncode).length() == 1) hexMessageEncode = hexMessageEncode + "0";
  hexMessageEncode = hexMessageEncode + Integer.toHexString(countEncode);
 }
 return hexMessageEncode;
}

Once all the three types of hashes are combined, we will have a total of 104 characters. Since we need only 18 for our serial key we can pick any random 18 digits from the combined hash. We cannot use random number generation to pick up the 18 digits since we need a valid exit strategy for validating the key.

String serialNumber = ""
    + serialNumberEncoded.charAt(32)
    + serialNumberEncoded.charAt(76)
    + serialNumberEncoded.charAt(100)
    + serialNumberEncoded.charAt(50)
    + "-"
    + serialNumberEncoded.charAt(2)
    + serialNumberEncoded.charAt(91)
    + serialNumberEncoded.charAt(73)
    + serialNumberEncoded.charAt(72)
    + serialNumberEncoded.charAt(98)
    + "-"
    + serialNumberEncoded.charAt(47)
    + serialNumberEncoded.charAt(65)
    + serialNumberEncoded.charAt(18)
    + serialNumberEncoded.charAt(85)
    + "-"
    + serialNumberEncoded.charAt(27)
    + serialNumberEncoded.charAt(53)
    + serialNumberEncoded.charAt(102)
    + serialNumberEncoded.charAt(15)
    + serialNumberEncoded.charAt(99); 

You can replace the numbers with anything between 0 & 103 so that the key is unique and based on the input string.

3. Validating the Serial

Now, whenever we get a user name & serial combination, we should be able to validate that. Since we already know the algorithm used to generate the serial, the validation part is pretty easier. We cannot follow the steps which we did while generating the serial in opposite direction because we will end up with a bunch of characters without any valid lead. Since we have the serial and user name to validate, we take the user name and generate the serial for the user name as per our algorithm. Once we have the serial number, we compare this against the serial which we got for validation, if both matches then we have a valid key.

String serialNumberEncoded = registrationAppSerialGenerationReversal.calculateSecurityHash(fullNameString,"MD2")
    + registrationAppSerialGenerationReversal.calculateSecurityHash(fullNameString,"MD5")
    + registrationAppSerialGenerationReversal.calculateSecurityHash(fullNameString,"SHA1");

String serialNumberCalc = ""
    + serialNumberEncoded.charAt(32)
    + serialNumberEncoded.charAt(76)
    + serialNumberEncoded.charAt(100)
    + serialNumberEncoded.charAt(50)
    + "-"
    + serialNumberEncoded.charAt(2)
    + serialNumberEncoded.charAt(91)
    + serialNumberEncoded.charAt(73)
    + serialNumberEncoded.charAt(72)
    + serialNumberEncoded.charAt(98)
    + "-"
    + serialNumberEncoded.charAt(47)
    + serialNumberEncoded.charAt(65)
    + serialNumberEncoded.charAt(18)
    + serialNumberEncoded.charAt(85)
    + "-"
    + serialNumberEncoded.charAt(27)
    + serialNumberEncoded.charAt(53)
    + serialNumberEncoded.charAt(102)
    + serialNumberEncoded.charAt(15)
    + serialNumberEncoded.charAt(99);

if (serialNumber.equals(serialNumberCalc))
    System.out.println("Serial MATCH");
else
    System.out.println("Serial MIS-MATCH"); 

Sample output from this program is demonstrated below.


This is a very basic implementation and used to demonstrate the underlying concept of serial generation and validation, the algorithm can be improved by adding more variables.

3 Comments:

  1. Ohad said...
    You have here 18 digits, not 16...
    ??
    Joey said...
    @Ohad - Thanks for pointing out, Its been changed.
    Anonymous said...
    Nobody should be using MD2, no matter how small the application.

    You would be better off building a larger hash/digest string consisting of the MD5, SHA1, and SHA256 hashes of the input data, and then selecting the 18 (or however many are needed) chars from it.

    Interesting idea though - thanks for posting this. :)


    --
    Salman A.

Post a Comment



Post a Comment