Payment Response

To ensure the integrity and authenticity of payment responses, you can use signature verification. The signature is a cryptographic hash generated using a secret key and the content of the payment response.

Steps for Signature Verification

  1. Extract Signature: Extract the signature from the payment response.
  2. Extract Data: Extract the relevant data fields from the payment response.
  3. Recreate Message: Recreate the message by concatenating the extracted data fields.
  4. Compute Signature: Compute the signature using the same algorithm and secret key used for generating the original signature.
  5. Compare Signatures: Compare the extracted signature with the computed signature.
  6. Verification: If the two signatures match, the payment response is considered valid. Otherwise, it may have been tampered with.

Example Code (Python)


import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
)

type PaymentResponse struct {
    OrderRef string
    ChannelOrderRef string
    MerchantOrderRef string
    Status string
    Signature string
}

func VerifySignature(paymentResponse PaymentResponse, secretKey string) bool {
    params := make(url.Values)
    params.Add("order_ref", paymentResponse.OrderRef)
    params.Add("channel_order_ref", paymentResponse.ChannelOrderRef)
    params.Add("merchant_order_ref", paymentResponse.MerchantOrderRef)
    params.Add("status", paymentResponse.Status)

    data = params.Encode()
    secret := []byte(secretKey)
    message := []byte(data)

    hash := hmac.New(sha256.New, secret)
    hash.Write(message)
    hash_value := base64.StdEncoding.EncodeToString(hash.Sum(nil))

    // compare this hash_value to one received in payment response
    if hash_value != paymentResponse.Signature {
        println("Hash verification failed, not from valid source")
        return false
    } else {
        println("Hash verification succeded")
        return true
    }
}

<?php
function VerifySignature($responseObj, $secretKey) {
  $signature_hash = $responseObj['signature_hash'];
      $data = array(
          'order_ref' => $responseObj['order_ref'],
          'merchant_order_ref' => $responseObj['merchant_order_ref'],
          'channel_order_ref' => $responseObj['channel_order_ref'],
          'status' => $responseObj['status'],
      );
  }
  ksort($data);
  $message = http_build_query($data);
  $hash_value = base64_encode(hash_hmac('sha256', $message, $secretKey, true));

  if ($hash_value !== $signature_hash) {
      echo "Hash verification failed, not from valid source";
      return false;
  } else {
      echo "Hash verification succeeded";
      return true;
  }
}
?>

var url = require('url');
var crypto = require('crypto');

function VerifySignature(responseObj, secretKey) {
    const params = new URLSearchParams();

    params.append('order_ref', responseObj.order_ref);
    params.append('channel_order_ref', responseObj.channel_order_ref);
    params.append('merchant_order_ref', responseObj.merchant_order_ref);
    params.append('status', responseObj.status);

    params.sort();
    var message = params.toString()
    var hash_value =  crypto.createHmac('sha256', secretKey).update(message).hash.digest('base64');

    if(hash_value !==  responseObj.signature_hash){
      console.log("Hash verification failed, not from valid source")
      return false;
    } else{
      console.log("Hash verification succeded")
      return true;
    }
}

using System;
using System.Security.Cryptography;
using System.Collections.Specialized;

class PaymentResponse {
  string OrderRef,
  string ChannelOrderRef,
  string MerchantOrderRef,
  string Status,
  string Signature,
}

namespace Signature {
  public class Signature {
    private bool VerifySignature(PaymentResponse paymentResponse, string secret) {

      NameValueCollection myCollection = System.Web.HttpUtility.ParseQueryString(string.Empty);
      myCollection.Add("order_ref", paymentResponse.OrderRef);
      myCollection.Add("channel_order_ref", paymentResponse.ChannelOrderRef);
      myCollection.Add("merchant_order_ref", paymentResponse.MerchantOrderRef);
      myCollection.Add("status", paymentResponse.Status);

      string message = myCollection.ToString();
      var encoding = new System.Text.ASCIIEncoding();
      byte[] keyByte = encoding.GetBytes(secret);
      byte[] messageBytes = encoding.GetBytes(message);
      var hmacsha256 = new HMACSHA256(keyByte);
      byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
      string hash_value = Convert.ToBase64String(hashmessage);

      if (hash_value !== paymentResponse.Signature) {
        Console.WriteLine("Hash verification failed, not from valid source")
        return false;
      } else {
        Console.WriteLine("Hash verification succeded")
        return true;
      }
    }
  }
}

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        PaymentResponse paymentResponse = new PaymentResponse("orderRefValue", "channelOrderRefValue", "merchantOrderRefValue", "statusValue", "signatureValue");
        boolean isValid = verifySignature(paymentResponse, "yourSecretKey");
        System.out.println("Is signature valid? " + isValid);
    }

    public static boolean verifySignature(PaymentResponse paymentResponse, String secretKey) {
        try {
            StringBuilder data = new StringBuilder();
            data.append("order_ref=").append(paymentResponse.getOrderRef())
                    .append("&channel_order_ref=").append(paymentResponse.getChannelOrderRef())
                    .append("&merchant_order_ref=").append(paymentResponse.getMerchantOrderRef())
                    .append("&status=").append(paymentResponse.getStatus());

            byte[] secret = secretKey.getBytes();
            byte[] message = data.toString().getBytes();

            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(secret, "HmacSHA256");
            sha256_HMAC.init(secretKeySpec);

            byte[] hash = sha256_HMAC.doFinal(message);
            String computedSignature = Base64.getEncoder().encodeToString(hash);

            // Compare computed signature to the one received in payment response
            if (!computedSignature.equals(paymentResponse.getSignature())) {
                System.out.println("Hash verification failed, not from a valid source");
                return false;
            } else {
                System.out.println("Hash verification succeeded");
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

class PaymentResponse {
    private String orderRef;
    private String channelOrderRef;
    private String merchantOrderRef;
    private String status;
    private String signature;

    public PaymentResponse(String orderRef, String channelOrderRef, String merchantOrderRef, String status, String signature) {
        this.orderRef = orderRef;
        this.channelOrderRef = channelOrderRef;
        this.merchantOrderRef = merchantOrderRef;
        this.status = status;
        this.signature = signature;
    }

    public String getOrderRef() {
        return orderRef;
    }

    public String getChannelOrderRef() {
        return channelOrderRef;
    }

    public String getMerchantOrderRef() {
        return merchantOrderRef;
    }

    public String getStatus() {
        return status;
    }

    public String getSignature() {
        return signature;
    }
}

#!/usr/bin/python
# -*- coding: utf-8 -*-
import urllib
import hashlib
import hmac
import base64

class responseObj:   
    def __init__(self, OrderRef, ChannelOrderRef, MerchantOrderRef, Status, Signature):
        # Instance Variable    
        self.OrderRef = OrderRef
        self.ChannelOrderRef = ChannelOrderRef    
        self.MerchantOrderRef = MerchantOrderRef 
        self.Status = Status
        self.Signature = Signature

def GenerateSignature(responseObj, secretKey):

    f = {
        'order_ref': responseObj.OrderRef,
        'channel_order_ref': responseObj.ChannelOrderRef,
        'merchant_order_ref': responseObj.MerchantOrderRef,
        'status': responseObj.Status,
        }
   
    message1 = urllib.urlencode(f)
    message = bytes(message1).encode('utf-8')
    secret = bytes(secretKey).encode('utf-8')
    signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())


    if (signature !== responseObj.Signature) {
        Print("Hash verification failed, not from valid source")
        return false;
    } else {
        Print("Hash verification succeded")
        return true;
    }