Skip to content
On this page

Message Security

RSA/AES Encryption

Optionally, message encryption may be used when making a POST request to the API.

  • Message encryption uses a combination of AES and RSA encryption.
    • The message payload is encrypted using AES-CTR-256.
    • The resultant AES key is then encrypted using an RSA 2048-bit public key.
  • RSA key-pairs can be created in the Nexus portal Settings view, and the public key can be copied.
    • A maximum of 2 keys can be created for key rotation purposes.
    • Public keys are copied in PCKS #8 format.
    • Public keys can also be retrieved from the partner public key API.

API Encryption Keys

  • Use the API routes as documented, except the payload will always be an object with 'encrypted' and 'hash' properties.
    • The 'encrypted' property will the Key ID used to encrypt the AES key
    • The 'hash' will be a built-up string containing the RSA encrypted combination of the AES key plus IV, and the AES encrypted payload.
      • rsaEncryptedAesKeyAndIv delimited with a bar character |
        • '${aesKey}.toString('base64')}|${aesIv}.toString('base64')'
      • aesEncryptedPayload
        • aesCipher.update(payload, 'utf8', 'base64') + aesCipher.final('base64')
      • Final hash value is the rsaEncryptedAesKeyAndIv and aesEncryptedPayload delimited with a bar character |
        • ${rsaEncryptedAesKeyAndIv}|${aesEncryptedPayload}

Example Node.js Encryption

javascript
import { createCipheriv, randomBytes } from 'crypto'
import NodeRSA from 'node-rsa'

const algorithm = 'aes-256-ctr'
const inputEncoding = 'utf8'
const outputEncoding = 'base64'

function preparePayload(payload) {
  // Get the public key from the Nexus portal or the partner public key API endpoint
  const publicKeyString = '' // https://bdcs.q2developer.com/docs/api/partner/public-key.html

  // Encrypt the payload with AES
  const aesKey = Buffer.from(randomBytes(32))
  const aesIv = Buffer.from(randomBytes(16))
  const aesCipher = createCipheriv(algorithm, aesKey, aesIv)
  let aesEncryptedPayload = aesCipher.update(payload, inputEncoding, outputEncoding)
  aesEncryptedPayload += aesCipher.final(outputEncoding)

  // Combine the AES key and iv into a single string
  const aesKeyPlusIv = `${aesKey.toString(outputEncoding)}|${aesIv.toString(outputEncoding)}`

  // Now Encrypt the AES key and iv with RSA
  const publicKey = new NodeRSA()
  publicKey.importKey(publicKeyString, 'pkcs8-public')
  const rsaEncryptedAesKeyAndIv = publicKey.encrypt(aesKeyPlusIv, outputEncoding)

  // Return the perpared hash value for the request
  return `${rsaEncryptedAesKeyAndIv}|${aesEncryptedPayload}`
}

Example Encrypted Request

json
{
  "encrypted": "os8th269xgj7tyku7wxl",
  "hash": "PQ5...Q==|H87c...Q=="
}

RSA Request Signing

Optionally, 2048-bit asymmetric request signing may be used when making requests to the API.

Example Signed Request

shell
curl "https://api.q2open.io/v1/client/create-token" \
  -H "Authorization: Bearer dc220490-e6ee-11e5-8a94-e7385a8d929e" \
  -H "Signature: MzfMtn6M9rpHyzGSvBPkzbNZlne+rf3tkcLUeMUW8mOMmdP1VtnnVdQA9hdYVObjwibOGdRQmCeoI9Xba5DXGT2/l9wOSJQ4FI90DssY1l+orOiwVwY8quAgBUYd2YDDUGyEJ31Y9yOgwLBp2xC4pA5vfkYtWAC9PccdxDyMZcCm6pz3AVgfCRN1m2rcZsE/VrhWhZof3sYitP3zTfV7KCF3T232HPHQtEYtEMLE4Pi7t4i+KvR4Rejt4a7DIgba3OfVmWf5La7WzdlU4eneIPnVjk3CGUo4t9PIPJQVbLyDSIXiF9pRD8ZlW+19XUe/HyWFHR4em00nbaNjBG4TSQ==" \
  -H "kid": "key001" \
  -H "Date: 2019-09-17T14:14:24.874Z" \
  -H "Content-Type: application/json" \
  -d '{
    "identifier": "5b2bd638bdf6035960b98694"
  }'
  -X POST

Keypair Provisioning

API request signing key-pairs can be added manually in the Nexus portal or in automated fashion by providing an API endpoint. If the kid is left out of the request headers, then the first key in the system will be used which may cause problems when rotating keys. Easiest is to just pass in the kid every time if request signing is set up and enabled.

Manual

  • Create a 2048-bit RSA keypair following the PKCS #1/sha-256 signing scheme.
  • Update the API Request Signing Public Key in the Q2 Nexus portal Settings view.

API Signing Key Manual

Partner Provided API

An API endpoint may be provided by the partner which the CardSwap system will use to keep signing keys synchronized. Keys will be requested from the API daily. It is assumed that the expiration of a new partner RSA signing key will be several days at a minimum. If no valid keys are present, the CardSwap retrieval job will ping the partner endpoint several times daily to request valid keys. The API must return keys in standard JWKS (JSON Web Key Set) format. Please refer to the JWK standards for more information.

When setting up the API endpoint in Nexus, a collection of headers can also be added if the endpoint requires additional metadata to function. Headers are provided in JSON format.

API Signing Key Url

Signing the API Request

  • With each request to the API, generate a signature using the following formula:
    • Request method in all uppercase: POST/PUT/GET/DELETE plus a colon.
    • Path and query of the request plus a colon.
    • Your API Key plus a colon.
    • The current date and time in ISO format
    • Example: POST:/v1/client/create-token:YOUR_API_KEY:2019-09-17T14:14:24.874Z
  • Use an RSA signing library to create an RSA signature from the signature text with the pkcs1-sha256 signing scheme.
  • Encode the produced signature as a Base64 string.
  • Add the Base64 signature in the Signature header of the request.
  • Add the date that was included in the signature to the Date header of the request.

When request signing is enabled, a signature must be provided with every API request. If the signature is not provided, a 401-Unauthorized response will result.