Overview
FinProServer supports end-to-end encryption on API payloads. When enabled, request bodies must be encrypted before sending, and responses are returned encrypted — protecting sensitive financial data in transit. The encryption scheme uses two layers working together: a symmetric cipher (AES-256-GCM) to encrypt the payload efficiently, and an asymmetric cipher (RSA-OAEP) to securely exchange the symmetric key with the server. The encrypted key bundle sent in each request is called the KEK (Key Encryption Key) — a fresh one is generated per request.Encryption Architecture
Two layers work together on every request:Layer 1 — RSA (Key Exchange)
- Algorithm: RSA-OAEP (SHA-1 hash, 2048/4096-bit key)
- Encrypts:
"key:iv"UTF-8 string - Sent in: Request Header →
kek
Layer 2 — AES (Payload Encryption)
- Algorithm: AES-256-GCM
- Key: 32 bytes · IV: 12 bytes
- Encrypts: JSON request body
- Sent in: Request Body →
RequestEncryptedValue
Step-by-Step Encryption Process
Perform these 8 steps for every API request:Generate Random AES Key
Generate a cryptographically secure random key:
- Length: 32 bytes (256 bits)
- Format: Printable ASCII characters recommended (alphanumeric, no colon)
- Generate fresh for every request
Generate Random IV
Generate a cryptographically secure random IV:
- Length: 12 bytes (96 bits) — required for AES-GCM
- Format: Printable ASCII characters (alphanumeric, no colon)
- Must be unique per request
Encrypt Payload with AES-256-GCM
Encrypt your JSON string:Process:
- Encrypt JSON with AES-256-GCM → produces ciphertext + 16-byte auth tag
- Base64-encode ciphertext:
ct_b64 = base64(ciphertext) - Base64-encode auth tag:
tag_b64 = base64(auth_tag)— always 24 characters - Concatenate:
encrypted_payload = ct_b64 + tag_b64
Combine Key + IV
Create a single plain UTF-8 string with key and IV separated by a colon:32 ASCII chars +
: + 12 ASCII chars = 45 characters total.Request Format
Complete Example
Header Reference
| Header | Required | Description |
|---|---|---|
kek | Yes | Base64 string of RSA-encrypted "key:iv" UTF-8 bytes |
appIdentifier | Yes | Your application identifier, provided during registration |
Content-Type | Yes | Must be application/json |
Body Reference
| Field | Description |
|---|---|
RequestEncryptedValue | base64(ciphertext) + base64(auth_tag) concatenated — no IV prefix in body |
Response Decryption
The server responds with an encrypted payload in the same format:Decryption Flow
Split the payload
Extract the last 24 characters →
base64(auth_tag). Everything before = base64(ciphertext).Decrypt with AES-256-GCM
Use the same Key and IV from your original request. GCM verifies the auth tag automatically.
Key points for response decryption:
- Reuse the same Key and IV you generated for the request — store them after Steps 2 & 3
- The response format is identical to the request:
base64(ciphertext) + base64(auth_tag)— no IV in the payload - Auth tag is always the last 24 characters (base64-encoded 16-byte GCM tag)
Prerequisites
Application Registration
Contact FinProServer administrators to register your application. You will receive:| Item | Description | Example |
|---|---|---|
| Server Public Key | RSA public key in PEM format — used to encrypt your AES key + IV | Shared by FinPro support over a secure channel |
| App Identifier | Unique string identifying your application | com.example.myapp |
- Generate cryptographically secure random bytes (for AES key and IV)
- AES-256-GCM encryption and decryption
- RSA-OAEP encryption (asymmetric)
- Base64 encoding and decoding
- HTTP requests with custom headers
| Platform | Library |
|---|---|
| Node.js | Built-in crypto module |
| Python | cryptography or pycryptodome |
| Java | javax.crypto |
| Browser (JS) | Web Crypto API (window.crypto.subtle) |
Algorithm Summary
| Data | Algorithm | Purpose | Transmitted In |
|---|---|---|---|
| AES Key + IV | RSA-OAEP (SHA-1) | Secure key exchange | Header: kek |
| JSON Request | AES-256-GCM | Authenticated payload encryption | Body: RequestEncryptedValue |
| JSON Response | AES-256-GCM (same key/IV) | Authenticated payload encryption | Body: ResponseOfEncryptedValue |
Encryption Flow Summary
Code Examples
Troubleshooting
Debug Checklist:- Server RSA public key is correct and in PEM format
- Application identifier is registered and matches exactly
- AES key is exactly 32 bytes (256 bits)
- IV is exactly 12 bytes (96 bits) — GCM requires 12-byte IV
- New random Key and IV are generated for every request
- Request payload is valid JSON before encryption
- Encrypted payload format:
base64(ciphertext) + base64(auth_tag)— NO IV prepended in body - KEK input is plain UTF-8
"key:iv"string — NOT Base64-encoded before RSA - RSA padding is OAEP with SHA-1 (not PKCS1 v1.5, not SHA-256)
- RSA-encrypted KEK bytes are Base64-encoded before putting in
kekheader - Both
kekandappIdentifierheaders are present on every request - Request body contains only the
RequestEncryptedValuefield - Same Key and IV are used to decrypt the response
- Response: last 24 chars =
base64(auth_tag); remaining =base64(ciphertext) - Auth tag is passed into GCM decrypt — not stripped from the payload first
oaep decoding error
oaep decoding error
Likely cause: Wrong RSA public key, or
key:iv was Base64-encoded before RSA encryption.Fix: Use the correct server public key. Pass the raw UTF-8 bytes of "key:iv" directly to RSA encrypt — do not Base64-encode first.GCM auth tag mismatch
GCM auth tag mismatch
Likely cause: Wrong key/IV used for decryption, or IV was prepended to the payload body.Fix: Do not prepend the IV to the payload — it lives only in the
kek header. Use the exact same key + IV from your original request to decrypt the response.AES key invalid size
AES key invalid size
Likely cause: Key is not exactly 32 bytes.Fix: Generate exactly 32 alphanumeric ASCII characters (32 UTF-8 bytes = 256 bits).
Decryption returns garbage
Decryption returns garbage
Likely cause: Payload parts split incorrectly.Fix: Ensure last 24 chars →
auth_tag; all remaining chars → ciphertext. Base64-decode each part separately before passing to GCM.Appendix
Key Specifications
| Parameter | Value |
|---|---|
| RSA Key Size | 2048 or 4096 bits |
| RSA Padding | OAEP with SHA-1 |
| AES Algorithm | AES-256-GCM |
| AES Key Size | 256 bits (32 bytes) |
| AES IV Size | 96 bits (12 bytes) |
| GCM Auth Tag Size | 128 bits (16 bytes) — always 24 chars when base64-encoded |
| Payload Encoding | Base64 (standard, not URL-safe) |
| JSON Encoding | UTF-8 |
Encrypted Payload Structure
| Part of string | Content | Notes |
|---|---|---|
| All characters except last 24 | base64(ciphertext) | AES-GCM ciphertext, base64-encoded |
| Last 24 characters | base64(auth_tag) | 16-byte GCM auth tag, base64-encoded (always 24 chars) |
Request / Response Body Fields
| Field | Direction | Content |
|---|---|---|
RequestEncryptedValue | Client → Server | base64(ciphertext) + base64(auth_tag) |
ResponseOfEncryptedValue | Server → Client | base64(ciphertext) + base64(auth_tag) |
