Hardened runtime
Hardened runtime
Class encryption and per-slot jars, available on request with a hardened JVM.
The hardened runtime goes further than obfuscation: the classes of your jar are encrypted and only a dedicated JVM can load them. It is a premium option, available on request, and comes with that JVM.
It has two parts: class encryption with magicCrypter, and per-slot jars that give each build its own keys.
Class encryption
With magicCrypter on, every class of the output jar is compressed with zlib and encrypted with AES-128-CTR, with a random IV per class. The class file no longer starts with CAFEBABE but with the PLRG magic, and carries an HMAC-SHA256 tag over the IV and the ciphertext.
{
"options": {
"profile": "High",
"magicCrypter": true
}
} - A standard JVM cannot load these classes. The hardened JVM supplied with the option, PLR-JAVA-25, verifies the tag and decrypts each class as it loads.
- The keys are not stored in the JVM or in the jar. Without the keys of its build, a class fails to load with a
ClassFormatError. - Obfuscation still applies underneath: a class that is somehow decrypted is still protected by every other transformer you enabled.
Per-slot jars
A slot is one copy of your jar encrypted with its own keys. Producing several slots from one build lets you hand different users differently keyed jars, and rotate keys at every release.
With the Gradle plugin, set slotCount, up to 100:
plrObfuscator {
inputJar = tasks.named<Jar>("jar").flatMap { it.archiveFile }
configFile = file("obfuscator-config.json")
slotCount = 100
} ./gradlew plrObfuscate then writes client_0.jar to client_99.jar in build/plr-obfuscated, all slots processed in parallel.
- Every run draws fresh random seeds, one per slot, and derives each slot’s AES and HMAC keys from its seed with HKDF. Seeds are never stored, so every build rotates the keys.
- The task also writes
keys-manifest.json, which lists the derived keys of every slot for your delivery pipeline. Treat it as a secret and keep it out of the published artifacts.
The CLI offers the same mode with -multislot <count> -outputdir <dir> -keysoutput <keys.json>, reading one hex seed per slot from the PLR_SLOT_SEED_0 to PLR_SLOT_SEED_<count-1> environment variables. A single-slot run with magicCrypter reads its keys, in hex, from PLR_SLOT_AES_KEY and PLR_SLOT_HMAC_KEY.
Getting the option
The hardened runtime is set up with you: the JVM, the key delivery and the rollout depend on how you distribute your application. Contact us to discuss it.