Creating Zero-Cost Licensing for Java Applications

We hope you checked out our previous post that tells how you can easily create time-limited trial versions of your Java applications and libraries. The only drawback of that approach is that it is needed to re-protect an application with Stringer Java Obfuscator in order to extend the working period. And probably, you will not be happy to spend your time doing that, it is better your company's sales managers get in charge of issuing trial versions to customers. You might easily integrate the Stringer's task that produces the protected license jar with your existing CRM system, or write a script/simple application for your sales team. So, it is one of the goals that is to be reached by our licensing system. There are lots of solutions in the market that costs money, but if you use Stringer Java Obfuscator, you might use the approach bellow in order to add licensing to your Java applications and libraries at no additional cost.

The main idea that is going to be used in our approach is that we, like in the previous post, will create two components: first one (license) will be time-limited, so it perfectly fits for subscriptions and trials, the second component is your application or library, which uses classes from the first component in order to get a license information. Thus, if the first component stops working, your application becomes inoperable as well.

Here is a draft of such a system:

License

Let it be a jar file (with, for example, .license extension), inside of it we place a properties file with license information, for example:

license.id=001
license.email=BigBoss@BigCompanyFortune500.com
license.company=BigCompany Fortune500

A properties file is used to make us able to easily generate a license without re-builds or modifying class files. And to make a malicious one unable to modify the file, we encrypt it with use of Stringer Java Obfuscator's Resource Encryption function.

Now, we have to create a class that will be used from the application for getting information about a certain license:

public class License {
    final static ResourceBundle bundle = java.util.ResourceBundle.getBundle("licenseInfo");

    public final static String getId() {
        return bundle.getString("license.id");
    }

    public final static String getEmail() {
        return bundle.getString("license.email");
    }

    public final static String getCompany() {
        return bundle.getString("license.company");
    }
}

Build the jar and use the following configuration of Stringer Java Obfuscator (yeah, we are old-school guys and use Ant, ... and Maven sometimes)

Ant:

<stringer srcFile="${dist}/license.jar"
                  destFile="${dist}/product.license"
                  verbose="true"
                  checkCaller="true"
                  resourceEncryption="true"
                  integrityProtection="true"
                  optimize="true"   
                  trialExpirationTimestamp="${trial.period.ts}"
                  trialExpirationTimestampPattern="yyyyMMdd">
</stringer>

Maven:

          <plugin>            
                <groupId>com.licel</groupId>
                <artifactId>stringer-maven-plugin</artifactId>
                <version>2.5.15</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>stringer</goal>
                        </goals>
                        <configuration>  
                            <verbose>true</verbose>
                            <checkCaller>true</checkCaller>
                            <resourceEncryption>true</resourceEncryption> 
                            <integrityProtection>true</integrityProtection>
                            <trialExpirationTimestamp>${trial.period.ts}</trialExpirationTimestamp>
                            <trialExpirationTimestampPattern>yyyyMMdd</trialExpirationTimestampPattern>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

Our next step is to make our application able to check if the license (license jar) was created by us, not by a bad guy. For that we will check a jar file's signature.

We create a keypair and self-signed certificate:

keytool -genkey -keyalg RSA -alias license -keystore license_key.jks -validity 720 -keysize 2048

Then we can use the key to sign the license:

Ant:

<signjar jar="${dist}/product.license" 
    alias=" ${keyAlias}"
    keypass=”${keyPass}” 
    storepass="${keystorePass}"
    storetype="${storeType }"
    keystore=”${keystoreLocation}”/>

Maven:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jarsigner-plugin</artifactId>
    <version>1.2</version>
    <executions>
        <execution>
            <id>sign</id>
            <goals>
                <goal>sign</goal>
            </goals>
        </execution>
        <execution>
            <id>verify</id>
            <goals>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <keystore>${keystoreLocation}</keystore>
        <alias>${keyAlias}</alias>
        <storepass>${keystorePass}</storepass>
        <keypass>${keyPass}</keypass>
        <storetype>${storeType}</storetype>
        <arguments>
            <argument>-sigalg</argument>
            <argument>SHA256withRSA</argument>
            <argument>-digestalg</argument>
            <argument>SHA-256</argument>
        </arguments>                                    
    </configuration>
</plugin>

To ensure that a malicious one did not sign the license with their own certificate we check it, let us get it via the following command:

keytool -list -rfc -alias license -keystore license_key.jks

Output:

Alias name: license
Creation date: 16.05.2016
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
-----BEGIN CERTIFICATE-----
MIIDLzCCAhegAwIBAgIESMPzJjANBgkqhkiG9w0BAQsFADBIMQowCAYDVQQGEwEx
……
wmK3
-----END CERTIFICATE-----

Lines between -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- we use in our application.

MIIDLzCCAhegAwIBAgIESMPzJjANBgkqhkiG9w0BAQsFADBIMQowCAYDVQQGEwEx
……
wmK3

Application

In order to check the license we do the following:

  • Load License class with use of URLClassLoader
  • Call ProtectionDomain->CodeSource->getCertificates from License class' instance and compare the certificate with one we got
  • With use of Java Reflection get the properties of the license

Here is an example of how should it look like:

    private final String cert
            = "MIIDLzCCAhegAwIBAgIESMPzJjANBgkqhkiG9w0BAQsFADBIMQowCAYDVQQGEwEx"
        …
            + "wmK3";

    public final LicenseInfo checkLicense(String path) {
        try {
            URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file://" + path)});
            Class licenseClass = urlClassLoader.loadClass("license.License");
            Certificate[] certs = licenseClass.getProtectionDomain().getCodeSource().getCertificates();
            if (certs == null || certs.length > 1) {
                throw new RuntimeException("No certificates");
            }
            if (!(Base64.getEncoder().encodeToString(certs[0].getEncoded()).equals(cert))) {
                throw new RuntimeException("Invalid cert");
            }
            LicenseInfo licenseInfo = new LicenseInfo();
            Object license = licenseClass.newInstance();
            licenseInfo.setId((String) licenseClass.getDeclaredMethod("getId", null).invoke(license, null));
            licenseInfo.setEmail((String) licenseClass.getDeclaredMethod("getEmail", null).invoke(license, null));
            licenseInfo.setCompany((String) licenseClass.getDeclaredMethod("getCompany", null).invoke(license, null));
            return licenseInfo;
        } catch (Exception ex) {
            throw new RuntimeException("Invalid license");
        }

    }

The application should be protected with Stringer Java Obfuscator as a string field cert that contains the certificate must be encrypted and the application must be tamper resistant. The configuration is similar to one that we used for the license, but here we would not use trialExpirationTimestamp and trialExpirationTimestampPattern.

We have shown how you could use Stringer Java Obfuscator to create a licensing system for your Java applications and libraries. As for the level of security, it is definitely not worse than commercial licensing systems in terms of security, in most cases, such an approach is even better than solutions available in the market. And here is another important tip, if you include more components that are required for normal functioning of your application into license, you will get a more secure licensing.

We will be happy to hear comments and your questions. The sample project will be available on our GitHub account soon.