Signed PAPE Requests

Digital Signatures

As mentioned in our security section, certain PAPE requests need to be digitally signed.

The digital signature algorithm to use will be RSAwithSHA256. You should figure out how to sign payloads with the RSAwithSHA256 on your programming platform. For platforms that don’t directly support RSAwithSHA256, you should hash your payload first with Sha256, and sign with PKCS1v15.

The payload to sign will be:

payloadToSign = urlWithoutHost + rawBody

You should sign your payload with the private key you generated during the onboarding process. PAPE will use your supplied public key to verify the validity of your API calls.

The Signed PAPE Requests Tool

Ultimately, you should integrate RSAwithSHA256 digital signatures in your own workflow and programming language.

But for the purpose of testing signed requests to the PAPE network, we’ve created a Python command line tool to help you conveniently sign and send digitally secured API requests to PAPE.

You can download the Python code here: Signed PAPE Requests Tool

The Signed PAPE Request Tool Python Code

If for any reasons you can’t download the above attached file, here’s the python code to help you sign requests. Feel free to adapt it to your own programming language and workflow.

Config file gateway.ini below:

[user]
# Contact Interswitch to obtain your username and password combo.
username=gateway_id_here
password=gateway_password_here

[oauth2]
token_url=https://id.dev.projectwhite.io/auth/realms/projectwhite/protocol/openid-connect/token
client_id=projectwhite

[rsa]
privkey_file=gateway.priv

Python file signed_pape_request.py below:

#!/usr/bin/python

import sys

from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
from Crypto.Hash import SHA256
import base64
import configparser
import requests
import json
from urllib.parse import urlparse


if len(sys.argv) != 5 :
    print(len(sys.argv))
    print("")
    print("invalid-syntax")
    print("")
    print("help: signed_pape_request.py 'config_file' 'HTTP_VERB' 'url' 'body'")
    print("e.g. On Linux")
    print("python3 signed_pape_request.py 'gateway.ini' 'POST' 'https://apis-alpha.dev.projectwhite.io/liquidity-providers/807e5a5a-8596-476b-8476-300640a1857b/deposits' '{\"paymentGatewayId\": \"cm.wallet.interstellar-demo.xaf\", \"amount\": \"10000\", \"currency\": \"XAF\", \"paymentGatewayTransactionId\":\"7\"}'")
    print("e.g. on Windows")
    print("python signed_pape_request.py \"gateway.ini\"  \"POST\" \"https://apis-alpha.dev.projectwhite.io/liquidity-providers/807e5a5a-8596-476b-8476-300640a1857b/deposits\" \"{\\\"paymentGatewayId\\\": \\\"cm.wallet.interstellar-demo.xaf\\\", \\\"amount\\\": \\\"10000\\\", \\\"currency\\\": \\\"XAF\\\", \\\"paymentGatewayTransactionId\\\":\\\"7\\\"}\"")
    exit(0)


parsedUrl = urlparse(sys.argv[3])

# our signing payload includes the path of the url, and query
uriWithoutHost = parsedUrl.path
payload = (uriWithoutHost+sys.argv[4]).encode('utf-8')

config = configparser.ConfigParser()
config.read(sys.argv[1])

with open(config['rsa']['privkey_file']) as f:
        key = f.read()
        privkey = RSA.importKey(key)
        signer = Signature_pkcs1_v1_5.new(privkey)
 
        digest = SHA256.new()
        digest.update(payload)
 
        signature = signer.sign(digest)

auth_signature = base64.b64encode(signature)
print("auth_signature: ", auth_signature)




grantpayload = {
    'grant_type': 'password',
    'client_id': config['oauth2']['client_id'],
    'client_secret': '',
    'username': config['user']['username'],
    'password': config['user']['password']
}


 
r = requests.request(sys.argv[2], config['oauth2']['token_url'], 
    headers={"Content-Type":"application/x-www-form-urlencoded"},
    data=grantpayload)

if r.status_code != 200:
    print("auth denied: " + str(r.status_code))
    print(r.content)
    exit(0)

access_token = json.loads(r.content)['access_token']

x = requests.request(sys.argv[2], sys.argv[3], data = sys.argv[4], headers={"Authorization":"Bearer " + access_token, "X-PAPE-SIGNATURE-BASE64": auth_signature})

if x.status_code != 200:
    print("error: " + str(x.status_code))
    print(x.content)
    exit(0)

print(x.content)