External Adapter Encryption and Decryption
To protect the content of data sent to an External Adapter, The message body content is first encrypted using the AES-CBC Algorithm. This uses both an Encryption Key along with a random Initialization Vector (IV). A separate Authentication Key is used to calculate a hash on the encrypted message body. The random IV and the Hash are sent along with the message as a header. This allows the message to be both decrypted and then validated as coming from a trustworthy source.
Securing a Custom External Adapter
Decrypting a Message
Your adapter implementation (or wherever you relay the messages to if your interface is acting as a proxy) must implement the ability to Decrypt and Authenticate messages received from the Fenergo Saas platform. The process for decryption is illustrated below, all languages support AES and HASH algorithms
C# Code to Decrypt and Authenticate Message
public string dencryptAESBody()
{
//KEYS are NOT Shown but are referred to as "base64EncryptionKey" and "base64AuthKey"
//Assume they are defined elsewhere in the code.
string passedIVinBase64 = "NF/xcZ21LhFIwA31q5oMzw==";
string passedMAC = "DEL/vVP8qD8feLtJCptnyI4ZYHRMDZ8zjkZk3AZRAnw=";
string cipherText = "UE30wHm2NrYnKkXBO4TLWdxxxp/QQLY1t1qFyJb3juEIZ+kh00z" +
"uQ68k8HiPxdlFX9wrrQWgCgjJ/kDhZcnYqTTADXWCzgLH9KCVGf19nz8Yn0XNbzeKiL" +
"QCvPeIq92UJIIDbon+3eMdOcQ7TOg54jaI6A/2U7A8qWXPbxkEhkd12kKJ4xq4Kg/jf" +
"lnhDzyKjmhYKzC46CIbk9AecRIvla1oowqqzNKAOdDbu+Vqr9A=";
using var aesAlgorithm = Aes.Create();
aesAlgorithm.Key = Convert.FromBase64String(base64EncryptionKey); //Reading a key from your Keystore
aesAlgorithm.IV = Convert.FromBase64String(passedIVinBase64); //passed in from the header x-encryption-iv
Console.WriteLine($"Aes Cipher Mode : {aesAlgorithm.Mode}");
Console.WriteLine($"Aes Padding Mode: {aesAlgorithm.Padding}");
Console.WriteLine($"Aes Key Size : {aesAlgorithm.KeySize}");
Console.WriteLine($"Aes Block Size : {aesAlgorithm.BlockSize}");
//Passed in from the Message Body - Convery to byte[] for decryption
byte[] cipherTextinByteArrayFormat = Convert.FromBase64String(cipherText);
var encryptor = aesAlgorithm.CreateDecryptor();
var cipherTextConvertedFromBase64 = Convert.FromBase64String(cipherText);
using var memoryStream = new MemoryStream();
using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(cipherTextConvertedFromBase64, 0, cipherTextConvertedFromBase64.Length);
cryptoStream.FlushFinalBlock();
var plaintext = memoryStream.ToArray();
//Authenticate the Sender by calculating the HMAC from the ciphertext
using var hmacSha = new HMACSHA256(Convert.FromBase64String(base64AuthKey)); //Decode Base64 Auth Key
var calculatedHMAC = hmacSha.ComputeHash(cipherTextinByteArrayFormat);
Console.WriteLine("Calculated Mac : " + Convert.ToBase64String(calculatedHMAC));
Console.WriteLine("Recieved Mac : " + passedMAC); //Passed in from the header x-authentication-mac
//Decrypted Data made readable with UTF8 Encoding
Console.WriteLine("Decrypted : " + Encoding.UTF8.GetString(plaintext));
//Send back plaintext
return Encoding.UTF8.GetString(plaintext);
}
The message which was sent was a Test from the Legal Entity Screening Domain. The output from the above code block is as follows:
Aes Padding Mode: PKCS7
Aes Key Size : 256
Aes Block Size : 128
Calculated Mac : DEL/vVP8qD8feLtJCptnyI4ZYHRMDZ8zjkZk3AZRAnw=
Recieved Mac : DEL/vVP8qD8feLtJCptnyI4ZYHRMDZ8zjkZk3AZRAnw=
Decrypted : {
"Data":
{
"AdditionalSettings":[]
},
"Id":"d4b89b85-827c-4d09-bc3e-1cbb39d52a4c",
"Tenant":"45bf62ac-e4b1-4c16-ae32-d774cd18db6d",
"ProviderId":"TestScreening",
"Type":"Test"
}
Python Code to Decrypt and Authenticate Message
import base64
from Crypto.Cipher import AES
from Crypto.Hash import HMAC
from Crypto.Util.Padding import unpad
from io import BytesIO
def decrypt_AES_body():
# KEYS are NOT Shown but are referred to as "base64EncryptionKey" and "base64AuthKey"
# Assume they are defined elsewhere in the code.
passed_IV_in_Base64 = "NF/xcZ21LhFIwA31q5oMzw=="
passed_MAC = "DEL/vVP8qD8feLtJCptnyI4ZYHRMDZ8zjkZk3AZRAnw="
cipher_text = "UE30wHm2NrYnKkXBO4TLWdxxxp/QQLY1t1qFyJb3juEIZ+kh00z" \
"uQ68k8HiPxdlFX9wrrQWgCgjJ/kDhZcnYqTTADXWCzgLH9KCVGf19nz8Yn0XNbzeKiL" \
"QCvPeIq92UJIIDbon+3eMdOcQ7TOg54jaI6A/2U7A8qWXPbxkEhkd12kKJ4xq4Kg/jf" \
"lnhDzyKjmhYKzC46CIbk9AecRIvla1oowqqzNKAOdDbu+Vqr9A="
# Reading a key from your Keystore
encryption_key = base64.b64decode(base64EncryptionKey)
iv = base64.b64decode(passed_IV_in_Base64) # passed in from the header x-encryption-iv
aes_algorithm = AES.new(encryption_key, AES.MODE_CBC, iv)
printf("AES Cipher Mode: {aes_algorithm.mode}")
printf("AES Padding Mode: {aes_algorithm.padding.name}")
printf("AES Key Size: {aes_algorithm.key_size}")
printf("AES Block Size: {aes_algorithm.block_size}")
# Convert cipher text from base64 to bytes for decryption
cipher_text_bytes = base64.b64decode(cipher_text)
# Decrypt cipher text
plaintext = aes_algorithm.decrypt(cipher_text_bytes)
plaintext = unpad(plaintext, AES.block_size)
# Authenticate the Sender by calculating the HMAC from the ciphertext
hmac_sha = HMAC.new(base64.b64decode(base64AuthKey)) # Decode Base64 Auth Key
calculated_hmac = hmac_sha.digest()
print("Calculated Mac:", base64.b64encode(calculated_hmac).decode())
print("Received Mac:", passed_MAC) # Passed in from the header x-authentication-mac
print("Decrypted:", plaintext.decode())
# Send back plaintext
return plaintext.decode()
Encrypting and Signing a Message
C# Code to Encrypt and Sign Message
public async Task encryptAESBody()
{
//STEP - 1 Prepare The Message
var plaintext = "{ \"response\":{ }, \"id\":\"d4b89b85-827c-4d09-bc3e-1cbb39d52a4c\", " +
"\"tenant\":\"xxxxxxx-Your-Tenant-Id-xxxxxx\", \"providerId\":\"TestScreening\", " +
"\"type\":\"Test\", \"status\":\"Success\", \"errorDetails\":null }";
byte[] plaintextAsByteArray = Encoding.UTF8.GetBytes(plaintext);
//STEP - 2 Gnerate IV and Encrypt Message Bodye
using var aesAlgorithm = Aes.Create();
aesAlgorithm.Key = Convert.FromBase64String(base64EncryptionKey); //Reading a key from your Keystore
aesAlgorithm.GenerateIV();
aesAlgorithm.Mode = CipherMode.CBC;
var encryptor = aesAlgorithm.CreateEncryptor();
using var memoryStream = new MemoryStream();
using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
cryptoStream.Write(plaintextAsByteArray, 0, plaintextAsByteArray.Length);
cryptoStream.FlushFinalBlock();
var cipherText = memoryStream.ToArray();
//STEP - 3 Calculate the Authentication Hash
using var hmacSha = new HMACSHA256(Convert.FromBase64String(base64AuthKey));
var calculatedHMAC = hmacSha.ComputeHash(cipherText);
Console.WriteLine("Base64 IV : " + Convert.ToBase64String(aesAlgorithm.IV));
Console.WriteLine("Base64 MAC : " + Convert.ToBase64String(calculatedHMAC));
Console.WriteLine("Base64 Body : " + Convert.ToBase64String(cipherText));
//STEP - 4 & 5 Add the Headers and Send The Message
//Your Code Implementation to Send Encrypted Message
}
The output from the above code block is as follows:
Base64 IV : /O0hpcmWjzWrCxpvwAp1fA==
Base64 MAC : NfXp/n8vpevd+V7uc/ORKSZ7HIqUo2fQwIebCATb7Mg=
Base64 Body : tnktn65X7Niu6ZU7nn8W/O4gFq1fd+EUk9uMzbqMLB7DOfisUMGkXtxuhFd+PYTaTk2+LNss8tn50AC5K1cONVDRJylyAffMGmG2ihRNNYIZk+UU2ch3NLve5ZDqiH6xXJoOaVTfqgPvSuWyu96gDTpohqSTobtc/CItO473ioQnrOkwxKIzjDcP+c8rb5mE8pSTYpI10+NuaEzKUGwEVULRp+wCBvWdxwHfF7786Ad6lqpGfpqvOOut0gelLoEYWvQOQy0tWgsR8Ez49UBxOg==
Python Code to Encrypt and Sign Message
import base64
import hashlib
from Crypto.Cipher import AES
from Crypto.Hash import HMAC
from Crypto.Util.Padding import pad
from io import BytesIO
async def encrypt_AES_body():
# STEP - 1 Prepare The Message
plaintext = "{ \"response\":{ }, \"id\":\"d4b89b85-827c-4d09-bc3e-1cbb39d52a4c\", " \
"\"tenant\":\"xxxxxxx-Your-Tenant-Id-xxxxxx\", \"providerId\":\"TestScreening\", " \
"\"type\":\"Test\", \"status\":\"Success\", \"errorDetails\":null }"
plaintext_as_byte_array = plaintext.encode('utf-8')
# STEP - 2 Generate IV and Encrypt Message Body
aes_algorithm = AES.new(base64.b64decode(base64EncryptionKey), AES.MODE_CBC)
iv = aes_algorithm.iv
encryptor = aes_algorithm.encryptor()
# Encrypt plaintext
cipher_text_bytes = encryptor.update(pad(plaintext_as_byte_array, AES.block_size)) + encryptor.finalize()
# STEP - 3 Calculate the Authentication Hash
hmac_sha = HMAC.new(base64.b64decode(base64AuthKey), digestmod=hashlib.sha256)
hmac_sha.update(cipher_text_bytes)
calculated_hmac = hmac_sha.digest()
print("Base64 IV :", base64.b64encode(iv).decode())
print("Base64 MAC :", base64.b64encode(calculated_hmac).decode())
print("Base64 Body :", base64.b64encode(cipher_text_bytes).decode())
# STEP - 4 & 5 Add the Headers and Send The Message
# Your Code Implementation to Send Encrypted Message