PAN encryption for 3DS authentication

3-D Secure (3DS) authentication is a card-payment security protocol that adds an extra layer of verification for online card-not-present transactions before authorization. This protocol confirms that the person making the payment is the legitimate cardholder and helps to reduce fraud.

The Send pre-authentication info endpoint sends information to the client's anti-fraud validator to evaluate. The Pismo platform calls the validator's webhook and gets a response before sending a response to the caller.

Pismo provides the encrypt/decrypt keys for the hashed Primary Account Number (PAN). Pismo's PAN encryption uses RSA with Optimal Asymmetric Encryption Padding (OAEP) and Secure Hash Algorithm3, 256-bit (SHA3-256) hashing to securely encrypt sensitive data. The following describes the steps to encrypt the PAN to use with the Send pre-authentication info endpoint.

Implementation steps

📘

Prerequisites

  • RSA public key (2048-bit or 4096-bit recommended)
  • Support for SHA3-256 hashtag algorithm

Step 1: Obtain the public key

Open an internal service desk (ISD) ticket to request the RSA public key. You must provide the following information:

  • The environment you are using: test or production
  • Org ID

Please note that the process to generate and store the private key and to complete the client setup on the 3DS API involves multiple teams and can take some time.

📘

3DS providers

If you are a 3DS provider, you cannot open an ISD ticket. You must contact your client and ask them to request the key and provide it to you.

If you serve more than one issuer with Pismo, each of them will have its own key for PAN encryption.

Step 2: Configure the cipher

Set up the RSA encryption with these specific parameters:

  • Algorithm: RSA
  • Padding: OAEP
  • Hash function: SHA3-256
  • Mask Generation Function (MFG): MFG1 with SHA3-256

Step 3: Encrypt the data

  1. Convert your sensitive data (PAN) to bytes.
  2. Use the public key to encrypt the data.
    The encryption will produce a byte array.

Step 4: Encode the result

Encode the encrypted bytes using Base64 Standard Encoding.

This produces a string safe for transmission in the JSON/HTTP.

Complete examples

Java implementation:

public String encryptPAN(PublicKey publicKey, String pan) throws Exception {
    // Step 1: Initialize cipher
    Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA3-256AndMGF1Padding");
    // Step 2: Configure OAEP parameters
    OAEPParameterSpec oaepParams = new OAEPParameterSpec(
        "SHA3-256",                    // Hash algorithm
        "MGF1",                        // Mask generation function
        MGF1ParameterSpec.SHA3_256,   // MGF hash
        PSource.PSpecified.DEFAULT     // No label
    );
    // Step 3: Initialize for encryption
    cipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParams, new SecureRandom());
    // Step 4: Encrypt
    byte[] encryptedBytes = cipher.doFinal(pan.getBytes());
    // Step 5: Encode to Base64
    return Base64.getEncoder().encodeToString(encryptedBytes);
}

Note: If SHA3-256 is not available, add Bouncy Castle dependency.

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk18on</artifactId>
    <version>1.78</version>
</dependency>

Go implementation

func encryptPAN(publicKey *rsa.PublicKey, pan string) (string, error) {
    // Step 1: Encrypt using OAEP with SHA3-256
    encryptedBytes, err := rsa.EncryptOAEP(
        sha3.New256(),           // Hash function
        rand.Reader,             // Random source
        publicKey,               // Public key
        []byte(pan),            // Data to encrypt
        nil,                    // Optional label (not used)
    )
    if err != nil {
        return "", err
    }
    // Step 2: Encode to Base64
    return base64.StdEncoding.EncodeToString(encryptedBytes), nil
}

Test your implementation

  1. Test with sample data. Use a known PAN value.
  2. Verify Base64 output. Ensure the result is valid Base64.
  3. Complete a length check. Encrypted output should match your key size (for example, 256 bytes for 2048-bit key).
  4. Complete an integration test. Send the encrypted value to the API endpoint.
  5. If you encounter any errors, reach out to your Pismo representative.