VoidTwo
VoidTwo

Reputation: 637

Encrypting an executable jar

To get the basics out of the way, I'm using Eclipse to code and create my executable jar files.

Some background research:
I'm aware that you can decompile jar files and see the source code. In fact, there are free programs out there like JD GUI that can easily decompile a jar file and reveal all its contents. This is an issue especially if you want to distribute a java program.
When I learned about this, I immediately began looking around for a solution, but I couldn't find a straight answer.

The issue:
My question is, how do you encrypt a jar file, or at least encrypt the class file so that it isn't readable if you decompile it?
One solution I keep seeing is that you can obfuscate your code, but the issue with this is that your code still has to be able to run, and therefore the obfuscation can be reverse engineered with a little effort. The only other solution I could think of is having two separate jar files so that one of the jar files is encrypted and requires the other jar file to decrypt it. Now, before you say "they could just decompile the other jar and use it to decrypt the first jar". My idea was using a cipher that would be used to decrypt the first jar. In theory, the user could know the exact decryption method, but it would be completely useless without the secret word (cipher).

My question:
How would I implement this? I'm asking how do I run a jar file to encrypt/decrypt another jar with a user-specified cipher?
Feel free to give example code, I'm looking for any help I can get.

Thanks in advance!

Upvotes: 2

Views: 6156

Answers (1)

Jake Holzinger
Jake Holzinger

Reputation: 6063

Imagine you have a JAR file where some of the classes have been encrypted after compilation.

Let's say you have an encrypted class called SecureMain that you want to decrypt and execute:

public class SecureMain implements Runnable {

    @Override
    public void run() {
        System.out.println("Running...");
    }

}

Given the following JAR file structure:

org
`---stackoveflow
    `---example
        |---EncryptedClassLoader.class
        |---Main.class
        `---SecureMain.enc

Where the files with an enc file extension are encrypted using some secret key.

The EncryptedClassLoader can be implemented to decrypt the class file before it is loaded:

public class EncryptedClassLoader extends ClassLoader {

    private final SecretKeySpec key;

    public EncryptedClassLoader(SecretKeySpec key) {
        this.key = key;
    }

    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            String[] segments = name.split("\\.");
            String filePath = String.join("/", segments) + ".enc";
            byte[] bytes = decryptResource(filePath);
            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            throw new ClassNotFoundException("Unable to load class: " + name, e);
        }
    }

    private byte[] decryptResource(String filePath) throws Exception {
        File file = new File(getResource(filePath).getFile());
        byte[] bytes = Files.readAllBytes(file.toPath());
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(bytes);
    }

}

Then the Main class can be implemented to load the secret key from the command line arguments, then load an execute the encrypted SecureMain class:

public class Main {

    public static void main(String[] args) throws Exception {
        byte[] bytes = Base64.getDecoder().decode(args[0]);
        SecretKeySpec key = new SecretKeySpec(bytes, "AES");
        ClassLoader loader = new EncryptedClassLoader(key);
        Class<?> cls = loader.loadClass("com.stackoverflow.example.SecureMain");
        Runnable main = (Runnable) cls.newInstance();
        main.run();
    }

}

Finally the JAR should be executed with the secret key passed as an argument.

java -jar myjar.jar <base64 encoded key>

Upvotes: 3

Related Questions