Overview
Currently the integration requires tokens captured via a proxy tool. It would be better UX to support direct email/password login so users don't need a proxy setup.
What we know
The login endpoint is:
POST https://m.iov.changanauto.sg/appgw/intl-app-auth/api/login/email-pass-in
The request body contains:
email — RSA encrypted
password — RSA encrypted
pubKey — the public key used for encryption (sent as a reference)
salesCountry — country code e.g. AU
The selectCountry header must NOT be present on this request (unlike all other endpoints).
The problem
The pubKey field sent in the request is a 1024-bit RSA key, but the actual encryption of the credentials produces 344-character output, consistent with a 2048-bit RSA key. This means:
- The
pubKey in the request body is just an identifier/reference sent to the server
- The actual encryption key used is a different, larger 2048-bit key hardcoded in the app binary
- Our encryption using the visible
pubKey produces 172-character output which the server rejects with APP_1_1_02_001
Investigation
- The Android APK was inspected — encryption is handled by a native library (
libijmDataEncryption.so) via com.ijm.dataencryption.DETool
- The 2048-bit key is not stored as a plain string in the binary — it appears to be obfuscated within the native library
- Replaying captured encrypted values from a real app login works correctly, confirming the endpoint and all headers are correct
- The only missing piece is the actual 2048-bit encryption key
Possible solutions
- Extract the key via Frida — hook
DETool.encrypt() at runtime on a rooted Android device or emulator to intercept the key material
- Reverse engineer the native library — disassemble
libijmDataEncryption_arm64.so to find the key
- Wait for community contribution — someone with reverse engineering experience may be able to extract the key
Current workaround
Token mode works well. Tokens are automatically refreshed and last ~90 days via the refresh token. When tokens expire a repair notification prompts the user to paste fresh tokens.
The other issue is a user can only be logged in on one device at a time - logging in with your username/password in Home Assistant would likely log you out of your phone if you're already logged in there.
Tokens works fine as a workaround so you can be logged in on both your phone and Home Assistant with the same account.
Overview
Currently the integration requires tokens captured via a proxy tool. It would be better UX to support direct email/password login so users don't need a proxy setup.
What we know
The login endpoint is:
POST https://m.iov.changanauto.sg/appgw/intl-app-auth/api/login/email-pass-inThe request body contains:
email— RSA encryptedpassword— RSA encryptedpubKey— the public key used for encryption (sent as a reference)salesCountry— country code e.g.AUThe
selectCountryheader must NOT be present on this request (unlike all other endpoints).The problem
The
pubKeyfield sent in the request is a 1024-bit RSA key, but the actual encryption of the credentials produces 344-character output, consistent with a 2048-bit RSA key. This means:pubKeyin the request body is just an identifier/reference sent to the serverpubKeyproduces 172-character output which the server rejects withAPP_1_1_02_001Investigation
libijmDataEncryption.so) viacom.ijm.dataencryption.DEToolPossible solutions
DETool.encrypt()at runtime on a rooted Android device or emulator to intercept the key materiallibijmDataEncryption_arm64.soto find the keyCurrent workaround
Token mode works well. Tokens are automatically refreshed and last ~90 days via the refresh token. When tokens expire a repair notification prompts the user to paste fresh tokens.
The other issue is a user can only be logged in on one device at a time - logging in with your username/password in Home Assistant would likely log you out of your phone if you're already logged in there.
Tokens works fine as a workaround so you can be logged in on both your phone and Home Assistant with the same account.