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.
- ✅ 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)
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
- Payload Sorting: Object keys are sorted alphabetically to ensure consistent checksum generation regardless of key order
- String Serialization: The canonicalized payload is serialized to JSON
- HMAC Generation: HMAC-SHA256 is applied using the provided secret key
- Hexadecimal Output: The result is returned as a 64-character hexadecimal string
- 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.
npm install --prefix javascriptconst { 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# Run the example demonstration
npm start --prefix javascript
# Run tests
npm test --prefix javascriptCreates an HMAC-SHA256 checksum for the given payload.
Parameters:
checksumKey(string): The secret key for HMAC generationpayload(Object): The payload object to create checksum for
Returns: string - Hexadecimal checksum
Validates a checksum against a payload.
Parameters:
checksumKey(string): The secret key for HMAC generationpayload(Object): The payload object to validatereceivedChecksum(string): The checksum to validate against
Returns: boolean - True if checksum is valid, false otherwise
Python 3.7+ is required. No external dependencies needed (uses standard library only).
# No installation needed - uses standard libraryfrom 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# Run tests
PYTHONPATH=python python3 -m unittest checksum_test
# or
PYTHONPATH=python python3 python/checksum_test.py
# Run example
PYTHONPATH=python python3 python/example.pyCreates an HMAC-SHA256 checksum for the given payload.
Parameters:
checksum_key(str): The secret key for HMAC generationpayload(dict): The payload dictionary to create checksum for
Returns: str - Hexadecimal checksum
Raises: ValueError if checksum_key is empty or payload is None
Validates a checksum against a payload.
Parameters:
checksum_key(str): The secret key for HMAC generationpayload(dict): The payload dictionary to validatereceived_checksum(str): The checksum to validate against
Returns: bool - True if checksum is valid, false otherwise
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.phpOptional - 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=phpNote: The checksum functions work without Composer - they use PHP's built-in hash_hmac() function.
<?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
?># 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)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
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 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.cgiBuild the project:
mvn clean install -f java/pom.xmlimport 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# 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.xmlCreates an HMAC-SHA256 checksum for the given payload.
Parameters:
checksumKey(String): The secret key for HMAC generationpayload(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 generationpayload(Map<String, Object>): The payload map to validatereceivedChecksum(String): The checksum to validate against
Returns: boolean - True if checksum is valid, false otherwise
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.
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
}# 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.goCreates an HMAC-SHA256 checksum for the given payload.
Parameters:
checksumKey(string): The secret key for HMAC generationpayload(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 generationpayload(map[string]interface{}): The payload map to validatereceivedChecksum(string): The checksum to validate against
Returns: (bool, error) - True if checksum is valid, false otherwise, and error (if any)
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
# 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=== 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
ISC