API Docs
Jexk Encrypt juga menyediakan REST API untuk enkripsi secara programatik. UI web mengenkripsi sepenuhnya di sisi klien; API menjalankan operasi AES-256-GCM yang sama di sisi server tanpa menyimpan file maupun password.
/api/encryptEncrypt a file
Kirim file dan password sebagai multipart/form-data. Mengembalikan container .enc terenkripsi sebagai unduhan biner.
curl -X POST https://your-app.vercel.app/api/encrypt \
-F "file=@document.pdf" \
-F "password=my-secret-password" \
-o document.pdf.enc200application/octet-stream — the .enc file400Missing file or password413File exceeds the 100 MB limit/api/decryptDecrypt a file
Kirim container .enc beserta password-nya sebagai multipart/form-data. Mengembalikan file asli dengan nama file aslinya.
curl -X POST https://your-app.vercel.app/api/decrypt \
-F "file=@document.pdf.enc" \
-F "password=my-secret-password" \
-o document.pdf200application/octet-stream — the original file400Invalid container or missing fields401Wrong password or corrupted file/api/deobfuscateRestore obfuscated JavaScript
Kirim file .js/.mjs/.cjs atau .zip sebagai multipart/form-data. Merespons dengan stream NDJSON berisi progres; baris terakhir memuat hasilnya (restored.js atau project-restored.zip) dalam base64 beserta laporan deteksi per file. Kode yang diunggah tidak pernah diserahkan ke mesin JavaScript (tanpa eval/Function/VM); decoder yang tidak dikenali dievaluasi di interpreter terbatas tanpa akses host. Endpoint ini dibatasi 4 MB karena batas body serverless; UI web menjalankan pipeline yang sama di browser lewat Web Worker sehingga tidak ada batas unggah.
curl -N -X POST https://your-app.vercel.app/api/deobfuscate \
-F "file=@bundle.obfuscated.js"
# {"stage":"uploading","label":"Uploading...","percent":4}
# {"stage":"detecting","label":"Detecting obfuscator...","percent":15}
# {"stage":"done","kind":"file","outputName":"restored.js",
# "stats":{...},"reports":[...],"payloadBase64":"..."}200application/x-ndjson — progress stream + result400Missing file, empty upload, or unsupported extension413Upload exceeds the 4 MB API limit — use the browser UI instead/api/healthHealth check
Mengembalikan status layanan. Berguna untuk pemantauan uptime.
curl https://your-app.vercel.app/api/health200{"status":"ok","service":"jexk-encrypt",...}Universal Deobfuscator pipeline
Setiap file melewati 16 langkah berikut, semuanya lewat transformasi AST. Kode yang diunggah tidak pernah diserahkan ke mesin JavaScript — tidak ada eval(), Function, maupun VM. Untuk skema yang tidak dikenali, fungsi decoder-nya dievaluasi di interpreter terbatas tanpa akses host.
1 detect obfuscation style 9 remove fake branches
2 parse AST using Babel 10 simplify expressions
3 beautify formatting 11 inline constants
4 rename generated variables 12 merge split strings
5 decode string arrays 13 remove wrapper functions
6 decode hexadecimal strings 14 remove unused variables
7 decode unicode escapes 15 restore indentation
8 remove dead code 16 generate readable JavaScript
Bundles -> each module factory is lifted out of the bundler's
argument list into a named top-level function the array
points at, with its entry point and dependencies in a
comment. The runtime is kept and marked as skippable
Dead code -> a switch on a constant keeps one run of arms; a loop with
a false test keeps only its initialiser; empty try/catch
goes. A bare identifier is kept unless it resolves to a
binding, and a member read is always kept (getters)
Function names -> scored from the APIs the body calls: strong evidence gives
the specific name (encryptData, parseJson, sendRequest),
weaker evidence the category's neutral name, and little
evidence no name at all. Parameters follow the position
they are passed in. Skipped entirely if the file uses eval
Objects -> a literal plus a run of obj.k = v folds back into one
literal; functions in it are written as methods, unless a
use constructs the property; the object is named after
what it carries (get/post/put -> httpClient)
Classes -> constructor function + prototype assignments become a
class, unless the name is ever called without "new", used
before its declaration, or given an arrow as a method
Flattened flow -> a dispatcher whose order is written down is read off the
list; one whose order is computed is read as a control-flow
graph and rebuilt into if/else at its post-dominators.
Loops in the graph are left flattened rather than guessed
Whole file first -> one parse, one walk, a graph of every binding, reference
and write, keyed by source offset. Chunks then rewrite
with that graph in hand, so a name declared in one part
and read from another is renamed at both ends
Local wrappers -> constant lookup tables are folded so the call sites have
literal arguments again, then each function's private
forwarder is evaluated in place and removed. Forwarders
chain — a method's calls its function's, which calls the
module's — so each is resolved through its own binding
until it reaches the decoder
Runtime checks -> a branch that asks about the environment — window chrome
width, a clock either side of nothing, a function's own
source, who called it — and answers by not continuing is
removed whole. Both halves are required: programs measure
time and programs have loops, but nothing legitimate
answers a question about the environment by refusing to
run. A debugger built at run time becomes a function that
does nothing, so whatever holds it still works. A console
method replaced by an empty one is silencing and goes; one
replaced by a method with a body is routing and stays
Self-defending -> the traps test a regex against the program's own source,
so reformatting sets them off: an endless loop, or a call
with no base case. They are recognised by the patterns they
carry, and the statement that arms one is removed only when
its body never reaches for anything the program declared —
dead-code injection copies a trap into real functions, and
deleting a real call is worse than leaving a dead one
Rotation -> the table's order is recovered against the obfuscator's own
checksum, or the strings are left encoded. A rotation that
is half applied still yields real strings, from the wrong
positions, which nothing downstream could notice. The calls
inside the loop are never rewritten: they are what the loop
measures the table against, so answering one freezes the
comparison and the table stops rotating at run time
Two modes -> "safe" undoes encodings and nothing else: decoding, the
wrappers that only ever hid a value, and protection that
was proven to be protection. It renames nothing, folds
nothing and moves no statement. Protection is removed in
both, which is not an exception — reprinting the file is
what a self-defending check exists to notice, so leaving
one in is what would make the mode unsafe. "aggressive" is
the default and does everything above
Unknown scheme -> the decoder is interpreted instead of pattern-matched,
on an interpreter with no host objects, no I/O, a step
budget and allocation caps. This covers schemes that hide
the real decoder behind thousands of thin forwarding
functions, and string tables the file rotates at startup
Parser fails -> recovery mode (Babel errorRecovery)
Recovery fails -> partially beautified source, never an empty response
Pass goes wrong -> output that no longer parses, or that a pass emptied, is
discarded in favour of a beautified copy of the original
Where it runs
Web UI -> a Web Worker on your machine; the file is never uploaded and
there is no size limit beyond the device's memory
REST API -> the server, capped at 4 MB by the serverless body limit
Analysis costs roughly 500 MB of memory per MB of obfuscated source, so size
decides how the work is arranged, never which passes run. Past what the device
can hold at once, the same passes repeat fewer times; past that again, the file
is cut at statement boundaries and restored part by part.
Every part gets the whole pipeline. The decoder, the wrappers that chain to it
and the self-defending names are resolved once up front and shared, so a call
site in one part follows a wrapper declared in another. Only the statements
that read their own source are copied out byte for byte, found by asking each
one rather than by preserving a window around a guess. A pass that does not run
is named in the report along with the reason — a statistic reading zero is
never left to stand for an explanation.Container format (.enc)
File yang dihasilkan UI dan API memakai format yang sama dan dapat saling dipertukarkan.
bytes 0..3 magic "JEXK"
byte 4 container version (1)
bytes 5..8 uint32 BE metadata JSON length
... metadata JSON { name, ext, size, salt, iv, v }
... AES-256-GCM ciphertext + 16-byte auth tag
Key derivation: PBKDF2-SHA256, 250,000 iterations, 16-byte salt
IV: 12 random bytes per file. The password is never stored.