Generate Hash

A hash is an encrypted value (checksum) that is sent by you in a payment request and reverted by PayU in the payment response. The hash is used to protect transactions against a “man-in-the-middle-attack.”

📘

Hashing logic for Web Integration and SDK is different

For the hashing logic in Android SDK or iOS SKD, refer to Generate Dynamic Hash.

Hash Generation Logic for Basic Payment Request

PayU uses the SHA-512 hash function that belongs to the SHA-2 family of cryptographic functions to generate hash values.

To generate hash for a payment request in general:

  1. Collect Transaction Data: Gather the required transaction details, including: 
  • key: Your merchant key (Test or Production key).
  • txnid: Unique transaction ID 
  • amount: Transaction amount 
  • productinfo: Product information 
  • firstname: Customer's first name 
  • email: Customer's email ID
  • Salt: Your Salt (Test or Production)

📘

Reference:

For more information on getting key and salt, refer to Access Test Merchant Key and Salt or Access Production Key and Salt.

  1. Create a Hash String: Concatenate the collected data in the following format: 
    sha512(key|txnid|amount|productinfo|firstname|email|||||||||||SALT) 
  2. Generate Hash: Use the SHA512 encryption algorithm to generate a hash of the concatenated string. 

Example Hash Generation

Suppose the transaction data is: 

  • key: gtKFFx 
  • txnid: 123456789 
  • amount: 10.00 
  • productinfo: Test Product 
  • firstname: John 
  • email: [email protected] 
  • Salt: <Salt>

The concatenated string would be: 

gtKFFx|123456789|10.00|Test Product|John|[email protected]|||||||||||| <Salt> 

📘

Important Notes:

  • Ensure that the hash is generated using the SHA512 encryption algorithm. 
  • The hash should be generated on the server-side to prevent tampering. 
  • The hash should be verified on the PayU server to ensure the authenticity of the transaction data. 
  • Salt is a susceptible information. Do not pass Salt in the payment request. 
  • PayU recommends you to use Merchant Salt (Version 2). To know more about generating salt, that is Merchant Salt (Version 2), see Generate PayU key and Salt.

🚧

Salt Security

Salt is a susceptible information. Do not pass Salt in the payment request. To know more about generating salt, see Generate Merchant Key and Salt on PayU Dashboard.

Sample code for generating hash

<?php
function generateHash($key, $txnid, $amount, $productinfo, $firstname, $email, $salt) {
    $input = $key . '|' . $txnid . '|' . $amount . '|' . $productinfo . '|' . $firstname . '|' . $email . '|||||||||||' . $salt;
    return hash('sha512', $input);
}

// Example usage
$key = 'yourKey';
$txnid = 'yourTxnId';
$amount = 'yourAmount';
$productinfo = 'yourProductInfo';
$firstname = 'yourFirstName';
$email = 'yourEmail';
$salt = 'yourSalt';

$hash = generateHash($key, $txnid, $amount, $productinfo, $firstname, $email, $salt);
echo 'Generated Hash: ' . $hash;
?>

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class HashGenerator {

    public static String generateHash(String key, String txnid, String amount, String productinfo, String firstname, String email, String salt) {
        String input = key + "|" + txnid + "|" + amount + "|" + productinfo + "|" + firstname + "|" + email + "|||||||||||" + salt;
        return sha512(input);
    }

    private static String sha512(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
            StringBuilder sb = new StringBuilder();
            for (byte b : hashBytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        // Example usage
        String key = "yourKey";
        String txnid = "yourTxnId";
        String amount = "yourAmount";
        String productinfo = "yourProductInfo";
        String firstname = "yourFirstName";
        String email = "yourEmail";
        String salt = "yourSalt";

        String hash = generateHash(key, txnid, amount, productinfo, firstname, email, salt);
        System.out.println("Generated Hash: " + hash);
    }
}

using System;
using System.Security.Cryptography;
using System.Text;

public class HashGenerator
{
    public static string GenerateHash(string key, string txnid, string amount, string productinfo, string firstname, string email, string salt)
    {
        string input = $"{key}|{txnid}|{amount}|{productinfo}|{firstname}|{email}|||||||||||{salt}";
        return Sha512(input);
    }

    private static string Sha512(string input)
    {
        using (SHA512 sha512 = SHA512.Create())
        {
            byte[] bytes = sha512.ComputeHash(Encoding.UTF8.GetBytes(input));
            StringBuilder sb = new StringBuilder();
            foreach (byte b in bytes)
            {
                sb.Append(b.ToString("x2"));
            }
            return sb.ToString();
        }
    }

    public static void Main(string[] args)
    {
        // Example usage
        string key = "yourKey";
        string txnid = "yourTxnId";
        string amount = "yourAmount";
        string productinfo = "yourProductInfo";
        string firstname = "yourFirstName";
        string email = "yourEmail";
        string salt = "yourSalt";

        string hash = GenerateHash(key, txnid, amount, productinfo, firstname, email, salt);
        Console.WriteLine("Generated Hash: " + hash);
    }
}

import hashlib

def generate_hash(key, txnid, amount, productinfo, firstname, email, salt):
    input_str = f"{key}|{txnid}|{amount}|{productinfo}|{firstname}|{email}|||||||||||{salt}"
    return hashlib.sha512(input_str.encode('utf-8')).hexdigest()

# Example usage
key = 'yourKey'
txnid = 'yourTxnId'
amount = 'yourAmount'
productinfo = 'yourProductInfo'
firstname = 'yourFirstName'
email = 'yourEmail'
salt = 'yourSalt'

hash_value = generate_hash(key, txnid, amount, productinfo, firstname, email, salt)
print("Generated Hash:", hash_value)
const crypto = require('crypto');

function generateHash(key, txnid, amount, productinfo, firstname, email, salt) {
    const input = `${key}|${txnid}|${amount}|${productinfo}|${firstname}|${email}|||||||||||${salt}`;
    return crypto.createHash('sha512').update(input).digest('hex');
}

// Example usage
const key = 'yourKey';
const txnid = 'yourTxnId';
const amount = 'yourAmount';
const productinfo = 'yourProductInfo';
const firstname = 'yourFirstName';
const email = 'yourEmail';
const salt = 'yourSalt';

const hash = generateHash(key, txnid, amount, productinfo, firstname, email, salt);
console.log("Generated Hash:", hash);

📘

Reference:

You can use the Hash API of the PayU node SDK on Github to perform hashing. Refer to the PayU node SDK Readme, download and install the PayU node SDK from the PayU node SDK Github location.

Hashing scenarios for payment request

Here, we will discuss some payment request scenarios and see how hash calculation varies for each of them:

  • Scenario 1: When all the udf parameters (udf1-udf5) are posted by the merchant, hash is calculated as:
sha512(key\|txnid\|amount\|productinfo\|firstname\|email\|udf1\|udf2\|udf3\|udf4\|udf5\|\|\|\|\|\|SALT)
  • Scenario 2: If only some of the udf parameters are posted . For example, if udf2 and udf4 are posted and udf1, udf3, udf5 are not, hash is calculated as:
sha512(key\|txnid\|amount\|productinfo\|firstname\|email\|\|udf2\|\|udf4\|\|\|\|\|\|\|SALT)
  • Scenario 3: If none of the udf parameters (udf1-udf5) are posted, hash is calculated as:
sha512(key\|txnid\|amount\|productinfo\|firstname\|email\|\|\|\|\|\|\|\|\|\|\|SALT)

📘

Delimiters when UDF parameters are not passed:

Ensure that you include the delimiters (pipe symbol: |) if you don't pass the UDF parameters, so you need to ensure that 5 delimiters are included if UDF parameters are not passed. There are 15 delimiters in total.

Tips for Hashing
  • In the test environment (payu.test.in), PayU displays the error message and the correct action required to resolve the error.
  • However, in the live environment, to retain the confidentiality of the business information, PayU displays only an error message and drops the transaction.
  • It has been observed that a majority of the hash mismatch errors result from an incorrect key insert by the merchant’s developers while generating the hash value. For instance:
Inserting Merchant ID (MID) instead of Merchant Keysha512(411112345110001 Shopping I Vinay I [email protected] I 3****s*k****h*j)
Inserting SALT instead of Merchant Key & Merchant ID in place of SALTsha512(3****s*k****h*[email protected] |411)

In these cases, while PayU will compile the hash value with the right positioning of the merchant key and salt in the string, it will be different from the one posted by the merchant for apparent reasons, leading to a mismatch.

  • PayU advises against sending the salt value as part of the payment request package, as it severely compromises the security of the transaction. Because, with access to the salt, a malicious actor executing a man-in-the-middle (MITM) attack can easily alter the details, regenerate the hash value, and can pass the same through the authentication filters in the PayU’s servers.

Hash Validation Logic for Payment Response (Reverse Hashing)

While sending the response, PayU takes the exact same parameters that were sent in the request (in reverse order) to calculate the hash and returns it to you. You must verify the hash and then mark a transaction as a success or failure. This is to make sure the transaction has not tampered within the response.

The order of the parameters is similar to the following code block:

sha512(SALT|status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key)

Note: You can use the Hash API of the PayU node SDK on Github to perform reverse hashing. Refer to the PayU node SDK Readme, download and install the PayU node SDK from the PayU node SDK Github location.

Integration Security

After receiving a response from PayU, you must calculate the hash again and validate it against the hash that you sent in the request to ensure the transaction is secure. PayU recommends implementing the transaction details APIs and webhook/callback as an extra security measure. You can find more information on this process in the Transaction Detail APIs and Webhooks.

You need to ensure that sensitive information related to the integration is not part of the payment request to PayU. The details including — but are not limited to — the following are considered sensitive information:

  • salt value
  • plain text hash string

Along with the request, the sensitive information should not be a part of any merchant-level URL. The following are considered sources for the merchant-level URL:

  • The last web address accessed by a browser before loading PayU’s checkout page.
  • URLs shared as part of payment request to PayU in the parameters: surl, furl, curl, nurl, and termUrl.
  • Notification URLs configured with the merchant account.
  • Invoice Completion URLs configured with the merchant account.

📘

Note:

It is important to compare the parameters sent by PayU in the response with the ones you sent in the request to make sure none of them have been changed. You should verify specific parameters such as the transaction ID and amount. PayU is not responsible for any security breaches or losses resulting from your failure to implement the necessary security measures.