Sec Key Calculation

Only required if you can't use one of our gems/packages.

If you use one of the supplied gems/packages there is no reason use the code in the following section as the sec_key can be gotten by calling the generate_sec_key function.

Definitions:

api_key - Half of a secret RSA key pair. Used to create signature token (sec_key).

sec_key - Token that combines your partner ID and a timestamp and is encrypted with the api_key.

API Key

Your api is a base 64 encoded RSA public key. It is used to encode a signature for requests made to our server, and to decode the signature of requests coming from our server. For information about how to create and decode signatures see the authentication section of the documentation. You can rotate your API key at time, however, your previous key will be immediately rendered inert.

You can find and generate your an API key hereTo communicate with our system we require a signature on each request to ensure that both parties are who they say they are. In order to sign your requests to our servers, the first step is to generate an API key here. This will return a base 64 encoded RSA public key. The key is unique to each environment, so you will need a different key for the test environment and the production environments. You will need to know your partner ID, which is available below, to create the signature.

Your partner ID: 5

String Value of your partner ID: "005"

In the calculation of the signature use an integer for your partner ID, everywhere else use a string

  1. Create a timestamp

  2. Join the integer value of your int Partner ID to the timestamp using a semi-colon in the format 5:[timestamp]

  3. Create a SHA256 hash of the string created in Step 2

  4. Public Key encrypt the hash using your Base 64 decoded API key. We encourage that you utilise the base 64 encoded version and then decode the api key on your server to public encrypt the hash, however, should you choose to use the the decoded version of your api key, you will also find it here

  5. Base64 encode the encrypted hash

  6. Finally join the the encrypted hash to the unencrypted hash using the "|" character

Be sure to specify pkcs1 padding when utilizing the public key encrypt function of your rsa key, if that is not the default padding of your language of choice.

Example code for creating the signature

Ruby
JavaScript
Python
Java

> Calculating your outgoing signature:
api_key = <Your API key>
partner_id = "<Your partner ID>"
timestamp = Time.now.to_i
hash_signature = Digest::SHA256.hexdigest([partner_id.to_i, timestamp].join(":"))
public_key = OpenSSL::PKey::RSA.new(Base64.decode64(api_key))
signature = [Base64.encode64(public_key.public_encrypt(hash_signature)), hash_signature].join('|')
> Make sure to replace partner_id with your Partner ID.
> Make sure to replace api_key with your API key.
> Calculating an incoming signature:
api_key = "TgorWTFHTG5NL2hEUU5aM3M2ZWJCUndWZGR1aTRLejNCTGZ2RkJwWis1Myty="
partner_id = "001"
timestamp = body["timestamp"]
hash = Digest::SHA256.hexdigest([partner_id.to_i, timestamp].join(":"))
encrypted, hashed = body["sec_key"].split("|")
success = OpenSSL::PKey::RSA.new(Base64.decode64(api_key)).public_decrypt(Base64.decode64(encrypted)) == hash && hash == hashed
## success should equal true
> Make sure to replace partner_id with the String Value of your Partner ID.
> Make sure to replace api_key with your API key.

> Calculating your outgoing signature:
> Please note, you will need to decode your base64 API Key before use
const crypto = require('crypto');
const https = require('https');
const request = require('request'); // npm install request
const URLSafeBase64 = require('urlsafe-base64');
const uuid = require('uuid4'); // npm install uuid4
let apiKey = <Your API key>
let timestamp = Date.now();
let partner_id = "<Your partner ID>";
let hash = crypto.createHash('sha256').update(parseInt(partner_id, 10) + ":" + timestamp).digest('hex');
let encrypted = crypto.publicEncrypt({
key: Buffer.from(apiKey, 'base64'),
padding: crypto.constants.RSA_PKCS1_PADDING
}, Buffer.from(hash)).toString('base64');
let signature = [encrypted, hash].join('|');
> Make sure to replace partner_id with the String Value of your Partner ID.
> Make sure to replace api_key with your API key.
> Calculating an incoming signature:
const crypto = require('crypto');
const URLSafeBase64 = require('urlsafe-base64');
let timestamp = body["timestamp"]
let encrypted, hashed;
[encrypted, hashed] = body["sec_key"].split("|")
let partner_id = "001";
let apiKey = "TgorWTFHTG5NL2hEUU5aM3M2ZWJCUndWZGR1aTRLejNCTGZ2RkJwWis1Myty=";
let hash = crypto.createHash('sha256').update(parseInt(partner_id) + ":" + timestamp).digest('hex');
let decrypted = crypto.publicDecrypt({
key: Buffer.from(Buffer.from(apiKey, 'base64')),
padding: crypto.constants.RSA_PKCS1_PADDING
}, Buffer.from(encrypted, 'base64'));
let success = decrypted == hashed && hashed == hash;
// success should equal true
> Make sure to replace partner_id with the String Value of your Partner ID.
> Make sure to replace api_key with your API key.
> Calculating your outgoing signature:
> Make sure to replace partner_id with the String Value of your Partner ID.
> Make sure to replace api_key with your API key.
from datetime import datetime
import base64
import hashlib
import uuid
from Crypto.PublicKey import RSA
from Crypto import Random
from Crypto.Cipher import PKCS1_v1_5
api_key = base64.b64decode(<Your API key>)
partner_id = "<Your partner ID>"
timestamp = datetime.isoformat(datetime.utcnow())
hashed = hashlib.sha256('{}:{}'.format(int(partner_id), timestamp)).hexdigest()
## Note: python does not handle RSA keys natively we have used the pycrypto library
public_key = RSA.importKey(api_key)
cipher = PKCS1_v1_5.new(public_key)
encrypted = base64.b64encode(cipher.encrypt(hashed))
signature = "{}|{}".format(encrypted, hashed)
> Calculating an incoming signature:
import rsa
import base64
import hashlib
api_key = "TgorWTFHTG5NL2hEUU5aM3M2ZWJCUndWZGR1aTRLejNCTGZ2RkJwWis1Myty="
partner_id = "001"
timestamp = body["timestamp"]
encrypted, hashed = body["sec_key"].split("|")
hash = hashlib.sha256('{}:{}'.format(int(partner_id), timestamp)).hexdigest()
## Note: python does not handle RSA keys natively so I use the rsa library
success = hashed == base64.b64encode(rsa.decrpy(encrypted, base64.b64decode(api_key))) && hashed == hash
## success should equal true
> Make sure to replace partner_id with the String Value of your Partner ID.
> Make sure to replace api_key with your API key.

> Calculating your outgoing signature:
> Make sure to replace partner_id with the String Value of your Partner ID.
> Make sure to replace api_key with the decoded version of your API key. This is special to the Java implementation
import java.util.Base64;
import java.security.spec.X509EncodedKeySpec;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.MessageDigest;
import java.security.Signature;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.*;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.BadPaddingException;
import javax.crypto.NoSuchPaddingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.UUID;
import java.util.Iterator;
import java.io.StringReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.*;
import java.lang.Exception;
public class MyClass {
public static PublicKey loadPublicKey(String apiKey) throws GeneralSecurityException, IOException {
byte[] data = Base64.getDecoder().decode((apiKey.getBytes()));
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory factObj = KeyFactory.getInstance("RSA");
PublicKey lPKey = factObj.generatePublic(spec);
return lPKey;
}
public static byte[] encryptString(PublicKey key, String plaintext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(plaintext.getBytes());
}
public static String bytesToHexStr(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static void main(String args[]) {
try {
String api_key = <Your API key>;
int partner_id = Integer.parseInt("<Your partner ID>")
long timestamp = System.currentTimeMillis();
String toHash = partner_id + ":" + timestamp;
System.out.println("Original: " + toHash);
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(toHash.getBytes());
byte[] hashed = md.digest();
String toEncryptString = bytesToHexStr(hashed);
System.out.println("Key used to encrypt: " + api_key);
PublicKey publicKey = loadPublicKey(api_key);
byte[] encSignature = encryptString(publicKey, toEncryptString);
String signature = Base64.getEncoder().encodeToString(encSignature) + "|" + toEncryptString;
System.out.println("sec_key: " + signature);
}
catch (Exception e) {
e.printStackTrace();
}
}
}