It is also possible to encrypt specific attributes sent on the establish data object to Trustly. The encryption is done using the AES-256-CBC algorithm and your Trustly accessKey as the encryption key. The encrypted attributes start with the prefix crypt2: and the full encrypted value (including the prefix) must be used when calculating the request signature.
Example code snippet:
const Crypto = require('crypto');
const accessKey = 'YOUR_ACCESS_KEY';
const attributeValue = '123123456'; //can be any PII or other sensitive data
const algorithm = 'aes-256-cbc';
const encoding = 'base64';
const iv = Buffer.from(Crypto.randomBytes(16)).toString('hex').slice(0, 16);;
const keyHash = Crypto.createHash('sha256').update(accessKey).digest();
const cipher = Crypto.createCipheriv(algorithm, keyHash.slice(0, 32), iv);
cipher.setAutoPadding(true);
let encrypted = cipher.update(iv + attributeValue, 'utf8', encoding);
encrypted += cipher.final(encoding);
console.log('response', 'crypt2:' + encrypted);public class EncryptedAttribute {
public static final String AES_ECB_PKCS_5_PADDING = "AES/ECB/PKCS5Padding";
private static volatile SecureRandom numberGenerator = new SecureRandom();
public static byte[] salt(byte[] data) {
byte[] salt = new byte[4];
numberGenerator.nextBytes(salt);
byte[] salted = new byte[data.length + salt.length];
System.arraycopy(salt, 0, salted, 0, salt.length);
System.arraycopy(data, 0, salted, salt.length, data.length);
return salted;
}
public static byte[] unsalt(byte[] data) {
byte[] unsalted = new byte[data.length - 4];
System.arraycopy(data, 4, unsalted, 0, unsalted.length);
return unsalted;
}
public static String encodeBase64(byte[] binary) {
return Base64.getEncoder().encodeToString(binary);
}
public static byte[] decodeBase64(String str) {
try {
return Base64.getDecoder().decode(str);
} catch (Exception e) {
return new byte[0];
}
}
public static String encryptAttribute(String attribute, String accessKey) throws Exception {
if (attribute == null || attribute.length() == 0) {
return attribute;
}
Cipher cipher = Cipher.getInstance(AES_ECB_PKCS_5_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, buildKey(accessKey));
return "crypt:" + encodeBase64(cipher.doFinal(salt(attribute.getBytes("UTF-8"))));
}
public static String decryptAttribute(String attribute, String accessKey) {
if (attribute == null || accessKey == null || !attribute.startsWith("crypt2:")) { //If attribute is not
encrypted
return it
return attribute;
}
try {
Cipher cipher = Cipher.getInstance(AES_ECB_PKCS_5_PADDING);
cipher.init(Cipher.DECRYPT_MODE, buildKey(accessKey));
return new String(unsalt(cipher.doFinal(decodeBase64(attribute.substring("crypt2:".length())))), "UTF-
8 ");
}
catch (Exception e) {
return attribute;
}
}
private static SecretKeySpec buildKey(String accessKey) throws Exception {
MessageDigest digester = MessageDigest.getInstance("SHA-256");
digester.update(accessKey.getBytes("UTF-8"));
byte[] key = Arrays.copyOf(digester.digest(), 32);
SecretKeySpec spec = new SecretKeySpec(key, "AES");
return spec;
}
}using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
const string accessKey = "YOUR_ACCESS_KEY";
const string attributeValue = "123123456";
var random = new Byte[16];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(random);
var iv = BitConverter.ToString(random).Replace("-", "").Substring(0, 16);
var keyHash = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(accessKey));
Aes aes = Aes.Create();
aes.Key = keyHash;
aes.IV = UTF8Encoding.UTF8.GetBytes(iv);
aes.Mode = CipherMode.CBC;
ICryptoTransform cipher = aes.CreateEncryptor(aes.Key, aes.IV);
var inputBuffer = aes.IV.Concat(UTF8Encoding.UTF8.GetBytes(attributeValue)).ToArray();
var resultArray = cipher.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
var encrypted = Convert.ToBase64String(resultArray, 0, resultArray.Length);
Console.WriteLine("crypt2:" + encrypted);
}
}- Create an initialization vector (
iv) containing 16 random characters. - Create a SHA256 hash of your
accessKey. - Using the first 32 characters of your accessKey hash (from step 2) and the initialization vector (from step 1), create a cipher.
- Using the cipher key (from step 3), the initialization vector (from step 1), and the attribute value to encrypt, update the cipher.
- Create an encrypted string by finalizing the cipher using
base64encoding. - Concatenate
crypt2:and your encrypted string, and pass the value in theestablishDatavalue that is passed to the SDK:
customer: {
name: 'John Smith',
taxId: 'crypt2:uFVg4qGHj7ZtwSv1tkFAL7pBJ5x8zsehYgNdU51w5yA=',
address: {
country: 'US',
}
},