🔐 Encryption Library
🛡️ HesabeCrypt Implementation
This section provides the complete HesabeCrypt implementation in multiple programming languages, featuring industry-standard AES-256-CBC encryption for secure data transmission.
⚠️Important Note
The encryption and decryption code snippets are provided in PHP, JavaScript, and TypeScript for better integration options.
🔒 Encryption Methods
- PHP
- JavaScript
- TypeScript
<?php
namespace App\Libraries;
class HesabeCrypt {
// AES Encryption Method Starts
public static function encrypt($str, $key, $ivKey)
{
$str = self::pkcs5_pad($str);
$encrypted = openssl_encrypt($str, 'AES-256-CBC', $key, OPENSSL_ZERO_PADDING, $ivKey);
$encrypted = base64_decode($encrypted);
$encrypted = unpack('C*', ($encrypted));
$encrypted = self::byteArray2Hex($encrypted);
$encrypted = urlencode($encrypted);
return $encrypted;
}
private static function pkcs5_pad($text)
{
$blocksize = 32;
$pad = $blocksize - (strlen($text) % $blocksize);
return $text.str_repeat(chr($pad), $pad);
}
private static function byteArray2Hex($byteArray)
{
$chars = array_map("chr", $byteArray);
$bin = join($chars);
return bin2hex($bin);
}
}
1. Create HesabeCrypt.js file
"use strict";
const aesjs = require("aes-js");
class HesabeCrypt {
constructor(secret, iv) {
this.key = secret;
this.iv = iv;
}
encryptAes(txt) {
var txtBytes = aesjs.padding.pkcs7.pad(aesjs.utils.utf8.toBytes(txt));
var aesCbc = new aesjs.ModeOfOperation.cbc(this.key, this.iv);
var encBytes = aesCbc.encrypt(txtBytes);
var encHex = aesjs.utils.hex.fromBytes(encBytes);
return encHex;
}
decryptAes(encHex) {
var encBytes = aesjs.utils.hex.toBytes(encHex);
var aesCbc = new aesjs.ModeOfOperation.cbc(this.key, this.iv);
var decBytes = aesCbc.decrypt(encBytes);
var decTxt = aesjs.utils.utf8.fromBytes(decBytes);
var strippedTxt = this.pkcs5Strip(decTxt);
return strippedTxt;
}
pkcs5Pad(data) {
var blockSize = 32;
var padLen = blockSize - (data.length % blockSize);
var paddedTxt = (data + this.strRepeat(String.fromCharCode(padLen), padLen));
return paddedTxt;
}
pkcs5Strip(data) {
var dataLen = data.length;
if (dataLen < 32) {
throw new Error('Invalid data length. Block size must be 32 bytes');
}
var padderCodeInt = parseInt(data.charCodeAt(dataLen - 1));
if (padderCodeInt > 32) {
throw new Error('PKCS#5 padding byte out of range');
}
var len = dataLen - padderCodeInt;
var strippedTxt = data.substr(0, len);
return strippedTxt;
}
strRepeat(input, multiplier) {
var y = '';
while (true) {
if (multiplier & 1) {
y += input;
}
multiplier >>= 1;
if (multiplier) {
input += input
} else {
break;
}
}
return y;
}
}
export default HesabeCrypt;
2. import HesabeCrypt.js file
import aesjs from "aes-js";
import hesabeCrypt from "../HesabeCrypt.js";
export const getEncryptedData = value => {
let secret_key = 'XXXXX' // Secret key provided by Hesabe
let iv_key = 'XXXXX' // IV key provided by Hesabe
if(value) {
let secret = secret_key // merchant secret key
let ivCode = iv_key // merchant iv code
let key = aesjs.utils.utf8.toBytes(secret);
let iv = aesjs.utils.utf8.toBytes(ivCode);
let instance = new hesabeCrypt(key, iv);
let text = value;
let encrypted = instance.encryptAes(JSON.stringify(text));
let encrypted_data = encrypted;
return encrypted_data;
}
};
1. Create HesabeCrypt.ts
import * as aesjs from "aes-js";
/**
* AES-CBC encrypt/decrypt helper using PKCS#7 (byte) padding.
* Hesabe gateway payloads are typically sent as hex strings.
*/
export class HesabeCrypt {
private static readonly BLOCK_SIZE = 16; // AES block size in bytes
/**
* Encrypts a UTF-8 string and returns ciphertext hex.
*/
encryptAes(plainText: string, key: Uint8Array, iv: Uint8Array): string {
// Convert to bytes
const plainBytes = aesjs.utils.utf8.toBytes(plainText);
// Pad to 16-byte boundary
const padded = this.pkcs7Pad(plainBytes);
const aesCbc = new aesjs.ModeOfOperation.cbc(key, iv);
const encBytes = aesCbc.encrypt(padded);
return aesjs.utils.hex.fromBytes(encBytes);
}
/**
* Decrypts ciphertext hex and returns UTF-8 string (unpadded).
*/
decryptAes(cipherHex: string, key: Uint8Array, iv: Uint8Array): string {
const encBytes = aesjs.utils.hex.toBytes(cipherHex);
const aesCbc = new aesjs.ModeOfOperation.cbc(key, iv);
const decBytes = aesCbc.decrypt(encBytes);
const unpadded = this.pkcs7Strip(decBytes);
return aesjs.utils.utf8.fromBytes(unpadded);
}
/**
* PKCS#7 padding on bytes.
*/
private pkcs7Pad(data: Uint8Array): Uint8Array {
const padLen = HesabeCrypt.BLOCK_SIZE - (data.length % HesabeCrypt.BLOCK_SIZE || HesabeCrypt.BLOCK_SIZE);
const out = new Uint8Array(data.length + padLen);
out.set(data);
out.fill(padLen, data.length);
return out;
}
/**
* Remove PKCS#7 padding from bytes.
*/
private pkcs7Strip(data: Uint8Array): Uint8Array {
if (data.length === 0 || data.length % HesabeCrypt.BLOCK_SIZE !== 0) {
throw new Error("Invalid decrypted data length.");
}
const padLen = data[data.length - 1];
if (padLen < 1 || padLen > HesabeCrypt.BLOCK_SIZE || padLen > data.length) {
throw new Error("Invalid PKCS#7 padding.");
}
// Validate all pad bytes (optional but safer)
for (let i = data.length - padLen; i < data.length; i++) {
if (data[i] !== padLen) throw new Error("Invalid PKCS#7 padding bytes.");
}
return data.subarray(0, data.length - padLen);
}
}
2. USE encrypted method
declare class hesabeCrypt {
constructor(key: Uint8Array, iv: Uint8Array);
encryptAes(data: string): string;
}
export const getEncryptedData = (value: unknown): string | null => {
const secretKey = "XXXXX"; // Secret key provided by Hesabe
const ivKey = "XXXXX"; // IV key provided by Hesabe
if (!value) {
return null;
}
const key: Uint8Array = aesjs.utils.utf8.toBytes(secretKey);
const iv: Uint8Array = aesjs.utils.utf8.toBytes(ivKey);
const instance = new hesabeCrypt(key, iv);
const text = JSON.stringify(value);
const encrypted: string = instance.encryptAes(text);
return encrypted;
};
🔓 Decryption Methods
- PHP
- JavaScript
- TypeScript
<?php
// Decryption Method for AES Algorithm Starts
public static function decrypt($code, $key, $ivKey)
{
if (!(ctype_xdigit($code) && strlen($code) % 2 == 0)) {
return false;
}
$code = self::hex2ByteArray(trim($code));
$code = self::byteArray2String($code);
$iv = $key;
$code = base64_encode($code);
$decrypted = openssl_decrypt($code, 'AES-256-CBC', $key, OPENSSL_ZERO_PADDING, $ivKey);
return self::pkcs5_unpad($decrypted);
}
private static function hex2ByteArray($hexString)
{
$string = hex2bin($hexString);
return unpack('C*', $string);
}
private static function byteArray2String($byteArray)
{
$chars = array_map("chr", $byteArray);
return join($chars);
}
private static function pkcs5_unpad($text)
{
$pad = ord($text{strlen($text) - 1});
if ($pad > strlen($text)) {
return false;
}
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) {
return false;
}
return substr($text, 0, -1 * $pad);
}
import aesjs from "aes-js";
import hesabeCrypt from "../HesabeCrypt.js";
export const getDecryptedData = value => {
let secret_key = 'XXXXX' // Secret key provided by Hesabe
let iv_key = 'XXXXX' // IV key provided by Hesabe
if(value) {
let secret = secret_key // merchant secret key
let ivCode = iv_key // merchant iv code
let key = aesjs.utils.utf8.toBytes(secret);
let iv = aesjs.utils.utf8.toBytes(ivCode);
let instance = new hesabeCrypt(key, iv);
let text = value;
let decrypted = instance.decryptAes(text);
let decrypted_data = JSON.parse(decrypted);
return decrypted_data;
}
};
import * as aesjs from "aes-js";
import hesabeCrypt from "../HesabeCrypt.ts";
declare class hesabeCrypt {
constructor(key: Uint8Array, iv: Uint8Array);
decryptAes(data: string): string;
}
export const getDecryptedData = <T = unknown>(value: string | null): T | null => {
const secretKey = "XXXXX"; // Secret key provided by Hesabe
const ivKey = "XXXXX"; // IV key provided by Hesabe
if (!value) {
return null;
}
const key: Uint8Array = aesjs.utils.utf8.toBytes(secretKey);
const iv: Uint8Array = aesjs.utils.utf8.toBytes(ivKey);
const instance = new hesabeCrypt(key, iv);
const decrypted: string = instance.decryptAes(value);
const decryptedData: T = JSON.parse(decrypted);
return decryptedData;
};
🔧 Usage Examples
✅
Security Features
🔐
AES-256-CBCIndustry standard encryption
🛡️
PKCS5 PaddingSecure data padding
🔑
IV Key SupportEnhanced security vector