# MIB Faisanet API Reverse-engineered from `mv.com.mib.faisamobilex` (Faisanet Mobile Banking, React Native / Hermes bytecode v96). [Play Store](https://play.google.com/store/apps/details?id=mv.com.mib.faisamobilex) --- ## Architecture MIB uses **two completely separate backends**: | Backend | Base URL | Auth | Used for | |---|---|---|---| | Encrypted API | `https://faisanet.mib.com.mv/faisamobilex_smvc/` | Blowfish + DH session key | Login, key exchange | | WebView host | `https://faisamobilex-wv.mib.com.mv` | Session cookies | Accounts, history, transfers, contacts, cards, financing | --- ## Encrypted API All calls to the encrypted API are `POST /` with `Content-Type: application/x-www-form-urlencoded; charset=utf-8` and form body: ``` sfunc=&data= ``` The request JSON is encrypted with Blowfish (ECB, PKCS5) before sending. The response body is also base64-encoded Blowfish ciphertext. Two keys are used: | Phase | Key | |---|---| | `sfunc=r` (initial key exchange) | `DEFAULT_KEY` (hardcoded in app) | | All subsequent requests | DH-derived session key | See [01-encryption.md](01-encryption.md) for full details. --- ## WebView Session Auth After login, all data endpoints use cookie-based auth on `faisamobilex-wv.mib.com.mv`: ``` Cookie: mbmodel=IOS-1.0; xxid=; IBSID=; mbnonce=; time-tracker=597 ``` These values come from the login flow — `xxid` and `nonceGenerator` from the DH key exchange response. **Cookie notes:** - `time-tracker=597` is a **hardcoded constant** in the client. Every WebView client (transfers, contacts, cards, activity, etc.) sends the literal value `597` — it is not computed or rotated. - `mbnonce` is the **unmodified `nonceGenerator` string** from the key-exchange response. It does **not** carry a freshly-computed per-request nonce. The actual per-request nonce (derived via the algorithm in [01-encryption.md](01-encryption.md)) only appears inside the encrypted payloads of `sfunc=n` calls on the encrypted API — WebView endpoints have no nonce field. ### WebView AJAX Headers All AJAX `POST` calls also require: ``` X-Requested-With: XMLHttpRequest Accept: */* Origin: https://faisamobilex-wv.mib.com.mv Content-Type: application/x-www-form-urlencoded; charset=UTF-8 ``` The `Referer` value varies per endpoint (documented per endpoint). A few endpoints (notably activity history, [10-activity-history.md](10-activity-history.md)) omit both `Referer` and `Origin`. --- ## Session Expiry Detection A MIB session is considered expired when **either** condition is met (`MibLoginFlow.kt:248-274`): | Signal | Source | |---|---| | HTTP **`419`** status | Encrypted API or any WebView endpoint | | JSON `reasonCode == "505"` in a decrypted response body | Encrypted API | On detection the client auto-recovers by re-running the login flow using stored credentials, refreshes `xxid` + `nonceGenerator` in the in-flight payload, and retries the original request once. Callers receive the retried response transparently. If the recovery itself hits expiry again it surfaces a `SessionExpiredException`. ### WebView User-Agent ``` Mozilla/5.0 (Linux; Android {version}; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.70 Mobile Safari/537.36 ``` --- ## Documents | # | File | Description | |---|---|---| | 1 | [01-encryption.md](01-encryption.md) | Blowfish encryption, DH key exchange, nonce computation | | 2 | [02-login.md](02-login.md) | Device registration and regular login flows | | 3 | [03-accounts.md](03-accounts.md) | Select profile, account balances | | 4 | [04-history.md](04-history.md) | Transaction history | | 5 | [05-cards.md](05-cards.md) | Debit card list | | 6 | [06-financing.md](06-financing.md) | Financing deals | | 7 | [07-profile.md](07-profile.md) | Personal profile (HTML scrape) | | 8 | [08-transfer.md](08-transfer.md) | Account lookup and fund transfer | | 9 | [09-contacts.md](09-contacts.md) | Beneficiary management | | 10 | [10-activity-history.md](10-activity-history.md) | Activity / audit log | --- **Start here →** [01-encryption.md](01-encryption.md)