Use a signature to secure authenticity and data integrity for communicating with Trustly's API
Overview
The signature with private and public keys is used to ensure sender authenticity and data integrity.
- All requests from the merchant shall be signed with the merchant's private key, Trustly will verify the signature of the request using the merchant's public key.
- All responses from Trustly are signed with Trustly's private key and should be verified by the merchant using Trustly's public key.
Key generation
You can generate your private and public keys with OpenSSL:
openssl genrsa -out private.pem 2048
openssl rsa -pubout -in private.pem -out public.pem -outform PEM
If you are using Windows you will have to install OpenSSL for Windows in order to run the OpenSSL commands above.
The file public.pem should then be sent to the integration team at Trustly ([email protected]).
Trustly's public keys
Trustly's public keys for TEST and LIVE:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy7h/yX8DEA2m588SrWye
AC8rTMbErwHt2hoTiP9fte/iOo0FXIZSmNsNu422L+iJyvZQu19ebeL7XgB0UXqt
zA6KtXBMXIKwuMCZhbdeR8sb7OKbX2nlWM+e2Hmrr9CTfkZkFBeSC+iN9fAU6PoR
X0i5PWm0uZnaoWXcZnk5CxQCgnfYgsx7xsd8Au+mrqE8SHeT8zi/Inw0Xp6ba25G
YsZhHfIPD2rcZQOpWbmHRS4Jk4aGzSOBHbAZhKlP97PxoVfUcPI3iCA1+3jMs1l2
PYsHUbP60NMVwkGPjFOTv4m1a1wKsue0mhspDdvswZUeKE+POGOuewqTQJ+gIhXw
mQIDAQAB
-----END PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoZhnqiELeoX3QNSg7jpU
kbLV4BU32LoSMuABAaPdxhpZaccFYud2z4QUlMq/j46vdVDpaCFaCZ+qNT5+tHbQ
BFgcrx82u7r+aMHvKy4FEczT5aev0NxRlQKHmNQygvp3hNkqeOw4nJy3PoD4cgCp
SlLTiPOBy2ZsWUHQpSVJdDUiLwAQfNV90jMqa3zq1nTfmTBmd6NR1XAjg5eS6SWr
to1nVS1b7XKGv7Cc1kt0RVd54tWqoCMDHwEiU0st66BCKdYk3r5woDZxGZUUjVdm
g9O2xpqRRDcdJGm8HIOVHGSNT9R7LMucH/PGwrfpdWmBDjy0BkuDlssuBgh731l2
cwIDAQAB
-----END PUBLIC KEY-----
Serialising and signing your request
The signature is a Base64 encoding of the [Method, concatenated with UUID, concatenated with a serialisation of the Data{} object]. The serialisation is done by concatenating all scalars, hash keys, hash values and array values together, sorted ASCIIbetically. ("Null" is treated as an empty string.)
We currently allow the following algorithms for signatures. The default is SHA1, when using other algorithms include the noted prefix to the signature. We recommend using one of the SHA256/SHA384/SHA512. Note that we will reciprocate the use of an algorithm, in the response and when signing notifications, including the same prefix to the signature.
Algorithm | Prefix |
---|---|
SHA-1 | |
SHA-256 | alg=RS256; |
SHA-384 | alg=RS384; |
SHA-512 | alg=RS512; |
Please see the simple PHP example below for clarification, and try our signature tester, it will show you how to serialise and sign any data.
$algorithm2prefix = [
OPENSSL_ALGO_SHA1 => '',
OPENSSL_ALGO_SHA256 => 'alg=RS256;',
OPENSSL_ALGO_SHA384 => 'alg=RS384;',
OPENSSL_ALGO_SHA512 => 'alg=RS512;'
];
function serialize_data($object) {
$serialized = '';
if( is_array($object) ) {
ksort($object); //Sort keys
foreach($object as $key => $value) {
if(is_numeric($key)) { //Array
$serialized .= serialize_data($value);
} else { //Hash
$serialized .= $key . serialize_data($value);
}
}
} else return $object; //Scalar
return $serialized;
}
function sign($method, $uuid, $data, $algorithm = OPENSSL_ALGO_SHA1) {
global $algorithm2prefix;
$merchant_private_key = openssl_get_privatekey(file_get_contents(
'trustly-signature-tester-private-key.pem'
));
$plaintext = $method . $uuid . serialize_data($data);
openssl_sign($plaintext, $signature, $merchant_private_key, $algorithm);
return $algorithm2prefix[$algorithm] . base64_encode($signature);
}
function verify($method, $uuid, $data, $signature_from_trustly) {
$trustly_public_key = openssl_get_publickey(file_get_contents(
'trustly-signature-tester-public-key.pem'
));
if(preg_match('/^alg=RS\d{3};/', $signature_from_trustly)) {
global $algorithm2prefix;
$prefix = substr($signature_from_trustly, 0, 10);
$algorithm = isset(array_flip($algorithm2prefix)[$prefix]) ? array_flip($algorithm2prefix)[$prefix] : OPENSSL_ALGO_SHA1;
$signature_from_trustly = substr($signature_from_trustly, 10);
} else {
$algorithm = OPENSSL_ALGO_SHA1;
}
$plaintext = $method . $uuid . serialize_data($data);
return openssl_verify($plaintext,
base64_decode($signature_from_trustly),
$trustly_public_key,
$algorithm
);
}
Below is an example of a JSON object and how it should be serialised:
{
"MyKey": "MyValue",
"MyArray": [
"Element1",
"Element2",
{
"mykey2": "myvalue2"
}
]
}
The JSON data above would result in the serialised string below:
MyArrayElement1Element2mykey2myvalue2MyKeyMyValue
And the resulting signature would, using the private key from the signature tester and the given algorithm, look like this:
DXLFbqQIUOJoYkOj4+RAoeoocRYlQ6DwnnPok0FdFzKz9oGfQ558m1U3TU8ZNcY8Bi4bqC2hF9UVNeFj9VJ0EODYDDQ1H+IIQP5twe4WdWYE912y2sCZcbxHljOhzmbt4KKL7AOkgT+/n7cuVSrCLNwZEllPmPyiWeoa7LnkX7jK446bcLvt1xX7V2V1TO13uA8SEkxzaS8n/iGIzezvLTjiCxw5xqjwm1OTpqISUGOk4Ta238hWDhRlMLkgmrBEb85FQi2U0VPM9brH8w6drBgbSc1jXCi8Xm4HdmX4scR19cfymM44jTvgSOAhtWJ5E12kvrHku1m1jUVTcTujag==
alg=RS256;dNI1vnGe1nyAisWh/TRb+MS1GageHgS2AKcrssckr6svDT81KN3G/1GdhP+zZFXFrLGr85nTs064RjXsiidZDxGv4BoZwosltFIM60uuDUxM9Z6rwFBek/qrCihb6lhOVZSv9v8n+/Jv2U4vm3CgsEOuHRDjiqOWIae92qRT90hN3eajTO8w8Czu62hRmswj9+BsU+CUlZyovjQOmAdgzsPyTMGdfbaP1wgtZt6V751/tUUTRjQCWmvnHDLb15OFGkme0FNi68q92pB9bHFsaNbaqCdTGnAHXbVppvnGCKlzuH6KoUfjmkO7hNHqL8MWYoB0+y2cumGbpov14wXofw==
alg=RS384;hLLU9Mh3o9I5ekN8gzGnaMt/HoQZrVN+Myoa1/y5qnjs9reh1zEvKtoMwHeruQ1qVLw6OLjz8V2SxjrrF9t1OC0VUZyazs99lFLE0s1BRWbNDPr6iq2XGqRLDm3vJQ8jDXzynKtX9nuq+Kel6hGJWYmIrWkAF+KSdjj5iQwg6wqDgbB5zorRX4e3q6z00FPIr4bkbzHDiOkcOtIs7njBLZmXfL3+L8fUmu1XrWvOj+Q17IgMZLqB0PdP6FlxLo2cfIMX08rzqD+pSV2UeaD70YQV6dGqMX8lXBUdj/KHtcld26EMPPsLSAmnc1l+ZjxKd4ScxHnaoHgR35WYYURI+g==
alg=RS512;uTPS0x3yLrFJhznutDqmPDC2VzHDVTN+yVpZhucEqWBJZzh2jIuQZH4KBj5qUOGkbjeZm3jDLNeIv5kVgXtM8YXeao2NAaGlMx9g5CwQv/868v7LjTYI/MdwrehOmrq6YxjGOwVXH98V43O8qsoxE+yr0P6uYEr/8XA6+3aSCHtMviSRHmc5Zcan2dSsEDfzkZTN4z+YM09DUfxxkTaaxRG4uEIExAqlhXkyMjp2ph6EUISYUUtGfPmwwOz/Fw6OX9RtoLbXZXX3q4Y4alQIdY8jsriDvbvMGY666qQMFsY0Qg97jfMljR0r8bGo5Ln5FLDOI3ukC0hzQRm+jLSl5Q==