Introduction to Sending Secure Data

Thredd enables customers to be able to send secure data to a cardholder. This is available to customers with or without PCI DSS compliance.

🚧

Important

Thredd does not authenticate the device or the identity of the device holder. We strongly recommend that you implement policy-based controls to identify cardholders.

Two keys will be provided by Thredd. You must convert them to byte arrays to use the encrypted data endpoint.

  • A Thredd signature RSA key. This is not to be used for encryption.
  • A customer specific RSA key. This is to be used for encryption.

📘

Note

Thredd provide the public key as a certificate or a raw key. Contact your Implementation Manager to let them know which you would prefer.

To use the encryption endpoints, combine the customer-specific RSA key with an AES key.

Creating an AES Key

When creating an AES key, ensure that the key:

  • Is uniquely generated for each request.
  • Has a length that is no smaller than 256 bits.
  • Is encrypted with your company specific public RSA key, provided to you in Hex format by Thredd.

See the below examples on how to create an AES key using C# and NodeJs.

using System.Security.Cryptography;

public byte[] GenerateKey()
{
    var aes = Aes.Create();
    aes.KeySize = 256;
    aes.GenerateKey();

    return aes.Key;
}

public string EncryptAesKey(byte[] aesKey)
{
    var aesKey = GenerateKey();
    var rsaPublicKey = Convert.FromHexString("Public RSA key as hexadecimal string goes here");

    using (RSACryptoServiceProvider crypto = new RSACryptoServiceProvider())
    {
        crypto.ImportRSAPublicKey(rsaPublicKey, out _);
        var encryptedAesKey = crypto.Encrypt(aesKey, RSAEncryptionPadding.Pkcs1);

        return Convert.ToBase64String(encryptedAesKey);
    }
}
const { subtle } = require('crypto').webcrypto;

async function generateKey() {
    const algoritm = { name: "AES-CBC", length: 256 };
    const exportable = true;
    const usage = ['encrypt', 'decrypt'];
    return await subtle.generateKey(algoritm, exportable, usage);
}

async function encryptAesKey() {
    let aesKey = generateKey();

    let rawRsaPublicKey = Buffer.from("Public RSA key as hexadecimal string goes here", 'hex');
    const format = "raw";
    const rsaParams = new RSAHashedImportParams {
        name = "RSASSA-PKCS1-v1_5",
        hash = "SHA-256"
    }
    const exportable = false;
    const usage = ["wrapKey"];
    let rsaPublicKey = await subtle.ImportKey(format, rawRsaPublicKey, rsaParams, exportable, usage);

    let wrappedKey = await subtle.wrapKey(format, aesKey, rsaPublicKey, { name: "RSA-OAEP" });

    return wrappedKey.toString('base64');
}

This script will produce two keys:

  • An unencrypted AES Key, used to decrypt the response.
  • An encrypted AES Key, use to populate the body of the Get Encrypted Data endpoint.

🚧

Important

If you do not have PCI DSS certification, all key generation encryption, and decryption must happen on the device. You must send only encrypted data to your backend systems. Thredd is only responsible for ensuring the data is encrypted as it leaves our estate. Thredd clients are responsible for ensuring they are not breaching PCI DSS rule.