Encryption
Implement end-to-end encryption for Paywize API requests using AES-256-CBC.
Last updated: 2026-02-21
Encryption and Decryption
Overview
All Paywize APIs use AES-256-CBC encryption to secure sensitive data transmission. This guide provides implementation details for encrypting request data and decrypting response data across all Paywize products.
Quick Reference
| Attribute | Details |
|---|---|
| Encryption Algorithm | AES-256-CBC |
| Key Source | API Key (32 characters) |
| IV Source | Secret Key (16 characters) |
| Encoding | Base64 after encryption |
| Data Format | JSON before encryption |
| Security Level | Enterprise-grade |
Encryption Process
Step-by-Step Encryption
- Prepare Data: Convert JSON object to string format
- AES-256-CBC Encryption: Encrypt using your API Key as encryption key
- Initialization Vector: Use your Secret Key as the IV
- Base64 Encoding: Encode encrypted data for safe transmission
Implementation
JavaScript
import crypto from 'crypto';
// Encrypt merchant data
export function encryptMerchantData(data, key, iv) {
if (typeof data === 'object') {
data = JSON.stringify(data);
}
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
const encrypted = Buffer.concat([cipher.update(data, 'utf8'), cipher.final()]);
return encrypted.toString('base64');
}
// Decrypt merchant data
export function decryptMerchantData(data, key, iv) {
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
const decrypted = Buffer.concat([
decipher.update(Buffer.from(data, 'base64')),
decipher.final()
]);
return decrypted.toString('utf8');
}
// Example usage
const apiKey = 'your_32_char_api_key_here_123456';
const secretKey = 'your_16_char_iv_12';
// Encrypt request data
const requestData = {
senderId: "TXN123456",
txnType: "INTENT",
requestAmount: "100.50"
};
const encryptedPayload = encryptMerchantData(requestData, apiKey, secretKey);
console.log('Encrypted:', encryptedPayload);
// Decrypt response data
const decryptedResponse = decryptMerchantData(encryptedPayload, apiKey, secretKey);
console.log('Decrypted:', JSON.parse(decryptedResponse));
Python
import json
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
def encrypt_merchant_data(data, key, iv):
"""
Encrypt data using AES-256-CBC
Args:
data: Data to encrypt (string or dict)
key: 32-byte encryption key
iv: 16-byte initialization vector
Returns:
Base64 encoded encrypted string
"""
if isinstance(data, dict):
data = json.dumps(data)
# Convert strings to bytes
key_bytes = key.encode('utf-8')
iv_bytes = iv.encode('utf-8')
data_bytes = data.encode('utf-8')
# Create cipher and encrypt
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
padded_data = pad(data_bytes, AES.block_size)
encrypted = cipher.encrypt(padded_data)
# Return base64 encoded result
return base64.b64encode(encrypted).decode('utf-8')
def decrypt_merchant_data(encrypted_data, key, iv):
"""
Decrypt data using AES-256-CBC
Args:
encrypted_data: Base64 encoded encrypted string
key: 32-byte encryption key
iv: 16-byte initialization vector
Returns:
Decrypted string
"""
# Convert strings to bytes
key_bytes = key.encode('utf-8')
iv_bytes = iv.encode('utf-8')
# Decode base64 and decrypt
encrypted_bytes = base64.b64decode(encrypted_data)
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
decrypted_padded = cipher.decrypt(encrypted_bytes)
decrypted = unpad(decrypted_padded, AES.block_size)
return decrypted.decode('utf-8')
# Example usage
api_key = 'your_32_char_api_key_here_123456'
secret_key = 'your_16_char_iv_12'
# Encrypt request data
request_data = {
"senderId": "TXN123456",
"txnType": "INTENT",
"requestAmount": "100.50"
}
encrypted_payload = encrypt_merchant_data(request_data, api_key, secret_key)
print(f"Encrypted: {encrypted_payload}")
# Decrypt response data
decrypted_response = decrypt_merchant_data(encrypted_payload, api_key, secret_key)
print(f"Decrypted: {json.loads(decrypted_response)}")
PHP
<?php
class PaywizeEncryption {
/**
* Encrypt data using AES-256-CBC
*/
public static function encryptMerchantData($data, $key, $iv) {
if (is_array($data) || is_object($data)) {
$data = json_encode($data);
}
$encrypted = openssl_encrypt(
$data,
'AES-256-CBC',
$key,
OPENSSL_RAW_DATA,
$iv
);
return base64_encode($encrypted);
}
/**
* Decrypt data using AES-256-CBC
*/
public static function decryptMerchantData($encryptedData, $key, $iv) {
$data = base64_decode($encryptedData);
$decrypted = openssl_decrypt(
$data,
'AES-256-CBC',
$key,
OPENSSL_RAW_DATA,
$iv
);
return $decrypted;
}
}
// Example usage
$apiKey = 'your_32_char_api_key_here_123456';
$secretKey = 'your_16_char_iv_12';
// Encrypt request data
$requestData = [
'senderId' => 'TXN123456',
'txnType' => 'INTENT',
'requestAmount' => '100.50'
];
$encryptedPayload = PaywizeEncryption::encryptMerchantData($requestData, $apiKey, $secretKey);
echo "Encrypted: " . $encryptedPayload . "\n";
// Decrypt response data
$decryptedResponse = PaywizeEncryption::decryptMerchantData($encryptedPayload, $apiKey, $secretKey);
echo "Decrypted: " . $decryptedResponse . "\n";
?>
Java
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.nio.charset.StandardCharsets;
public class PaywizeEncryption {
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String KEY_ALGORITHM = "AES";
/**
* Encrypt data using AES-256-CBC
*/
public static String encryptMerchantData(String data, String key, String iv)
throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), KEY_ALGORITHM);
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
}
/**
* Decrypt data using AES-256-CBC
*/
public static String decryptMerchantData(String encryptedData, String key, String iv)
throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), KEY_ALGORITHM);
IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
return new String(decrypted, StandardCharsets.UTF_8);
}
// Example usage
public static void main(String[] args) throws Exception {
String apiKey = "your_32_char_api_key_here_123456";
String secretKey = "your_16_char_iv_12";
// Encrypt request data
String requestData = "{\"senderId\":\"TXN123456\",\"txnType\":\"INTENT\",\"requestAmount\":\"100.50\"}";
String encryptedPayload = encryptMerchantData(requestData, apiKey, secretKey);
System.out.println("Encrypted: " + encryptedPayload);
// Decrypt response data
String decryptedResponse = decryptMerchantData(encryptedPayload, apiKey, secretKey);
System.out.println("Decrypted: " + decryptedResponse);
}
}
Key Requirements
API Key (Encryption Key)
- Length: 32 characters (256 bits)
- Usage: Used as the AES encryption key
- Security: Keep this confidential and never expose in client-side code
Secret Key (Initialization Vector)
- Length: 16 characters (128 bits)
- Usage: Used as the Initialization Vector (IV) for CBC mode
- Security: Keep this confidential and never expose in client-side code
Request/Response Flow
1. Encrypting Request Data
// Original request data
const requestData = {
senderId: "TXN123456",
txnType: "INTENT",
requestAmount: "100.50"
};
// Encrypt the data
const encryptedPayload = encryptMerchantData(requestData, apiKey, secretKey);
// Send encrypted payload
const apiRequest = {
payload: encryptedPayload
};
2. Decrypting Response Data
// API response contains encrypted data
const apiResponse = {
respCode: 2000,
respMessage: "Success",
data: "encrypted_base64_string_here"
};
// Decrypt the response data
const decryptedData = decryptMerchantData(apiResponse.data, apiKey, secretKey);
const responseData = JSON.parse(decryptedData);
Error Handling
Common Encryption Errors
| Error Code | Message | Solution |
|---|---|---|
4014 | Decryption failed. Please check the encryption | Verify API Key and Secret Key are correct |
4001 | Invalid request format | Ensure data is properly encrypted and Base64 encoded |
Debugging Tips
- Verify Key Lengths: Ensure API Key is 32 characters and Secret Key is 16 characters
- Check Character Encoding: Use UTF-8 encoding for all string operations
- Validate Base64: Ensure encrypted data is properly Base64 encoded
- Test with Known Values: Use the provided test cases to verify your implementation
Security Best Practices
Critical Security Guidelines
- Never Log Sensitive Data: Don't log API keys, secret keys, or decrypted data
- Use Environment Variables: Store credentials securely outside your codebase
- Validate Input: Always validate data before encryption
- Handle Exceptions: Implement proper error handling for encryption/decryption operations
- Secure Key Storage: Use secure credential management systems in production
- Regular Key Rotation: Rotate your API credentials regularly
Additional Security Measures
- HTTPS Only: Always use HTTPS for API requests
- IP Whitelisting: Restrict API access to approved IP addresses
- Rate Limiting: Implement proper rate limiting to prevent abuse
- Audit Logging: Log API usage patterns without exposing sensitive data
Testing Your Implementation
Use these test vectors to verify your encryption implementation:
// Test case
const apiKey = 'test_api_key_32_characters_long';
const secretKey = 'test_secret_16ch';
const testData = '{"test": "data"}';
// Expected encrypted result (will vary due to padding)
const encrypted = encryptMerchantData(testData, apiKey, secretKey);
const decrypted = decryptMerchantData(encrypted, apiKey, secretKey);
// Should match original data
console.assert(decrypted === testData, 'Encryption/Decryption test failed');
Next Steps
- Learn about Authentication to obtain JWT tokens
- Explore Collection API implementation
- Explore Payout API implementation