Merchants can follow the steps below to verify a signature:
Step 1: Extract the timestamp and signatures from the header irembopay-signature. Split the header using the , character as the separator, to get a list of elements. Then split each element, using the = character as the separator, to get a prefix and value pair. The value for the prefix t corresponds to the timestamp, and s corresponds to the signature
Step 2: Prepare the signed_payload string. The signed_payload string is created by concatenating: The timestamp (as a string), the character # and the actual JSON payload (the request body).
Step 3: Determine the expected signature. Compute an HMAC with the SHA256 hash function. Use the merchant’s secret key as the key and use the signed_payload string as the message.
Step 4: Compare the signatures. Compare the signature in the header to the expected signature. Optionally, you can also check if the timestamp is not too far from the current time to prevent replay attacks.
const crypto = require('crypto');
function verifySignature(secretKey, payload, signatureHeader) {
// Step 1: Extract the timestamp and signatures from the header
const elements = signatureHeader.split(',');
let timestamp = null;
let signatureHash = null;
elements.forEach(element => {
const [prefix, value] = element.split('=');
if (prefix === 't') {
timestamp = value;
} else if (prefix === 's') {
signatureHash = value;
}
});
if (!timestamp || !signatureHash) {
return false;
}
// Step 2: Prepare the signed_payload string
const signedPayload = `${timestamp}#${payload}`;
// Step 3: Determine the expected signature
const expectedSignature = crypto.createHmac('sha256', secretKey)
.update(signedPayload)
.digest('hex');
// Step 4: Compare the signatures
const isSignatureValid = crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'hex'),
Buffer.from(signatureHash, 'hex')
);
// Optionally check if the timestamp is not too far from the current time
const currentTime = Date.now(); // Current time in milliseconds
const timestampInt = parseInt(timestamp, 10);
if (Math.abs(currentTime - timestampInt) > 300 * 1000) { // 5 minutes tolerance in milliseconds
return false;
}
return isSignatureValid;
}
// Example usage
const headerValue = "t=1653405045000,s=bfecb20753326e5e8602f4a6e727bcd22b7cb1d00797fe5bd65db8cfaf2f4903";
const secretKey = "your_secret_key_here";
const requestBody = '{"key": "value"}';
const isValid = verifySignature(secretKey, requestBody,headerValue);
console.log("Signature is valid:", isValid);
import hmac
import hashlib
import time
def verify_signature(secret_key, payload, signature_header):
# Step 1: Extract the timestamp and signatures from the header
elements = signature_header.split(',')
timestamp = None
signature_hash = None
for element in elements:
prefix, value = element.split('=')
if prefix == 't':
timestamp = value
elif prefix == 's':
signature_hash = value
if timestamp is None or signature_hash is None:
return False
# Step 2: Prepare the signed_payload string
signed_payload = f'{timestamp}#{payload}'
# Step 3: Determine the expected signature
expected_signature = hmac.new(
key=secret_key.encode(),
msg=signed_payload.encode(),
digestmod=hashlib.sha256
).hexdigest()
# Step 4: Compare the signatures
is_signature_valid = hmac.compare_digest(expected_signature, signature_hash)
# Optionally check if the timestamp is not too far from the current time
current_time = int(time.time() * 1000) # Convert current time to milliseconds
timestamp_int = int(timestamp)
if abs(current_time - timestamp_int) > 300 * 1000: # 5 minutes tolerance in milliseconds
return False
return is_signature_valid
# Example usage
secret_key = 'secret_key'
payload = 'request_payload'
signature_header = 'signature_header'
is_valid = verify_signature(secret_key, payload, signature_header)
print(f'Signature valid: {is_valid}')
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class SignatureVerifier {
public static boolean verifySignature(String secretKey, String payload, String signatureHeader) {
// Step 1: Extract the timestamp and signatures from the header
String[] elements = signatureHeader.split(",");
String timestamp = null;
String signatureHash = null;
for (String element : elements) {
String[] parts = element.split("=");
String prefix = parts[0];
String value = parts[1];
if (prefix.equals("t")) {
timestamp = value;
} else if (prefix.equals("s")) {
signatureHash = value;
}
}
if (timestamp == null || signatureHash == null) {
return false;
}
// Step 2: Prepare the signed_payload string
String signedPayload = timestamp + "#" + payload;
// Step 3: Determine the expected signature
String expectedSignature = null;
try {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKeySpec);
byte[] rawHmac = mac.doFinal(signedPayload.getBytes(StandardCharsets.UTF_8));
expectedSignature = bytesToHex(rawHmac);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
return false;
}
// Step 4: Compare the signatures
boolean isSignatureValid = expectedSignature.equals(signatureHash);
// Optionally check if the timestamp is not too far from the current time
long currentTime = System.currentTimeMillis(); // Current time in milliseconds
long timestampInt = Long.parseLong(timestamp);
if (Math.abs(currentTime - timestampInt) > 300 * 1000) { // 5 minutes tolerance in milliseconds
return false;
}
return isSignatureValid;
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2);
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
// Example usage
public static void main(String[] args) {
String secretKey = "your_secret_key_here";
String payload = "{\"key\": \"value\"}";
String signatureHeader = "signature_header_here";
boolean isValid = verifySignature(secretKey, payload, signatureHeader);
System.out.println("Signature valid: " + isValid);
}
}