Skip to content

ClickPesa/clickpesa-api-checksum-demo

Repository files navigation

ClickPesa Checksum Demo

A multi-language project for creating and validating HMAC-SHA256 checksums for payload integrity verification. Available in JavaScript/Node.js, Python, PHP, Java, and Go.

Features

  • ✅ Create HMAC-SHA256 checksums for any payload object
  • ✅ Validate checksums against payloads
  • ✅ Consistent checksum generation regardless of object key order
  • Full cross-language interoperability - checksums created in one language can be validated by any other
  • ✅ Comprehensive test suite for all languages
  • ✅ Example usage demonstrations
  • ✅ Multi-language support (JavaScript, Python, PHP, Java, Go)

Project Structure

The project is organized by language for better visibility:

clickpesa-checksum-demo/
├── javascript/          # JavaScript/Node.js implementation
│   ├── checksum.js
│   ├── checksum.test.js
│   ├── example.js
│   ├── package.json
│   └── node_modules/
├── python/              # Python implementation
│   ├── checksum.py
│   ├── checksum_test.py
│   ├── example.py
│   └── requirements.txt
├── php/                 # PHP implementation
│   ├── checksum.php
│   ├── checksum_test.php
│   ├── example.php
│   └── composer.json
├── java/                # Java implementation
│   ├── pom.xml
│   └── src/
│       ├── main/java/com/clickpesa/
│       │   ├── Checksum.java
│       │   └── Example.java
│       └── test/java/com/clickpesa/
│           └── ChecksumTest.java
├── go/                  # Go implementation
│   ├── checksum.go
│   ├── checksum_test.go
│   ├── example.go
│   └── go.mod
└── README.md

How It Works

  1. Payload Sorting: Object keys are sorted alphabetically to ensure consistent checksum generation regardless of key order
  2. String Serialization: The canonicalized payload is serialized to JSON
  3. HMAC Generation: HMAC-SHA256 is applied using the provided secret key
  4. Hexadecimal Output: The result is returned as a 64-character hexadecimal string

Key Features

  • Order Independence: The same checksum is generated regardless of object key order
  • Tamper Detection: Any modification to the payload or key will result in a different checksum
  • Secure: Uses HMAC-SHA256 for cryptographic security
  • Cross-Language Compatible: Checksums created in one language can be validated by any other language implementation

💡 Interoperability: All implementations produce identical checksums for the same input. See INTEROPERABILITY.md for details and examples.


JavaScript/Node.js

Installation

npm install --prefix javascript

Usage

const { createPayloadChecksum, validateChecksum } = require('./checksum');

// Create a checksum
const payload = { amount: 100, currency: "USD", reference: "TX123" };
const checksumKey = "secret-key";
const checksum = createPayloadChecksum(checksumKey, payload);

console.log('Checksum:', checksum);

// Validate a checksum
const isValid = validateChecksum(checksumKey, payload, checksum);
console.log('Valid:', isValid); // true

Running

# Run the example demonstration
npm start --prefix javascript

# Run tests
npm test --prefix javascript

API Reference

createPayloadChecksum(checksumKey, payload)

Creates an HMAC-SHA256 checksum for the given payload.

Parameters:

  • checksumKey (string): The secret key for HMAC generation
  • payload (Object): The payload object to create checksum for

Returns: string - Hexadecimal checksum

validateChecksum(checksumKey, payload, receivedChecksum)

Validates a checksum against a payload.

Parameters:

  • checksumKey (string): The secret key for HMAC generation
  • payload (Object): The payload object to validate
  • receivedChecksum (string): The checksum to validate against

Returns: boolean - True if checksum is valid, false otherwise


Python

Installation

Python 3.7+ is required. No external dependencies needed (uses standard library only).

# No installation needed - uses standard library

Usage

from checksum import create_payload_checksum, validate_checksum

# Create a checksum
payload = {"amount": 100, "currency": "USD", "reference": "TX123"}
checksum_key = "secret-key"
checksum = create_payload_checksum(checksum_key, payload)

print('Checksum:', checksum)

# Validate a checksum
is_valid = validate_checksum(checksum_key, payload, checksum)
print('Valid:', is_valid)  # True

Running

# Run tests
PYTHONPATH=python python3 -m unittest checksum_test
# or
PYTHONPATH=python python3 python/checksum_test.py

# Run example
PYTHONPATH=python python3 python/example.py

API Reference

create_payload_checksum(checksum_key: str, payload: dict) -> str

Creates an HMAC-SHA256 checksum for the given payload.

Parameters:

  • checksum_key (str): The secret key for HMAC generation
  • payload (dict): The payload dictionary to create checksum for

Returns: str - Hexadecimal checksum

Raises: ValueError if checksum_key is empty or payload is None

validate_checksum(checksum_key: str, payload: dict, received_checksum: str) -> bool

Validates a checksum against a payload.

Parameters:

  • checksum_key (str): The secret key for HMAC generation
  • payload (dict): The payload dictionary to validate
  • received_checksum (str): The checksum to validate against

Returns: bool - True if checksum is valid, false otherwise


PHP

Installation

PHP 7.4+ is required. No external dependencies needed for the checksum functions (uses standard library only).

Installing PHP:

If PHP is not installed on your system:

# macOS (using Homebrew)
brew install php

# Ubuntu/Debian
sudo apt-get install php

# Or download from: https://www.php.net/downloads.php

Optional - For running tests only:

If you want to run the PHPUnit tests, install Composer and PHPUnit:

# Install Composer (if not already installed)
# See: https://getcomposer.org/download/

# Then install PHPUnit for testing
composer install --working-dir=php

Note: The checksum functions work without Composer - they use PHP's built-in hash_hmac() function.

Usage

<?php
require_once 'checksum.php';

// Create a checksum
$payload = ["amount" => 100, "currency" => "USD", "reference" => "TX123"];
$checksumKey = "secret-key";
$checksum = createPayloadChecksum($checksumKey, $payload);

echo "Checksum: " . $checksum . "\n";

// Validate a checksum
$isValid = validateChecksum($checksumKey, $payload, $checksum);
echo "Valid: " . ($isValid ? "true" : "false") . "\n"; // true
?>

Running

# Run example (no dependencies needed)
php php/example.php

# Run tests (requires Composer/PHPUnit - optional)
(cd php && php vendor/bin/phpunit)
# or with explicit config
(cd php && php vendor/bin/phpunit --configuration phpunit.xml)

API Reference

createPayloadChecksum(string $checksumKey, array $payload): string

Creates an HMAC-SHA256 checksum for the given payload.

Parameters:

  • $checksumKey (string): The secret key for HMAC generation
  • $payload (array): The payload array to create checksum for

Returns: string - Hexadecimal checksum

Throws: InvalidArgumentException if checksum_key is empty or payload is null

validateChecksum(string $checksumKey, array $payload, string $receivedChecksum): bool

Validates a checksum against a payload.

Parameters:

  • $checksumKey (string): The secret key for HMAC generation
  • $payload (array): The payload array to validate
  • $receivedChecksum (string): The checksum to validate against

Returns: bool - True if checksum is valid, false otherwise


Java

Installation

Java 11+ and Maven are required.

Installing Java and Maven:

If Java or Maven are not installed on your system:

# macOS (using Homebrew)
brew install openjdk@11 maven

# Ubuntu/Debian
sudo apt-get install openjdk-11-jdk maven

# Or download from:
# Java: https://adoptium.net/
# Maven: https://maven.apache.org/download.cgi

Build the project:

mvn clean install -f java/pom.xml

Usage

import com.clickpesa.Checksum;
import java.util.HashMap;
import java.util.Map;

// Create a checksum
Map<String, Object> payload = new HashMap<>();
payload.put("amount", 100);
payload.put("currency", "USD");
payload.put("reference", "TX123");

String checksumKey = "secret-key";
String checksum = Checksum.createPayloadChecksum(checksumKey, payload);

System.out.println("Checksum: " + checksum);

// Validate a checksum
boolean isValid = Checksum.validateChecksum(checksumKey, payload, checksum);
System.out.println("Valid: " + isValid); // true

Running

# Compile the project first
mvn compile -f java/pom.xml

# Run tests
mvn test -f java/pom.xml

# Run example (after compilation)
mvn exec:java -f java/pom.xml
# Or with explicit main class:
mvn exec:java -Dexec.mainClass="com.clickpesa.Example" -f java/pom.xml

API Reference

Checksum.createPayloadChecksum(String checksumKey, Map<String, Object> payload): String

Creates an HMAC-SHA256 checksum for the given payload.

Parameters:

  • checksumKey (String): The secret key for HMAC generation
  • payload (Map<String, Object>): The payload map to create checksum for

Returns: String - Hexadecimal checksum

Throws: IllegalArgumentException if checksumKey is empty or payload is null

Checksum.validateChecksum(String checksumKey, Map<String, Object> payload, String receivedChecksum): boolean

Validates a checksum against a payload.

Parameters:

  • checksumKey (String): The secret key for HMAC generation
  • payload (Map<String, Object>): The payload map to validate
  • receivedChecksum (String): The checksum to validate against

Returns: boolean - True if checksum is valid, false otherwise


Go

Installation

Go 1.21+ is required.

Installing Go:

If Go is not installed on your system:

# macOS (using Homebrew)
brew install go

# Ubuntu/Debian
sudo apt-get install golang-go

# Or download from: https://go.dev/dl/

Note: Go modules are automatically managed when running go commands - no separate installation step needed for dependencies.

Usage

package main

import (
    "fmt"
)

func main() {
    // Create a checksum
    payload := map[string]interface{}{
        "amount":    100,
        "currency":  "USD",
        "reference": "TX123",
    }
    checksumKey := "secret-key"

    checksum, err := CreatePayloadChecksum(checksumKey, payload)
    if err != nil {
        panic(err)
    }

    fmt.Println("Checksum:", checksum)

    // Validate a checksum
    isValid, err := ValidateChecksum(checksumKey, payload, checksum)
    if err != nil {
        panic(err)
    }

    fmt.Println("Valid:", isValid) // true
}

Running

# Run tests (from project root)
(cd go && go test -v)
# or
go test -C go -v

# Run the example
go run go/example.go go/checksum.go

API Reference

CreatePayloadChecksum(checksumKey string, payload map[string]interface{}) (string, error)

Creates an HMAC-SHA256 checksum for the given payload.

Parameters:

  • checksumKey (string): The secret key for HMAC generation
  • payload (map[string]interface{}): The payload map to create checksum for

Returns: (string, error) - Hexadecimal checksum and error (if any)

Error: Returns error if checksumKey is empty or payload is nil

ValidateChecksum(checksumKey string, payload map[string]interface{}, receivedChecksum string) (bool, error)

Validates a checksum against a payload.

Parameters:

  • checksumKey (string): The secret key for HMAC generation
  • payload (map[string]interface{}): The payload map to validate
  • receivedChecksum (string): The checksum to validate against

Returns: (bool, error) - True if checksum is valid, false otherwise, and error (if any)


Testing

All implementations include comprehensive tests covering:

  • Consistent checksum generation
  • Validation accuracy
  • Edge cases (empty payloads, special characters, numeric values)
  • Order independence
  • Tamper detection
  • Nested objects

Running Tests

# JavaScript/Node.js
npm test --prefix javascript

# Python
PYTHONPATH=python python3 -m unittest checksum_test
# or
PYTHONPATH=python python3 python/checksum_test.py

# PHP (requires Composer/PHPUnit - optional)
(cd php && php vendor/bin/phpunit)

# Java
mvn test -f java/pom.xml

# Go
(cd go && go test -v)
# or
go test -C go -v

Example Output

=== ClickPesa Checksum Demo ===

Payload: {
  "amount": 100,
  "currency": "USD",
  "reference": "TX123"
}
Checksum Key: secret-key

Generated Checksum: a1b2c3d4e5f6...

--- Validation Test 1 (Valid checksum) ---
Validation Result: ✅ Valid

--- Validation Test 2 (Invalid checksum) ---
Validation Result: ❌ Invalid

--- Validation Test 3 (Different payload order) ---
Reordered Payload: {
  "reference": "TX123",
  "amount": 100,
  "currency": "USD"
}
Validation Result: ✅ Valid

--- Validation Test 4 (Modified payload) ---
Modified Payload: {
  "amount": 200,
  "currency": "USD",
  "reference": "TX123"
}
Validation Result: ❌ Invalid

License

ISC

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors