Code samples to generate and verify signature hash for the data received via Payment Status webhooks sent from PortOne servers..


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

type WebhookResponseObj struct {
    Currency string
    Amount string
    OrderRef string
    MerchantOrderRef string
    CountryCode string
    ChannelOrderRef string
    Status string
    ChannelKey string
    MethodName string
    Signature string
}

func VerifySignature(webhookResponseObj WebhookResponseObj, secretKey string) bool {
    params := make(url.Values)
    params.Add("currency", webhookResponseObj.Currency)
    params.Add("amount", webhookResponseObj.Amount)
    params.Add("order_ref", webhookResponseObj.OrderRef)
    params.Add("merchant_order_ref", webhookResponseObj.MerchantOrderRef)
    params.Add("channel_order_ref", webhookResponseObj.ChannelOrderRef)
    params.Add("country_code", webhookResponseObj.CountryCode)
    params.Add("status", webhookResponseObj.Status)
    params.Add("channel_key", webhookResponseObj.ChannelKey)
    params.Add("method_name", webhookResponseObj.MethodName)

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

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

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

<?php
function VerifySignature($webhookResponseObj, $secretKey) {
  $data = array(
    'currency' =>$webhookResponseObj.Currency,
    'amount' => $webhookResponseObj.Amount,
    'order_ref' => $webhookResponseObj.OrderRef,
    'merchant_order_ref' => $webhookResponseObj.MerchantOrderRef,
    'channel_order_ref'=> $webhookResponseObj.ChannelOrderRef,
    'country_code' => $webhookResponseObj.CountryCode,
    'status' => $webhookResponseObj.Status,
    'channel_key' => $webhookResponseObj.ChannelKey,
    'method_name' => $webhookResponseObj.MethodName
  );

  ksort($data);
  $message = http_build_query($data);
  $hash_value = base64_encode(hash_hmac('sha256', $message, $secretKey, true));

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

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

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

    params.append('currency', webhookResponseObj.Currency)
    params.append('amount', webhookResponseObj.Amount)
    params.append('order_ref', webhookResponseObj.OrderRef)
    params.append('merchant_order_ref', webhookResponseObj.MerchantOrderRef)
    params.append('channel_order_ref', webhookResponseObj.ChannelOrderRef)
    params.append('country_code', webhookResponseObj.CountryCode)
    params.append('status', webhookResponseObj.Status)
    params.append('channel_key', webhookResponseObj.ChannelKey)
    params.append('method_name', webhookResponseObj.MethodName)

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

    if(hash_value !==  webhookResponseObj.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;
using System.Text;
using System.Web;

namespace Signature {
    public class WebhookResponse {
        public string Currency;
        public string Amount;
        public string OrderRef;
        public string MerchantOrderRef;
        public string CountryCode;
        public string ChannelOrderRef;
        public string Status;
        public string ChannelKey;
        public string MethodName;
        public string Signature;
        public WebhookResponse() {}
    }

  public class Signature {

    public static bool VerifySignature(WebhookResponse webhookResponseObj, string secretKey) {

        NameValueCollection parameters = new NameValueCollection();
        // Sequence of params is important here
        parameters.Add("amount", HttpUtility.UrlEncode(webhookResponseObj.Amount));
        parameters.Add("channel_key", HttpUtility.UrlEncode(webhookResponseObj.ChannelKey));
        parameters.Add("channel_order_ref", HttpUtility.UrlEncode(webhookResponseObj.ChannelOrderRef));
        parameters.Add("country_code", HttpUtility.UrlEncode(webhookResponseObj.CountryCode));
        parameters.Add("currency", HttpUtility.UrlEncode(webhookResponseObj.Currency));
        parameters.Add("merchant_order_ref", HttpUtility.UrlEncode(webhookResponseObj.MerchantOrderRef));
        parameters.Add("method_name", HttpUtility.UrlEncode(webhookResponseObj.MethodName));
        parameters.Add("order_ref", HttpUtility.UrlEncode(webhookResponseObj.OrderRef));
        parameters.Add("status", HttpUtility.UrlEncode(webhookResponseObj.Status));
        string data = string.Join("&", Array.ConvertAll(parameters.AllKeys, key => $"{key}={parameters[key]}"));
        Console.WriteLine("data: " + data);
        byte[] secret = Encoding.UTF8.GetBytes(secretKey);
        byte[] message = Encoding.UTF8.GetBytes(data);
        using (HMACSHA256 hash = new HMACSHA256(secret))
        {
            byte[] hashValue = hash.ComputeHash(message);
            string hashValueBase64 = Convert.ToBase64String(hashValue);
            Console.WriteLine("hash_value: " + hashValueBase64);
            if (hashValueBase64 != webhookResponseObj.Signature)
            {
                Console.WriteLine("Hash verification failed, not from valid source");
                return false;
            } else {
                Console.WriteLine("Hash verification success");
                return true;
            }
        }
        return true;
    }

    public static void Main(string[] args) {
        WebhookResponse wr = new WebhookResponse();
        wr.Currency = "PHP";
        wr.Amount = "7299.12";
        wr.OrderRef = "2WsxnsRUq4evFG52utO6Yd7BGQf";
        wr.MerchantOrderRef = "2WsxnGXFObnNXaiZZNf1dqWegFH_1";
        wr.ChannelOrderRef = "6975352881716203803001";
        wr.CountryCode = "PH";
        wr.ChannelKey = "CYBERSOURCE_PH";
        wr.MethodName = "Credit Card";
        wr.Status = "Success";
        wr.Signature = "8S/en9MtbZIAEdAORMxCDdjdos+vOTN+4JlQCQjp528=";

        string Secret = "f993758ef2d10ae67ec8b2519c1df916aa2140d3a13d75e45e792adb03ca6e1a";

        VerifySignature(wr, Secret);
    }
  }
}


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) {
        WebhookResponseObj webhookResponseObj = new WebhookResponseObj(
            "THB", "100", "orderRefValue", "merchantOrderRefValue",
            "US", "channelOrderRefValue", "success", "channelKeyValue",
            "methodNameValue", "signatureValue"
        );
        boolean isValid = verifySignature(webhookResponseObj, "yourSecretKey");
        System.out.println("Is signature valid? " + isValid);
    }

    public static boolean verifySignature(WebhookResponseObj webhookResponseObj, String secretKey) {
        try {
            StringBuilder data = new StringBuilder();
            data.append("amount=").append(webhookResponseObj.getAmount())
                .append("&channel_key=").append(webhookResponseObj.getChannelKey())
                .append("&channel_order_ref=").append(webhookResponseObj.getChannelOrderRef())
                .append("&country_code=").append(webhookResponseObj.getCountryCode())
                .append("&currency=").append(webhookResponseObj.getCurrency())
                .append("&merchant_order_ref=").append(webhookResponseObj.getMerchantOrderRef())
                .append("&method_name=").append(webhookResponseObj.getMethodName())
                .append("&order_ref=").append(webhookResponseObj.getOrderRef())
                .append("&status=").append(webhookResponseObj.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 webhook response
            if (!computedSignature.equals(webhookResponseObj.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 WebhookResponseObj {
    private String currency;
    private String amount;
    private String orderRef;
    private String merchantOrderRef;
    private String countryCode;
    private String channelOrderRef;
    private String status;
    private String channelKey;
    private String methodName;
    private String signature;

    public WebhookResponseObj(String currency, String amount, String orderRef, String merchantOrderRef, String countryCode, String channelOrderRef, String status, String channelKey, String methodName, String signature) {
        this.currency = currency;
        this.amount = amount;
        this.orderRef = orderRef;
        this.merchantOrderRef = merchantOrderRef;
        this.countryCode = countryCode;
        this.channelOrderRef = channelOrderRef;
        this.status = status;
        this.channelKey = channelKey;
        this.methodName = methodName;
        this.signature = signature;
    }

    public String getCurrency() {
        return currency;
    }

    public String getAmount() {
        return amount;
    }

    public String getOrderRef() {
        return orderRef;
    }

    public String getMerchantOrderRef() {
        return merchantOrderRef;
    }

    public String getCountryCode() {
        return countryCode;
    }

    public String getChannelOrderRef() {
        return channelOrderRef;
    }

    public String getStatus() {
        return status;
    }

    public String getChannelKey() {
        return channelKey;
    }

    public String getMethodName() {
        return methodName;
    }

    public String getSignature() {
        return signature;
    }
}

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

class WebhookResponseObj:
    def __init__(self, Currency, Amount, OrderRef, MerchantOrderRef, CountryCode, ChannelOrderRef, Status, ChannelKey, MethodName, Signature):
        # Instance Variable
        self.Currency = Currency
        self.Amount = Amount
        self.OrderRef = OrderRef
        self.MerchantOrderRef = MerchantOrderRef
        self.CountryCode = CountryCode
        self.ChannelOrderRef = ChannelOrderRef
        self.Status = Status
        self.ChannelKey = ChannelKey
        self.MethodName = MethodName
        self.Signature = Signature

def GenerateSignature(WebhookResponseObj, secretKey):

    f = {
        'currency': WebhookResponseObj.Currency,
        'amount': WebhookResponseObj.Amount,
        'order_ref': WebhookResponseObj.OrderRef,
        'merchant_order_ref': WebhookResponseObj.MerchantOrderRef,
        'channel_order_ref': WebhookResponseObj.ChannelOrderRef,
        'country_code': WebhookResponseObj.CountryCode,
        'status': WebhookResponseObj.Status,
        'channel_key': WebhookResponseObj.ChannelKey,
        'method_name': WebhookResponseObj.MethodName,
        }

    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 !== WebhookResponseObj.Signature) {
        Print("Hash verification failed, not from valid source")
        return false;
    } else {
        Print("Hash verification succeded")
        return true;
    }