/

to search

Introducing Setu Changelog Check it out ↗

#Setu Encrypted APIs

#Overview

Our secure data add-on is designed to be integrated with any KYC API to enhance the protection of sensitive data during transmission.

With this add-on, non-sensitive fields (such as id and traceId) remain visible for tracking and logging, while all sensitive information is securely packaged inside the encrypted_data field.

Setu’s public key, fetched dynamically, is used to secure the sensitive data in your request. The response from Setu will also be secured, and you must decrypt it to reconstruct the complete message.


#Integration Steps

#1. Public Key Exchange

Before transmitting any secured data, you must retrieve Setu's latest public key dynamically.
This ensures that all secured requests use the current key, as keys are rotated periodically.

GET /v2/public-key

Sample Response:

{
"public-key": {
"ECIES": "03d…",
"RSA": "MIIBI…"
},
"traceId": "1-67dbb.."
}

Note: The public key may be updated over time.


#2. Securing Sensitive Data (Request)

Use Setu's public key (obtained from the previous step) to secure your request payload. Below are the two available methods for securing the sensitive data in your request.

#Method 1: ECIES

  • Process:
    The sensitive payload is directly secured using the ECIES mechanism and Setu’s public key.
  • Request Message Structure:
{
"id": "unique-request-id-123",
"encrypted_data": "Encrypted_Payload"
}

#Method 2: AES-RSA (Hybrid)

  • Process:
    1. A temporary AES key is generated.
    2. The sensitive payload is encrypted using this AES key.
    3. The AES key is then encrypted using Setu’s RSA public key.
  • Request Message Structure:
{
"id": "unique-request-id-123",
"encrypted_data": "Base64_Encrypted_Payload",
"encrypted_key": "Base64_Encrypted_AES_Key"
}

Note: In your secured request, use Setu's public key (from section 1) to secure the data.


#3. Response Handling

Setu's response will include unprotected fields (like id and traceId) along with the secured sensitive data. Depending on the method used:

  • For ECIES:
    The response will include an encrypted_data field.
    To recover the sensitive payload, decrypt the encrypted_data using your ECIES private key.
{
"id": "unique-request-id-123",
"traceId": "trace-id-456",
"encrypted_data": "Encrypted_Payload"
}
  • For AES-RSA (Hybrid):
    The response will include both encrypted_data and encrypted_key fields.
    First, unwrap the AES key by decrypting encrypted_key using your RSA private key.
    Then, use the recovered AES key to decrypt the encrypted_data and retrieve the sensitive payload.
{
"id": "unique-request-id-123",
"traceId": "trace-id-456",
"encrypted_data": "Base64_Encrypted_Payload",
"encrypted_key": "Base64_Encrypted_AES_Key"
}

After decryption, merge the recovered sensitive data with the unprotected fields to reconstruct the complete response.

Note: Store your private keys securely and share your public key to setu


#Code Examples


import base64
import os
from Crypto.Cipher import AES, PKCS1_v1_5
from Crypto.Util.Padding import pad, unpad
from Crypto.PublicKey import RSA
import json
def generate_aes_key() -> str:
key = os.urandom(32) # 256-bit key
return base64.b64encode(key).decode('utf-8')
def aes_encrypt(message: str, key_base64: str) -> str:
key = base64.b64decode(key_base64)
iv = os.urandom(16)
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(message.encode(), AES.block_size))
return base64.b64encode(iv + ciphertext).decode('utf-8')
def aes_decrypt(message: str, key_base64: str) -> str:
key = base64.b64decode(key_base64)
encrypted_data = base64.b64decode(message)
iv = encrypted_data[:16]
ciphertext = encrypted_data[16:]
cipher = AES.new(key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(ciphertext), AES.block_size).decode('utf-8')
def rsa_encrypt(message, public_key_b64):
public_key_der = base64.b64decode(public_key_b64)
public_key = RSA.import_key(public_key_der)
cipher = PKCS1_v1_5.new(public_key)
encrypted = cipher.encrypt(message.encode())
return base64.b64encode(encrypted).decode('utf-8')
def rsa_decrypt(encrypted_message_b64, private_key_b64):
private_key = RSA.import_key(base64.b64decode(private_key_b64))
encrypted_message = base64.b64decode(encrypted_message_b64)
cipher = PKCS1_v1_5.new(private_key)
decrypted_message = cipher.decrypt(encrypted_message, None).decode('utf-8')
return decrypted_message
def encrypt(rsa_public_key: str, data_str: str) -> dict:
aes_key = generate_aes_key()
secured_data = aes_encrypt(message=data_str, key_base64=aes_key)
wrapped_key = rsa_encrypt(message=aes_key, public_key_b64=rsa_public_key)
return {"encrypted_data": secured_data, "encrypted_key": wrapped_key}
def decrypt(rsa_private_key: str, encrypted_key: str, encrypted_data: str) -> dict:
aes_key = rsa_decrypt(encrypted_message_b64=encrypted_key, private_key_b64=rsa_private_key)
data = aes_decrypt(message=encrypted_data, key_base64=aes_key)
return json.loads(data)
# Example usage:
private_key = "<YOUR_RSA_PRIVATE_KEY>"
public_key = "<YOUR_RSA_PUBLIC_KEY>"
data = '{"ifsc":"ABCD0123456","accountNumber":"1234567890","narration":"test transaction","matchKey":"gaurav"}'
secured_response = encrypt(rsa_public_key=public_key, data_str=data)
print("Secured Request:", secured_response)
recovered_data = decrypt(rsa_private_key=private_key, encrypted_key=secured_response['encrypted_key'], encrypted_data=secured_response['encrypted_data'])
print("Recovered Data:", recovered_data)

Was this page helpful?