Java, ProGuard, and Ant - How to obfuscate Java class files with ProGuard

Java obfuscator/obfuscation FAQ: How can I obfuscate my Java class files so they can't easily be decompiled? (Or, how do I use ProGuard to obfuscate my Java class files?)

As I've written before in Java decompilers and obfuscators, if you're sharing a Java application with other people, and you don't want them to be able to easily decompile your Java class files, you're going to want to obfuscate your Java class files. One way to obfuscate your class files is with a tool named ProGuard. In this article I'll share how I obfuscate my Hyde application with ProGuard.

It's easy to decompile Java class files

As I mentioned in an earlier article, you can easily decompile Java class files with a tool given the name "Java Decompiler Project". I tested this Java decompiler on my own class files, and it works as advertised, magically turning my Java class files back into Java source code.

If you're selling a Java application, or trying to protect trade secrets while distributing Java class files, the counter measure to this is to obfuscate your Java class files. There are several free projects that help you do this, including one named ProGuard, which I used on my Java application.

Using ProGuard with Ant to obfuscate Java class files

There are a number of ways to configure ProGuard, but I choose to create an Ant task to obfuscate my Java class files, as my application is built using Ant, and adding another Ant task made it easy to keep building my application this way.

At the beginning of my Ant build.xml configuration file I added one line like this to specify the default ProGuard Ant properties:

<taskdef resource="proguard/ant/task.properties" classpath="/Users/al/Projects/DesktopShield/build/proguard.jar" />

That line assumes that the proguard.jar file is in the directory shown.

Later in the Ant build.xml file I created an obfuscate task, which would be run immediately after my create-jar task. My entire obfuscate task is shown here:

<!-- ANT OBFUSCATE TASK -->  
<target name="obfuscate" depends="create-jar">
  <proguard
    allowaccessmodification="true"
    usemixedcaseclassnames="false"
    defaultpackage=""
    skipnonpubliclibraryclasses="false"
    printseeds="obfuscateseeds.txt"
    printusage="obfuscateusage.txt"
    printmapping="obfuscatemapping.txt">

    <!-- specify which jar files should be obfuscated -->
    <injar name="${jar.dir}/${jar-file-name}"/>
    <injar name="${jar.dir}/truexml.jar"/>
    <injar name="${jar.dir}/truelicense.jar"/>
    <injar name="${jar.dir}/trueswing.jar"/>

    <!-- java libraries my java application depends on -->
    <libraryjar name="${java.home}/../Classes/classes.jar"/>    <!-- rt.jar on other platforms -->
    <libraryjar name="${java.home}/../Classes/ui.jar"/>         <!-- ApplicationAdapter and Co. -->
    <libraryjar name="${java.home}/../Classes/jce.jar"/>        <!-- crypto stuff -->
    <libraryjar name="${jar.dir}/forms-1.0.7.jar"/>
    <libraryjar name="${jar.dir}/quaqua.jar"/>
    <libraryjar name="${jar.dir}/commons-codec-1.4.jar"/>

    <!-- the output jar file that should be created with the obfuscated java class files -->
    <outjar name="${jar.dir}/HydeApp.jar"/>

    <!-- don't obfuscate this method -->
    <keep name="com.devdaily.heidi.Hyde">
      <method name="main"/>
    </keep>
    
    <!-- this class gets serialized, and i don't want it messed with -->
    <keep name="com.devdaily.heidi.DCRuntime">
      <constructor/>
      <method name="get*"/>
      <method name="set*"/>
    </keep>

    <!-- this is a true license class that cannot be obfuscated -->
    <!-- have to keep this one to get this to work with obfuscation -->
    <keep name="de.schlichtherle.license.ftp.LicenseParam">
      <constructor/>
      <method name="*"/>
    </keep>

    <!-- more true license classes that must be left alone -->
    <keep name="de.schlichtherle.license.LicenseContent">
      <constructor/>
      <method name="get*"/>
      <method name="set*"/>
    </keep>
    <keep name="de.schlichtherle.xml.GenericCertificate">
      <constructor/>
      <method name="get*"/>
      <method name="set*"/>
    </keep>
  </proguard>
  
  <!-- delete the "injars" when obfuscation is complete -->
  <delete>
    <fileset dir="${jar.dir}">
      <include name="${jar-file-name}"/>
      <include name="truexml.jar"/>
      <include name="truelicense.jar"/>
      <include name="trueswing.jar"/>
    </fileset>
  </delete>
  
</target>

As you can see from the code, my Ant obfuscate task use the proguard Ant task to do its work. All I have to do is tell ProGuard which jar files to use as input, which jar files are dependencies for my application, and which classes or methods ProGuard should leave alone using the "keep" tag. In my case I had to tell ProGuard to leave a number of classes and methods alone because I used the TrueLicense library to license my Java application, and their documentation mentioned which classes and methods could not be obfuscated because they relied on reflection.

After this Ant obfuscate task is run, I'm left with a jar file given by the name in the outjar task, specifically HydeApp.jar. To verify that the obfuscation process worked properly, I opened this jar file and tried to decompile the Java class files in it, but indeed, they had been obfuscated properly.

Java obfuscation with ProGuard and Ant - summary

Unless there are any questions, I'll leave this article on how to obfuscate your Java class files with ProGuard as is for the time being. If you think it will be helpful to share my entire Ant build file here I'll be glad to do so, but I didn't want to complicate things too much.