- NEVER store UPI PIN, MPIN, or any authentication secret on device or server
- PIN exists in memory ONLY during the single transaction execution
- After use, PIN
CharArrayis immediately overwritten with zeros - 3 wrong PIN attempts → 24-hour lockout (matches UPI standard)
- ALWAYS use Android Keystore (hardware-backed / StrongBox) for all cryptographic keys
- Key algorithm: ECDSA P-256 (secp256r1/NIST P-256)
- Key storage: TEE (Trusted Execution Environment) or StrongBox (dedicated secure element)
- User authentication required for signing operations (biometric or device PIN)
- ALWAYS sign every transaction payload with ECDSA P-256 before transmission
- Canonical serialization:
payeeVpa|amountPaise|timestamp|nonce(hex) - Hash: SHA-256 of canonical string
- Signature: DER-encoded ECDSA signature
- ALWAYS include 8-byte cryptographically random nonce in every transaction
- ALWAYS check nonce registry before processing any cryptogram
- Nonce TTL: 24 hours (matching RBI offline payment window)
- ALWAYS validate timestamp within 5-minute window
- All sensitive data encrypted with AES-256-GCM
- Encryption key stored in Android Keystore (hardware-backed)
- EncryptedSharedPreferences for configuration data
- Room DB fields individually encrypted for payee data
- TLS 1.3 minimum for all network connections
- Certificate pinning for NPCI and bank API endpoints
- Binary SMS payload: signed with ECDSA before transmission
- DETECT SIM swap: if MSISDN changes, force re-KYC before allowing any transaction
- Store registered phone MSISDN in EncryptedSharedPreferences
- Compare against current SIM on every app launch
- Per-user: max 20 transactions/day (UPI standard)
- Per-SIM: max 5 attempts/minute (anti-fraud)
- Per-carrier: circuit breaker (5 failures → 2-minute cooldown)
- Non-customer calls blocked during peak hours 9am-9pm IST (NPCI OC-215A)
- NEVER log transaction amounts, VPAs, or user identifiers in plaintext
- Debug builds: raw USSD/SMS responses stored in local DB only
- Release builds: all sensitive fields redacted in logs
| Operation | Algorithm | Key Size | Storage |
|---|---|---|---|
| Transaction signing | ECDSA P-256 | 256-bit | Android Keystore (TEE/StrongBox) |
| Vault encryption | AES-256-GCM | 256-bit | Android Keystore |
| PIN block encryption | RSA-OAEP | 2048-bit (bank key) | Bank certificate (pinned) |
| Payload hashing | SHA-256 | 256-bit | N/A |
| Certificate pin | SHA-256 | 256-bit | Hardcoded in app |
┌─────────────────────────────────────────────────┐
│ Binary SMS Payload (120 bytes / 140 byte limit) │
├──────────┬──────┬───────────────────────────────┤
│ Field │ Size │ Security │
├──────────┼──────┼───────────────────────────────┤
│ Amount │ 8B │ Integrity via signature │
│ VPA │ 32B │ Integrity via signature │
│ Timestamp│ 8B │ Anti-replay (5-min window) │
│ Nonce │ 8B │ Anti-replay (24h uniqueness) │
│ Signature│ 64B │ ECDSA P-256 (R||S raw format) │
└──────────┴──────┴───────────────────────────────┘
| Threat | Mitigation |
|---|---|
| PIN interception | Hardware-backed input, never stored, zeroed after use |
| Man-in-the-middle | TLS 1.3 + certificate pinning |
| Replay attack | Nonce registry + timestamp window |
| SIM swap fraud | MSISDN change detection + mandatory re-KYC |
| Brute force PIN | 3 attempts → 24h lockout |
| Local data theft | AES-256-GCM encryption, Keystore-backed keys |
| USSD interception | Transaction-level ECDSA signatures |
| DDoS on UPI switch | Rate limiting per OC-215A |