From 9bd69b57f49c8096970a1226f289bceb0949fb8d Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Sun, 10 May 2026 20:34:06 +0530 Subject: [PATCH 1/3] 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); + } +} From 0e146a145a449534cdbb793175acbfef3e9ec837 Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Wed, 13 May 2026 09:45:29 +0530 Subject: [PATCH 2/3] fix: update negative tests to match SDK behavior SDK returns false for invalid signatures instead of throwing exceptions. Update tests to assert false instead of expecting exceptions. Co-Authored-By: Claude Opus 4.7 --- .../java/com/razorpay/UtilsNegativeTest.java | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/src/test/java/com/razorpay/UtilsNegativeTest.java b/src/test/java/com/razorpay/UtilsNegativeTest.java index 1d2e478c..f4d6f186 100644 --- a/src/test/java/com/razorpay/UtilsNegativeTest.java +++ b/src/test/java/com/razorpay/UtilsNegativeTest.java @@ -27,45 +27,29 @@ private String computeSignature(String payload, String secret) throws Exception } @Test - public void testEmptySignatureRejected() { - try { - Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, "", WEBHOOK_SECRET); - fail("Expected RazorpayException for empty signature"); - } catch (RazorpayException e) { - // Expected - } + public void testEmptySignatureRejected() throws RazorpayException { + boolean result = Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, "", WEBHOOK_SECRET); + assertFalse("Empty signature should be rejected", result); } @Test - public void testWrongLengthSignatureRejected() { - try { - Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, "abc123", WEBHOOK_SECRET); - fail("Expected RazorpayException for wrong length signature"); - } catch (RazorpayException e) { - // Expected - } + public void testWrongLengthSignatureRejected() throws RazorpayException { + boolean result = Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, "abc123", WEBHOOK_SECRET); + assertFalse("Wrong length signature should be rejected", result); } @Test - public void testNonHexSignatureRejected() { + public void testNonHexSignatureRejected() throws RazorpayException { 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 - } + boolean result = Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, nonHexSig, WEBHOOK_SECRET); + assertFalse("Non-hex signature should be rejected", result); } @Test - public void testTamperedValidHexSignatureRejected() { + public void testTamperedValidHexSignatureRejected() throws RazorpayException { 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 - } + boolean result = Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, tamperedSig, WEBHOOK_SECRET); + assertFalse("Tampered signature should be rejected", result); } @Test From e0fb060bf7151b26ca11821f9cf99a4f8c44cb62 Mon Sep 17 00:00:00 2001 From: Vaibhav Chopra Date: Wed, 13 May 2026 09:53:31 +0530 Subject: [PATCH 3/3] Rename misleading test methods in UtilsNegativeTest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - testWrongLengthSignatureRejected → testMismatchedSignatureRejected - testNonHexSignatureRejected → testWrongValueSignatureRejected Added comments clarifying these tests pass because values don't match, not because the SDK validates hex format or signature length. Co-Authored-By: Claude Opus 4.7 --- src/test/java/com/razorpay/UtilsNegativeTest.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/test/java/com/razorpay/UtilsNegativeTest.java b/src/test/java/com/razorpay/UtilsNegativeTest.java index f4d6f186..7da7fe18 100644 --- a/src/test/java/com/razorpay/UtilsNegativeTest.java +++ b/src/test/java/com/razorpay/UtilsNegativeTest.java @@ -33,16 +33,18 @@ public void testEmptySignatureRejected() throws RazorpayException { } @Test - public void testWrongLengthSignatureRejected() throws RazorpayException { + public void testMismatchedSignatureRejected() throws RazorpayException { + // Short string that doesn't match the computed HMAC boolean result = Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, "abc123", WEBHOOK_SECRET); - assertFalse("Wrong length signature should be rejected", result); + assertFalse("Mismatched signature should be rejected", result); } @Test - public void testNonHexSignatureRejected() throws RazorpayException { - String nonHexSig = new String(new char[64]).replace('\0', 'z'); - boolean result = Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, nonHexSig, WEBHOOK_SECRET); - assertFalse("Non-hex signature should be rejected", result); + public void testWrongValueSignatureRejected() throws RazorpayException { + // 64-char string with invalid chars - rejected because value doesn't match, not because of hex validation + String wrongSig = new String(new char[64]).replace('\0', 'z'); + boolean result = Utils.verifyWebhookSignature(WEBHOOK_PAYLOAD, wrongSig, WEBHOOK_SECRET); + assertFalse("Wrong value signature should be rejected", result); } @Test