Jexk Encrypt

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.

POST/api/encrypt

Encrypt 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.enc
200application/octet-stream — the .enc file
400Missing file or password
413File exceeds the 100 MB limit
POST/api/decrypt

Decrypt 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.pdf
200application/octet-stream — the original file
400Invalid container or missing fields
401Wrong password or corrupted file
POST/api/deobfuscate

Restore 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 + result
400Missing file, empty upload, or unsupported extension
413Upload exceeds the 4 MB API limit — use the browser UI instead
GET/api/health

Health check

Mengembalikan status layanan. Berguna untuk pemantauan uptime.

curl https://your-app.vercel.app/api/health
200{"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.