One shared secret
The app and the server keep the same key. Reproduce the digest and you reproduce the signature. The key and the canonical order are the whole problem.
Capabilities · Request signing
The app builds a signature for every call. Copying a request copies one signature from one moment. A working reproduction computes a fresh signature for the moment you send.
POST /v2/account HTTP/2 X-Timestamp: 1738307384 X-Nonce: 6c1b9e7f2a3d41c0 X-Signature: 3b2e...b91a {"account":"ABC123"}
Where signing lives
Signed requests often pass through one code path. Find the Interceptor and the signing call is usually one hop away.
If the signer is a JNI method, the algorithm lives in a .so and moves into disassembly.
The key may be static, derived, or fetched. Each changes how you reproduce it.
The signed input
The signature is the result of a function. Rebuilding it means knowing both the function and the exact bytes it takes in.
A canonical string is a fixed order of those parts. If you get the order wrong, the signature does not match even when you use the right key.
The algorithm
The app and the server keep the same key. Reproduce the digest and you reproduce the signature. The key and the canonical order are the whole problem.
The server only has the public half. Reproducing the signature requires the private key the app holds, which makes key recovery the deciding question.
How we read it
Disassemble the application and locate the request path and the interceptor that attaches the signature.
Reconstruct the exact order and encoding of method, path, body, timestamp and nonce.
If the signer is a JNI method, open the .so in a disassembler and map the native flow back to the request.
Find the key, or the derivation that produces it, so the signature can be produced outside the app.
The signature is a function of the request and a key. Recreate the function and the request stops being a replay.
Reproduce it
# rebuild the signature, not replay it import hashlib, hmac, time, secrets, requests KEY = bytes.fromhex("9f2c...") def sign(method, path, body, ts, nonce): text = "\n".join([method, path, body, ts, nonce]) return hmac.new(KEY, text.encode(), hashlib.sha256).hexdigest() ts = str(int(time.time())) nonce = secrets.token_hex(8) body = '{"account":"ABC123"}' requests.post( base + "/v2/account", data=body, headers={"X-Timestamp": ts, "X-Nonce": nonce, "X-Signature": sign("POST", "/v2/account", body, ts, nonce)}, )
Fig. 01 · the same function the app runs, outside the app
// runs before every request in the collection const ts = Math.floor(Date.now() / 1000).toString(); const nonce = CryptoJS.lib.WordArray.random(8).toString(); const text = ["POST", "/v2/account", pm.variables.get("body"), ts, nonce].join("\n"); pm.variables.set("ts", ts); pm.variables.set("nonce", nonce); pm.variables.set("signature", CryptoJS.HmacSHA256(text, KEY).toString());
Fig. 02 · the same signature regenerated per request in Postman
Send us the app
We read the signing code off the application and hand you a working signature in Python, TypeScript or Postman.
Projects start at $120. Most are delivered in 24 to 72 hours.
Python, JavaScript/TypeScript, Postman and complete API documentation cover the same full endpoint set. Your team runs the clients in its own server or system.
The delivery window starts after we receive the APK and any account access needed to run it. The fixed quote states the deadline. Most projects finish sooner.
The package includes signing, encryption, decryption and session handling. We verify device-bound keys and server integrity checks during review and document runtime requirements before you commit.
Report a defect within 30 days of delivery. We fix any delivered call that does not match the tested APK at no extra cost.