Skip to content

JavaScript

This guide shows you how to decrypt sensitive card details using Node.js. The decryption process uses Rivest-Shamir-Adleman Optimal Asymmetric Encryption Padding (RSA-OAEP) to unwrap the Advanced Encryption Standard (AES) key. Then Advanced Encryption Standard 256-bit Galois/Counter Mode (AES-256-GCM) is used to decrypt the card data.

Prerequisites

Before you begin, you need:

  • Node.js installed on your system
  • Your RSA private key, which was generated when you created the key pair
  • An encrypted response from the View card sensitive details endpoint or the Get card PIN endpoint

Understanding the encrypted response

The View card sensitive details and the Get card PIN endpoints return three base64-encoded values:

Field Description
encrypted_key AES-256 key encrypted with your RSA public key
nonce 12-byte initialization vector for AES-GCM decryption
ciphertext Encrypted card details

Decode the base64 values

Convert all three base64-encoded values from the API response into buffers:

const encryptedKey = Buffer.from(payload.encrypted_key, "base64");
const nonce = Buffer.from(payload.nonce, "base64");
const ciphertext = Buffer.from(payload.ciphertext, "base64");

Decrypt the AES key

Use your RSA private key to decrypt the AES key. The decryption uses RSA-OAEP padding with SHA-256:

const aesKey = crypto.privateDecrypt(
    {
        key: privateKeyPem,
        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
        oaepHash: "sha256",
    },
    encryptedKey
);

Separate the authentication tag

The last 16 bytes of the ciphertext contain the GCM authentication tag. Separate this from the encrypted data:

const authTag = ciphertext.slice(ciphertext.length - 16);
const encryptedData = ciphertext.slice(0, ciphertext.length - 16);

Decrypt the card details

Create an AES-256-GCM decipher, set the authentication tag, and decrypt the card details:

const decipher = crypto.createDecipheriv("aes-256-gcm", aesKey, nonce);
decipher.setAuthTag(authTag);

let decrypted = decipher.update(encryptedData, null, "utf8");
decrypted += decipher.final("utf8");

Complete decryption code

The following example combines all the steps above into a single reusable function, with error handling:

import crypto from "crypto";

export function decryptCardDetails(privateKeyPem, payload) {
    try {
        // Step 1: Decode base64 values
        const encryptedKey = Buffer.from(payload.encrypted_key, "base64");
        const nonce = Buffer.from(payload.nonce, "base64");
        const ciphertext = Buffer.from(payload.ciphertext, "base64");

        // Step 2: Decrypt the AES key using RSA-OAEP
        const aesKey = crypto.privateDecrypt(
            {
                key: privateKeyPem,
                padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
                oaepHash: "sha256",
            },
            encryptedKey
        );

        // Step 3: Separate authentication tag from ciphertext
        const authTag = ciphertext.slice(ciphertext.length - 16);
        const encryptedData = ciphertext.slice(0, ciphertext.length - 16);

        // Step 4: Decrypt using AES-256-GCM
        const decipher = crypto.createDecipheriv("aes-256-gcm", aesKey, nonce);
        decipher.setAuthTag(authTag);

        let decrypted = decipher.update(encryptedData, null, "utf8");
        decrypted += decipher.final("utf8");

        return decrypted;
    } catch (err) {
        throw new Error("Decryption failed: " + err.message);
    }
}

Usage example

The following example shows how you can pass your PEM-formatted private key and the encrypted payload from the API response to the decryptCardDetails function:

const privateKey = `
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA5llQr/KNtRhTn+2LJMwd5H62QUdMZ8Gq25LDpZRaosYbsoxH
... your private key content ...
-----END RSA PRIVATE KEY-----
`;

// Response from the View card sensitive details endpoint
const encryptedPayload = {
    ciphertext: "kJR3z/bVTMTjiXMIQ8ha/eN/69q5vMr1sm6o1iKnCOixCB98tvp4WNsh9YCFXqNEPWfTkuiQ",
    encrypted_key: "zmhGe7OkCl2e5lNaSU6rw28u1UvzqWyncHc+4fKfn+GRBua+zleDdaMfHctTPqK0...",
    nonce: "W5lMRrL2yKSyWgfq"
};

const cardDetails = decryptCardDetails(privateKey, encryptedPayload);
console.log("Card details:", cardDetails);