Author Topic: [Source] Licensing Example  (Read 2273 times)

0 Members and 1 Guest are viewing this topic.

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
[Source] Licensing Example
« on: January 07, 2014, 02:12:05 pm »
I was curious how licensing works, so I wrote the following example application that has a licensing system. I figured this code might be useful for you too, either to implement a licensing system for your application or just to know how this might be done in case you want to reverse engineer software.

Note that there are several possibilities to implement this, so this is really just one example.

This is how it works in general:

The customer who buys your software tells you the username to license the software with.
Upon paying for the software, he will get: the software itself that has a personal serial number and an activation key

The activation key is generated from the username and the serial number. You may also include more information as you like, including hardware information which will limit the use of the software to a certain device (caution here, it may piss off the users if the software doesn't work anymore after a hardware update).
You put this into a hashing algorithm and thus get the activation key. Example:

Code: [Select]
activationKey = hash(username + serial + SOME_CODE).

The customer starts your program and is asked for username and activation key. He enters it and the program will verify the activation key by comparing it with the hash it generates from the username and the serial. If both are the same, the software will run properly.
The license information is saved subsequently in the app data directory, so the user only has to input his key once.

Example GUI program with source:

zip file attached



Here is also valid username-key-pair example for testing:

username: test
activation key: ec80b8ca371d17aaa5361d811f8bc7a3f4207134af3dc70dbbac102592a91533


Source:

Code: [Select]
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.swing.JOptionPane;

public class License {

    private static final String SERIAL_PATH = "serial";
    private static final String LICENSE = "license";
    private static final String CODE = "4e0f07ff2d9440912c928ca4986c98e97b13b5ad35dee80e9663a6357edfc2de";
    private boolean activated;
    private String serial;
    private File licenseFile;

    public License() {
        prepareAppDataDir();
        readSerial();
        readActivationStatus();
    }

    private void readActivationStatus() {
        try (BufferedReader reader = new BufferedReader(new FileReader(licenseFile))) {
            String username = reader.readLine();
            String activationKey = reader.readLine();
            activate(activationKey, username);
        } catch (FileNotFoundException e) {
            activated = false;
        } catch (IOException e) {
            e.printStackTrace();
            activated = false;
        }
    }

    private void readSerial() {
        try (Reader ir = new InputStreamReader(getClass().getResourceAsStream(
                SERIAL_PATH));
                BufferedReader reader = new BufferedReader(ir)) {
            serial = reader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean activate(String activationKey, String username) {
        String hash = hash(username + serial + CODE);
        System.out.println(hash);
        activated = hash.equals(activationKey);
        if(!activated) {
            removeActivationStatus();
        }
        return activated;
    }
   
    public void removeActivationStatus() {
        licenseFile.delete();
    }
   
    public void saveLicense(String key, String username) throws IOException {
        try(BufferedWriter writer = new BufferedWriter(new FileWriter(licenseFile))) {
            writer.write(username);
            writer.newLine();
            writer.write(key);
        }
       
    }
   
    /**
     * Prepares application data directory depending on OS.
     */
    private void prepareAppDataDir() {
        File appDataDir;
        if (System.getProperty("os.name").toLowerCase().contains("windows")
                && new File(System.getProperty("user.home"), "AppData\\Roaming")
                        .exists()) {
            appDataDir = new File(System.getProperty("user.home"),
                    "AppData\\Roaming\\LicensingExample");
        } else {
            appDataDir = new File(System.getProperty("user.home"),
                    ".licensingExample");
        }
        createDir(appDataDir);
        licenseFile = new File(appDataDir.getAbsolutePath() + "/" + LICENSE);
    }

    /**
     * Creates directory if it doesn't exist.
     *
     * @param dir
     *            directory to be created
     */
    private void createDir(File dir) {
        if (!dir.exists()) {
            if (!dir.mkdir()) {
                System.err.println("error creating directory "
                        + dir.getAbsolutePath());
                JOptionPane.showMessageDialog(null, "error creating directory "
                        + dir.getAbsolutePath(), "Error",
                        JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    private String hash(String string) {
        MessageDigest sha256;
        try {
            sha256 = MessageDigest.getInstance("SHA-256");
            byte[] hash = sha256.digest(string.getBytes());
            return byteToHex(hash);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String byteToHex(byte array[]) {
        StringBuilder buffer = new StringBuilder();
        for (int i = 0; i < array.length; i++) {
            if ((array[i] & 0xff) < 0x10) {
                buffer.append("0");
            }
            buffer.append(Integer.toString(array[i] & 0xff, 16));
        }
        return buffer.toString().trim();
    }

    public boolean statusActivated() {
        return activated;
    }

    public String getSerial() {
        return serial;
    }

}

FAQ

Is this safe?

No licensing system is safe.

What can I do to make it more safe?

Use obfuscation and other anti-reversing techniques, i.e. http://www.cs.sjsu.edu/faculty/stamp/students/kundu_deepti.pdf
Try not to annoy the customer who was so kind to buy your software with protection techniques. Rather make the software so great that people want to pay for it in order to support it. ;)

Offline vezzy

  • Royal Highness
  • ****
  • Posts: 771
  • Cookies: 172
    • View Profile
Re: [Source] Licensing Example
« Reply #1 on: January 07, 2014, 04:27:20 pm »
Behead those who develop proprietary software.
Quote from: Dippy hippy
Just brushing though. I will be semi active mainly came to find a HQ botnet, like THOR or just any p2p botnet

Offline Kulverstukas

  • Administrator
  • Zeus
  • *
  • Posts: 6627
  • Cookies: 542
  • Fascist dictator
    • View Profile
    • My blog
Re: [Source] Licensing Example
« Reply #2 on: January 07, 2014, 05:41:56 pm »
Behead those who develop proprietary software.
Lolz, agreed.

@OP: very nice, though a bit short. I had such an idea to write about in tutorials to-write list, looks like you beat me to it xD
The hashing you shown here is very basic, but it works I suppose, but huge software devs use their own algos I think. And you could have went into detail about different types of licenses, like limited, timed and such... but they all seem straightforward though, connect to the central database and check...?

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
Re: [Source] Licensing Example
« Reply #3 on: January 07, 2014, 06:05:27 pm »
It is not a tutorial, it is really only a simple source example with explanations. So you can still write your paper.

@vezzy: I guess I am lucky that I only write open source software.

Offline Phage

  • VIP
  • Overlord
  • *
  • Posts: 1280
  • Cookies: 120
    • View Profile
Re: [Source] Licensing Example
« Reply #4 on: January 07, 2014, 11:56:39 pm »
This serves great as a prove of example of how it works. Tbh it seems much simpler that I thought it was, nice job.
"Ruby devs do, in fact, get all the girls. No girl wants a python, but EVERY girl wants rubies" - connection

"It always takes longer than you expect, even when you take into account Hofstadter’s Law."

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
Re: [Source] Licensing Example
« Reply #5 on: January 08, 2014, 09:30:23 am »
This serves great as a prove of example of how it works. Tbh it seems much simpler that I thought it was, nice job.

You can do it much more complicated to make it more difficult for others to reverse engineer it. But I don't think it is worth the work. Someone will eventually crack it nevertheless.
This licensing example is patched easily since I didn't use any anti reversing techniques so far (I didn't want to obscure how the licensing mechanism works, because the purpose was showing how it works). Whoever wants to try can use it as an easy reverse engineer challenge.
« Last Edit: January 08, 2014, 09:31:46 am by Deque »