HMAC & AES process to follow:

This process explains the secure request,response and header flow using HMAC(Hash-based Message Authentication Code)and AES(Advanced Encryption Standard)for integration with our API platform.It includes header-level HMAC signing for authentication and AES-based payload encryption for secure data exchange.

Headers Required in Each Request:

Header Description
requestTimestamp Epoch timestamp in milliseconds
transactionid Unique transaction ID
merchantId Merchant identifier
orderId Order reference ID
clientId Client authentication key
hmacSecret HMAC signature key
Content-Type Must be application/json

HMAC Request Signature Generation:

Step1:Credentials

clientid:e.g.,client1
secretkey:e.g.,3FF9CBF87A66A452

 

Step2:Prepare HMAC String

hmac_string=String.join("|",method,uri,contentType,accept,traceId,timestamp, payloadHash.toUpperCase());
Example:
POST|/isu/pg/apimerchantOnboarding|application/json|application/json| f8567cd967ed46bfaedd1437f39eb06d|1748337693776| 568364767101810775BC999496C0B33BA7EBEF555A59B96A80DFD8285DA2ABAF

 

Step3:Generate HMAC Value

HMACValue=HMAC-SHA256(hmac_string,secretkey)
ExampleOutput:
a0e73956779d362e039df04af12b45970936074c402bb610401aeafdaeecbc95

 

Step4:Create Authorization Header

Authorization:HMACSignature<space>client_ID:
a0e73956779d362e039df04af12b45970936074c402bb610401aeafdaeecbc95

 

HMAC Validation in Response

Each response includes: Content-Type,Traceid,Timestamp,and Server-Authorization

Step1:Use Same Credentials

clientid=client1(sample)
secretkey=3FF9CBF87A66A452(sample)

 

Step2:Construct Response HMAC String

hmac_string=HTTP-Status+"|"+Content-Type+"|"+Traceid+"|"+Timestamp+"|"+ SHA256(ResponseBody)
 
Example:
200|application/json|a453c1353|20160528121320| C6ED656BCA63C0BE27128D54DEC93F9A615D6E06CD1BEDA5574FD33FCD25E90A

 

Step3:Generate HMAC Value

HMACValue=HMAC-SHA256(hmac_string,secretkey)
ExampleOutput:
a0e73956779d362e039df04af12b45970936074c402bb610401aeafdaeecbc95

 

Step4:Validate Server-Authorization Header

Server-Authorization:HMACSignature
client1:27b0428ea48930dd9831b13161ee0323fcc7c91be7b0ac8ac536fadd3638deed

 

AES Payload Encryption and Decryption

Encryption Overview

Algorithm:AES/CBC/PKCS5Padding
Key: Symmetric key(Base64 Encoded)
IV:Randomly generated 16-byte Initialization Vector Output: Base64 encoded(IV+cipher text)

 

AES Encryption Process

1.Decode Base64 encoded symmetric key
2.Generate 16-byte random IV
3.Encrypt JSON payload using AES/CBC/PKCS5 Padding
4.Concatenate IV + Encrypted bytes Base64 encode the final output

 

AES Decryption Process

1.Decode input(Base64)
2.Split IV(first 16 bytes) and ciphertext
3.Decrypt using AES key and IV
4.Trim/clean decrypted string to remove noise(till last '}'or']')

 

Java Implementation(Sample)

//EncryptMethod

public static String EncryptRequest(Object incomingJsonReq,String key)throws Exception
{
byte[]decodedKey=Base64.getDecoder().decode(key);
byte[]iv=newbyte[16];
newSecureRandom().nextBytes(iv);
Ciphercipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE,newSecretKeySpec(decodedKey, "AES"),newIvParameterSpec(iv));
byte[]encrypted=cipher.doFinal(incomingJsonReq.toString().getBytes());
byte[]result=newbyte[iv.length+encrypted.length];
System.arraycopy(iv,0,result,0, iv.length);
System.arraycopy(encrypted,0,result,iv.length,encrypted.length);
returnBase64.getEncoder().encodeToString(result);
}

 

Java Implementation(Sample)

//DecryptMethod

public String decryptRequest(String encryptedString,String key)throws Exception
{byte[]
byteCipherText=Base64.getDecoder().decode(encryptedString);
byte[]byteKey=Base64.getDecoder().decode(key);
byte[] iv=Arrays.copyOfRange(byteCipherText,0,16);
byte[]cipherText=Arrays.copyOfRange(byteCipherText,16,byteCipherText.length);
Ciphercipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE,new SecretKeySpec(byteKey,"AES"),new IvParameterSpec(iv));
byte[]bytePlainText=cipher.doFinal(cipherText);
return removeNoise(new String(bytePlainText,StandardCharsets.UTF_8).trim());
}
private String removeNoise(String data)
{
int lastCurlyBrace=data.lastIndexOf('}');
int lastSquareBracket=data.lastIndexOf(']');
int lastIndex=Math.max(lastCurlyBrace, lastSquareBracket);
return lastIndex!=-1?data.substring(0,lastIndex+1):data;
}