Integration Guide
Gateway Encryption
RSA + AES envelope encryption for sensitive operations like PIN management and card data retrieval.
For operations involving sensitive card data (PIN set, full card number retrieval), the M2P Platform requires envelope encryption using RSA + AES.
Encryption Flow
How It Works
| Step | Action | Algorithm |
|---|---|---|
| 1 | Generate a random AES-256 key and initialization vector (IV) | AES-256 |
| 2 | Encrypt the JSON request payload using AES-256-CBC | AES-256-CBC |
| 3 | Encrypt the AES key using M2P's RSA public key | RSA PKCS1 |
| 4 | Send the encrypted payload, encrypted key, and IV to the gateway | HTTPS |
| 5 | Gateway decrypts the AES key using its RSA private key | RSA PKCS1 |
| 6 | Gateway decrypts the payload and processes the request | AES-256-CBC |
Implementation
const crypto = require('crypto');
function encryptForGateway(payload, m2pRsaPublicKey) {
// Step 1: Generate random AES-256 key and IV
const aesKey = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
// Step 2: Encrypt payload with AES-256-CBC
const cipher = crypto.createCipheriv('aes-256-cbc', aesKey, iv);
let encryptedData = cipher.update(
JSON.stringify(payload), 'utf8', 'base64'
);
encryptedData += cipher.final('base64');
// Step 3: Encrypt AES key with RSA public key
const encryptedKey = crypto.publicEncrypt(
{
key: m2pRsaPublicKey,
padding: crypto.constants.RSA_PKCS1_PADDING
},
aesKey
).toString('base64');
// Step 4: Return the encrypted bundle
return {
encryptedData,
encryptedKey,
iv: iv.toString('base64')
};
}import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.util.Base64;
public class GatewayEncryption {
public static Map<String, String> encrypt(
String payload, PublicKey m2pRsaPublicKey
) throws Exception {
// Step 1: Generate random AES-256 key and IV
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey aesKey = keyGen.generateKey();
byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
// Step 2: Encrypt payload with AES-256-CBC
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey,
new IvParameterSpec(iv));
byte[] encryptedData = aesCipher.doFinal(
payload.getBytes(StandardCharsets.UTF_8));
// Step 3: Encrypt AES key with RSA public key
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsaCipher.init(Cipher.ENCRYPT_MODE, m2pRsaPublicKey);
byte[] encryptedKey = rsaCipher.doFinal(aesKey.getEncoded());
// Step 4: Return the encrypted bundle
return Map.of(
"encryptedData", Base64.getEncoder()
.encodeToString(encryptedData),
"encryptedKey", Base64.getEncoder()
.encodeToString(encryptedKey),
"iv", Base64.getEncoder()
.encodeToString(iv)
);
}
}When Encryption Is Required
| Operation | Encryption Required | Reason |
|---|---|---|
| Set PIN | Yes | PIN must never be transmitted in plaintext |
| Change PIN | Yes | PIN must never be transmitted in plaintext |
| Full Card Number Retrieval | Yes | Full PAN is sensitive cardholder data |
| Encrypted Card Data (Tokenization) | Yes | Card data for Apple Pay / Google Pay provisioning |
| Standard API Calls | No | JWT + HTTPS provides sufficient security |
Never transmit card PINs or full card numbers without gateway encryption. This is a PCI-DSS compliance requirement.
