A MAC value needs a construction
A hash-based message authentication code is a keyed digest over a byte string. Three things decide the output: the key, the message the routine authenticates, and the encoding applied to the digest. Recovering the key alone leaves you unable to compute a value the server accepts, because the signed string is assembled by app code that concatenates fields in an order you have to establish.
That order is where most of the work sits. A signature routine hashes a string built from method, path, query, body, a timestamp, a nonce and possibly a subset of headers, joined with a separator that might be a newline, an ampersand or nothing at all. Concatenation is cheap for the app and unforgiving for an outside client, because one missing field or one different separator changes the digest completely.
Confirm the scheme before you chase the key
Establish the family first, since it decides where to look next.
- Compare digest lengths against the common algorithms. An MD5 based MAC produces sixteen raw bytes, SHA-1 produces twenty, and the SHA-2 family produces thirty-two or more, so the length of the value on the wire narrows the candidates before you read any code.
- Check whether the value is stable for identical inputs. A MAC of a fixed string is deterministic, while a value that changes for the same body and path points at a nonce, a timestamp or an asymmetric signature.
- Look at how the value is carried. A hex string, a base64 string and a URL-safe variant each imply a different transformation after the digest, and the transformation has to be reproduced exactly.
- Test whether the server verifies with a public key by altering the signature to a same-length value. If the request reaches deeper validation rather than failing on the signature, the check is not a keyed MAC.
Recover the key and the message
The key material sits in one of a few places. It can be a constant in Java or Kotlin, a byte array in a native library, a value derived from the APK signing certificate, or a per-install secret fetched from the server at startup. A key delivered at run time is the interesting case, because a client that hardcodes it will fail against another install or another build.
Recovering the message is a reconstruction problem, and it is easiest when you start from the signing routine rather than from the capture. Find where the request values are read into the helper, note the order in which they are appended, and note whether an intermediate step lowercases the path, sorts parameters or removes a header before hashing. When the code is obfuscated, hook the hashing function under a debugger and print its input, which gives you the exact bytes the server also computes over.
Treat every difference as fatal while you are matching digests. A signature over the body means that changing one field of a JSON payload requires recomputing the value, and a signing routine that includes a header you did not notice produces a mismatch that looks like a wrong key. Match against captures you can send again so the comparison is meaningful, and keep a written record of the exact string for each endpoint, because APIs that sign several route families often build the string differently for each one.
Reproduce it and prove it
Build the candidate string outside the app and compare digests for a request you can send twice. A working match confirms the key, the message layout and the encoding together. A near miss usually means one field is included that you ignored, or that a query string is being re-encoded before it is signed, so test the captured raw text rather than a normalised form.
Once the digest matches, the remaining work is the runtime state around it: generating the timestamp the routine expects, obtaining the nonce from the same source the app uses, and refreshing a server-delivered key when the session changes. A signature scheme recovered without that state produces values that are correct and briefly valid, which fails in production rather than in testing.
Related work
Reviewed 28 September 2026 · SReverse research desk