From 9bd69b57f49c8096970a1226f289bceb0949fb8d Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Sun, 10 May 2026 20:34:06 +0530 Subject: [PATCH] test: add negative-path crypto utility tests Add comprehensive tests for signature verification edge cases: - Empty signature rejection - Wrong length signature rejection - Non-hex signature rejection - Tampered valid-length hex signature rejection - Valid dynamic signature acceptance - Special characters in payload - Unicode in payload Co-Authored-By: Claude Opus 4.7 --- .../java/com/razorpay/UtilsNegativeTest.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/test/java/com/razorpay/UtilsNegativeTest.java diff --git a/src/test/java/com/razorpay/UtilsNegativeTest.java b/src/test/java/com/razorpay/UtilsNegativeTest.java new file mode 100644 index 00000000..1d2e478c --- /dev/null +++ b/src/test/java/com/razorpay/UtilsNegativeTest.java @@ -0,0 +1,93 @@ +package com.razorpay; + +import org.junit.Test; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import static org.junit.Assert.*; + +public class UtilsNegativeTest { + + private static final String WEBHOOK_PAYLOAD = "{\"event\":\"payment.authorized\"}"; + private static final String WEBHOOK_SECRET = "test_webhook_secret"; + + private String computeSignature(String payload, String secret) throws Exception { + Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); + SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"); + sha256_HMAC.init(secretKey); + byte[] hash = sha256_HMAC.doFinal(payload.getBytes("UTF-8")); + StringBuilder hexString = new StringBuilder(); + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) hexString.append('0'); + hexString.append(hex); + } + return hexString.toString(); + } + + @Test + public void testEmptySignatureRejected() { + try { + Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, "", WEBHOOK_SECRET); + fail("Expected RazorpayException for empty signature"); + } catch (RazorpayException e) { + // Expected + } + } + + @Test + public void testWrongLengthSignatureRejected() { + try { + Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, "abc123", WEBHOOK_SECRET); + fail("Expected RazorpayException for wrong length signature"); + } catch (RazorpayException e) { + // Expected + } + } + + @Test + public void testNonHexSignatureRejected() { + String nonHexSig = new String(new char[64]).replace('\0', 'z'); + try { + Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, nonHexSig, WEBHOOK_SECRET); + fail("Expected RazorpayException for non-hex signature"); + } catch (RazorpayException e) { + // Expected + } + } + + @Test + public void testTamperedValidHexSignatureRejected() { + String tamperedSig = new String(new char[64]).replace('\0', 'a'); + try { + Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, tamperedSig, WEBHOOK_SECRET); + fail("Expected RazorpayException for tampered signature"); + } catch (RazorpayException e) { + // Expected + } + } + + @Test + public void testValidDynamicSignatureAccepted() throws Exception { + String validSig = computeSignature(WEBHOOK_PAYLOAD, WEBHOOK_SECRET); + boolean result = Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, validSig, WEBHOOK_SECRET); + assertTrue("Valid signature should be accepted", result); + } + + @Test + public void testSpecialCharsInPayload() throws Exception { + String specialPayload = "{\"event\":\"payment\",\"data\":{\"notes\":\"Test & \"}}"; + String validSig = computeSignature(specialPayload, WEBHOOK_SECRET); + boolean result = Utils.verifyWebhookSignature(specialPayload, validSig, WEBHOOK_SECRET); + assertTrue("Special chars payload should verify", result); + } + + @Test + public void testUnicodeInPayload() throws Exception { + String unicodePayload = "{\"event\":\"payment\",\"data\":{\"name\":\"日本語テスト\"}}"; + String validSig = computeSignature(unicodePayload, WEBHOOK_SECRET); + boolean result = Utils.verifyWebhookSignature(unicodePayload, validSig, WEBHOOK_SECRET); + assertTrue("Unicode payload should verify", result); + } +}