Files
thijooree/docs/mibapi/02-login.md
Shihaam Abdul Rahman 256f216da4
All checks were successful
Auto Tag on Version Change / check-version (push) Successful in 4s
update docs
2026-05-23 23:46:00 +05:00

7.1 KiB
Raw Blame History

Login Flow

MIB uses a two-phase authentication model:

Phase Trigger Key used
Device Registration First time this device+account pair is seen DEFAULT_KEY → DH session key
Regular Login Every subsequent login (stored key1/key2) key1 → DH session key

Password Hashing (pgf03)

The password is never sent in plaintext. Required by both C41 (registration) and A41 (login).

pgf03 = SHA256( clientSalt + SHA256( userSalt + SHA256( password ) ) )

All SHA-256 values are uppercase hex strings. clientSalt is a fresh random 32-character alphanumeric string each time.

import hashlib

def compute_pgf03(password: str, user_salt: str, client_salt: str) -> str:
    h1 = hashlib.sha256(password.encode()).hexdigest().upper()
    h2 = hashlib.sha256((user_salt + h1).encode()).hexdigest().upper()
    return hashlib.sha256((client_salt + h2).encode()).hexdigest().upper()

Device Registration Flow (first time only)

[0] sfunc=r  DEFAULT_KEY  →  DH exchange  →  derive session_key_1, get xxid + nonceGenerator
[1] sfunc=n  A44          →  get userSalt
[2] sfunc=n  C41          →  submit credentials  →  returns key1, key2 (persist!)
[3] sfunc=n  C42          →  verify OTP
[48] regular login (below) using the key1/key2 just received

Regular Login Flow

[0] sfunc=i  key1         →  DH exchange  →  derive session_key_2, get xxid + nonceGenerator
[1] sfunc=n  A44          →  get userSalt
[2] sfunc=n  A41          →  submit credentials  →  returns otpTypes, email, uuid
[3] sfunc=n  P41          →  fetch profile image (optional)
[4] sfunc=n  A42          →  verify OTP  →  session established
[5] sfunc=n  P47          →  select profile  →  returns accountBalance array

Step-by-Step Reference

[0] Initial Key Exchange — sfunc=r

Key: DEFAULT_KEY = 8M3L9SBF1AC4FRE56788M3L9SBF1AC4FRE5678

Request (outer + inner are encrypted together):

{
  "sfunc": "r",
  "data": {
    "cmod": "<G^A mod P as decimal string>",
    "appId": "IOS17.2-<15 random alphanumeric chars>",
    "routePath": "S40",
    "sodium": "<random 20-bit int as string>",
    "xxid": "<random 40-bit int as string>"
  }
}

Response (decrypted with DEFAULT_KEY):

{
  "success": true,
  "reasonCode": "201",
  "reasonText": "Key generated successfully.",
  "smod": "<server DH public key as decimal string>",
  "nonceGenerator": "<instruction string>",
  "xxid": "<session token — use for all subsequent calls>",
  "sodium": "<server random>",
  "encMethod": 2
}

After: session_key = derive_session_key(int(smod)). Save xxid and nonceGenerator.


[1] Get Auth Type — sfunc=n, routePath: A44

Key: session key

Request:

{
  "sfunc": "n",
  "xxid": "<session xxid>",
  "data": {
    "uname": "<username>",
    "nonce": "<computed nonce>",
    "appId": "<appId>",
    "sodium": "<random>",
    "routePath": "A44",
    "xxid": "<session xxid>"
  }
}

Response:

{
  "success": true,
  "data": [{ "loginType": "1", "userSalt": "<server salt>" }]
}

Use userSalt in pgf03 computation.


[2a] Device Registration Init — sfunc=n, routePath: C41

First-time only.

Request:

{
  "sfunc": "n",
  "xxid": "<session xxid>",
  "data": {
    "uname": "<username>",
    "pgf03": "<computed>",
    "clientSalt": "<random 32-char string>",
    "nonce": "<nonce>",
    "appId": "<appId>",
    "sodium": "<random>",
    "routePath": "C41",
    "xxid": "<session xxid>"
  }
}

Response:

{
  "success": true,
  "reasonCode": "201",
  "primaryOTPType": "3",
  "otpTypes": [2, 3],
  "fullName": "<user full name>",
  "customerImgHash": "<hash>"
}

[3a] OTP Verification (Registration) — sfunc=n, routePath: C42

First-time only. Receive and persist key1/key2.

Request:

{
  "sfunc": "n",
  "xxid": "<session xxid>",
  "data": {
    "otp": "<6-digit OTP>",
    "uname": "<username>",
    "otpType": "3",
    "nonce": "<nonce>",
    "appId": "<appId>",
    "sodium": "<random>",
    "routePath": "C42",
    "xxid": "<session xxid>"
  }
}

Response:

{
  "success": true,
  "reasonCode": "101",
  "data": [{
    "key1": "<store securely — Blowfish key for next sfunc=i>",
    "key2": "<store securely — sent plaintext in sfunc=i wrapper>",
    "appId": "<appId>",
    "encryptionMethod": "2"
  }]
}

key1 and key2 are long-lived device credentials. Store them securely on the device.


[0b] Authenticated Key Exchange — sfunc=i

Regular login. key2 is a separate unencrypted outer field.

Key: key1

Form body: key2=<key2>&sfunc=i&data=<encrypted payload>

Encrypted payload:

{
  "sfunc": "i",
  "key2": "<key2>",
  "data": {
    "cmod": "<G^A mod P>",
    "appId": "<appId>",
    "routePath": "S40",
    "sodium": "<random 20-bit int>",
    "xxid": "<random 40-bit int>"
  }
}

Response (decrypted with key1):

{
  "success": true,
  "smod": "<new server DH public key>",
  "nonceGenerator": "<new instruction string>",
  "xxid": "<new session token>",
  "encMethod": 2
}

After: derive new session key, replace xxid and nonceGenerator.


[2b] Regular Login Init — sfunc=n, routePath: A41

Key: session key

Request:

{
  "sfunc": "n",
  "xxid": "<session xxid>",
  "data": {
    "uname": "<username>",
    "pgf03": "<computed>",
    "clientSalt": "<random 32-char>",
    "pmodTime": 0,
    "requireBankData": 1,
    "nonce": "<nonce>",
    "appId": "<appId>",
    "sodium": "<random>",
    "routePath": "A41",
    "xxid": "<session xxid>"
  }
}

Response:

{
  "success": true,
  "reasonCode": "104",
  "primaryOTPType": "3",
  "otpTypes": [2, 3],
  "email": "<masked email>",
  "uuid": "<uuid1>",
  "uuid2": "<uuid2>"
}

[3b] Get Profile Image — sfunc=n, routePath: P41

Optional. Fetch the user's avatar to display on the OTP screen.

Request:

{
  "sfunc": "n",
  "xxid": "<session xxid>",
  "data": {
    "imageHash": "<customerImgHash from C41/A41>",
    "nonce": "<nonce>",
    "appId": "<appId>",
    "sodium": "<random>",
    "routePath": "P41",
    "xxid": "<session xxid>"
  }
}

Response:

{
  "success": true,
  "reasonCode": "201",
  "profileImage": "<base64-encoded JPEG>"
}

[4b] OTP Verification (Login) — sfunc=n, routePath: A42

Request:

{
  "sfunc": "n",
  "xxid": "<session xxid>",
  "data": {
    "otp": "<6-digit OTP>",
    "uname": "<username>",
    "otpType": "3",
    "nonce": "<nonce>",
    "appId": "<appId>",
    "sodium": "<random>",
    "routePath": "A42",
    "xxid": "<session xxid>"
  }
}

After successful A42, the xxid and nonceGenerator from the sfunc=i response become the WebView session cookies. See README for the cookie format.


[5] Select Profile — sfunc=n, routePath: P47

See 03-accounts.md for the full P47 reference.


 


← Encryption     Next → Accounts