Browse documentation
Documentation / Protection passes / Resource & asset encryption

Resource & asset encryption

ConditionalBundled resource files referenced by a literal path are transparently encrypted and decrypted at the call site.

What it does

Every Class#getResourceAsStream and ClassLoader#getResourceAsStream call site is redirected through a runtime loader that decrypts a resource only if it was encrypted at protect time. Otherwise the loader passes the stream through, so rewriting every call site is always safe. A resource is only encrypted where a literal, statically resolvable path argument ties it to a call site inside the set of classes being protected, and its exact path never appears among classes outside that set. Matched resources reuse the same manifest-plus-obfuscated-blob scheme as native library bundling.

Scope and boundaries

Only the InputStream-returning getResourceAsStream overload is covered. The URL-returning getResource(String) form is not, since producing a working URL for encrypted content would need a custom URLStreamHandler. A Class-relative literal with no leading / is never resolved, since that would need runtime knowledge of which Class instance the receiver is. Its call site is still redirected, but the resource is never encrypted. A small, fixed set of files a surrounding framework reads by convention regardless of what your bytecode does (a manifest file, common framework metadata files, RJNI's own runtime namespace) is never touched.

Threat model

Raises the bar against extracting a bundled resource by unzipping the jar and reading a file. It doesn't resist an attacker who finds the redirect logic and reimplements the reversal, the same as every obfuscation pass in this pipeline that has no secret key.

Verified. A class reading an embedded resource was run through the full pipeline and loaded via an isolated class loader. The plaintext resource entry is gone from the output jar, and invoking the method returns the original content, byte for byte.