Examples
Credentials Required
In order to use the Quick Quotes via Encrypted URLs functionality, you will require a Partner ID and encryption keys provided by the Aventus Platform. Please contact us to get these.
The step-by-step example below shows the necessary steps in encrypting, signing & formatting the payload with the expected outcome at each step (base64-encoded) for prepa
This example uses the following keys, you must replace these with your own keys as provided by Aventus Platform:
Encryption key | DbU0fQQc5IbF4v9a/KUvMrzF2EWGhnp7Ussb4GvWk9M= |
Authentication key | HPqKD+TDmsZPuKSZHSmpZT+Y2nGsZ7uijy1NesJWbyU= |
Random 16 bytes Initialisation Vector (IV) | 6AimI+hLvyAuxLlTlGN0pg== |
The process
Step | Description | Outcome |
---|---|---|
1 | Construct the JSON payload | {"firstName":"John","lastName":"Doe","dateOfBirth":"1970-01-01T00:00:00Z","emailAddress":"[email protected]","phoneNumber":"07000123456","address1": "1 Anchor Road","address2":"Kingsclere","town":"Newbury","postalCode":"RG20 5NE","partnerReference":"01F0B37A-E056-4415-93D9-03F75506EE17","nonce":"u_KDhf2j79jCjDZ-ArFqHXOKqaC.B9sZ","timestamp","2018-10-19T11:35:20Z"} |
2 | Encrypt the JSON with encryption key + IV | FYOX4sfwwshBs9sxACOP8W2Fez9shCP4eYUB0oTJf7/KbD5vh92G3Y/f/u3rzebHRO60guu9qY17Z+vnQMREZPR0EzzGa5yyzvD9UuHoPR/MiiLyLcAHphAts6QWhpuosfY8mCoSd9p+Sp365LZkjXAIa/JWSMVa981Ykriedr7Pz2bLtsbkc0JF7M2Yq483mOIZtCKq997UsAEulXNQ2y75hpNu+g1898/65YThcd7YDJ8d/0QQ/69JRgTFPtVak4EyIhUTUViW7FhuifYDw4sjhmlBxclyy/zsRGdQrG13GAtDKdgl2Upg/QKWsMiNKhSnKtQ/cDDjJqs8y+MQ/XrKPrNEpSor4ltLIC1b/Sj5Z/0I+DPh0F3Z9wcqBObjVOjN7mFHsQDcZRLG6xWt2V9QqhFF7Ka6Gi0f6BXVlWQx8X2umOjrDD+M+8t8i/aVMGkYQiag0bUkdY77qXjvVCe4Ke/dpGyJZyuHy7YC19o= |
3.1 | Concatenate IV + cipher | 6AimI+hLvyAuxLlTlGN0phWDl+LH8MLIQbPbMQAjj/FthXs/bIQj+HmFAdKEyX+/ymw+b4fdht2P3/7t683mx0TutILrvamNe2fr50DERGT0dBM8xmucss7w/VLh6D0fzIoi8i3AB6YQLbOkFoabqLH2PJgqEnfafkqd+uS2ZI1wCGvyVkjFWvfNWJK4nna+z89my7bG5HNCRezNmKuPN5jiGbQiqvfe1LABLpVzUNsu+YaTbvoNfPfP+uWE4XHe2AyfHf9EEP+vSUYExT7VWpOBMiIVE1FYluxYbon2A8OLI4ZpQcXJcsv87ERnUKxtdxgLQynYJdlKYP0ClrDIjSoUpyrUP3Aw4yarPMvjEP16yj6zRKUqK+JbSyAtW/0o+Wf9CPgz4dBd2fcHKgTm41Toze5hR7EA3GUSxusVrdlfUKoRReymuhotH+gV1ZVkMfF9rpjo6ww/jPvLfIv2lTBpGEImoNG1JHWO+6l471QnuCnv3aRsiWcrh8u2Atfa |
3.2 | Compute hash | cTwKkvrFuYjZHEpCtAWocg9+1KslEka0zIbw+K0D6Wc= |
3.3 | Concatenate IV + cipher + hash | 6AimI+hLvyAuxLlTlGN0phWDl+LH8MLIQbPbMQAjj/FthXs/bIQj+HmFAdKEyX+/ymw+b4fdht2P3/7t683mx0TutILrvamNe2fr50DERGT0dBM8xmucss7w/VLh6D0fzIoi8i3AB6YQLbOkFoabqLH2PJgqEnfafkqd+uS2ZI1wCGvyVkjFWvfNWJK4nna+z89my7bG5HNCRezNmKuPN5jiGbQiqvfe1LABLpVzUNsu+YaTbvoNfPfP+uWE4XHe2AyfHf9EEP+vSUYExT7VWpOBMiIVE1FYluxYbon2A8OLI4ZpQcXJcsv87ERnUKxtdxgLQynYJdlKYP0ClrDIjSoUpyrUP3Aw4yarPMvjEP16yj6zRKUqK+JbSyAtW/0o+Wf9CPgz4dBd2fcHKgTm41Toze5hR7EA3GUSxusVrdlfUKoRReymuhotH+gV1ZVkMfF9rpjo6ww/jPvLfIv2lTBpGEImoNG1JHWO+6l471QnuCnv3aRsiWcrh8u2AtfacTwKkvrFuYjZHEpCtAWocg9+1KslEka0zIbw+K0D6Wc= |
4 | URL encode | 6AimI%2bhLvyAuxLlTlGN0phWDl%2bLH8MLIQbPbMQAjj%2fFthXs%2fbIQj%2bHmFAdKEyX%2b%2fymw%2bb4fdht2P3%2f7t683mx0TutILrvamNe2fr50DERGT0dBM8xmucss7w%2fVLh6D0fzIoi8i3AB6YQLbOkFoabqLH2PJgqEnfafkqd%2buS2ZI1wCGvyVkjFWvfNWJK4nna%2bz89my7bG5HNCRezNmKuPN5jiGbQiqvfe1LABLpVzUNsu%2bYaTbvoNfPfP%2buWE4XHe2AyfHf9EEP%2bvSUYExT7VWpOBMiIVE1FYluxYbon2A8OLI4ZpQcXJcsv87ERnUKxtdxgLQynYJdlKYP0ClrDIjSoUpyrUP3Aw4yarPMvjEP16yj6zRKUqK%2bJbSyAtW%2f0o%2bWf9CPgz4dBd2fcHKgTm41Toze5hR7EA3GUSxusVrdlfUKoRReymuhotH%2bgV1ZVkMfF9rpjo6ww%2fjPvLfIv2lTBpGEImoNG1JHWO%2b6l471QnuCnv3aRsiWcrh8u2AtfacTwKkvrFuYjZHEpCtAWocg9%2b1KslEka0zIbw%2bK0D6Wc%3d |
Example Code
const int keySize = 256;
const int blockSize = 128;
const CipherMode cipherMode = CipherMode.CBC;
const PaddingMode paddingMode = PaddingMode.PKCS7;
const int ivLength = 16;
static Random random = new Random();
static void Main(string[] args)
{
var nonce = GenerateNonce();
var utcNow = DateTime.UtcNow.ToString("o");
var input = $@"{{""firstName"":""John"",""lastName"":""Doe"",""dateOfBirth"":""1970-01-01T00:00:00Z"",""emailAddress"":""[email protected]"",""phoneNumber"":""07000123456"",""address1"":""1 Anchor Road"",""address2"":""Kingsclere"",""town"":""Newbury"",""postalCode"":""RG20 5NE"",""partnerReference"":""01F0B37A-E056-4415-93D9-03F75506EE17"",""nonce"":""{nonce}"",""timestamp"":""{utcNow}""}}";
var encryptionKey = Convert.FromBase64String("DbU0fQQc5IbF4v9a/KUvMrzF2EWGhnp7Ussb4GvWk9M=");
var authenticationKey = Convert.FromBase64String("HPqKD+TDmsZPuKSZHSmpZT+Y2nGsZ7uijy1NesJWbyU=");
string encryptedText = Encrypt(input, encryptionKey, authenticationKey);
string decryptedText = Decrypt(encryptedText, encryptionKey, authenticationKey);
}
public static string Encrypt(string input, byte[] encryptionKey, byte[] authenticationKey)
{
var inputBytes = Encoding.UTF8.GetBytes(input);
byte[] cipher;
using (var aes = new AesManaged())
{
aes.KeySize = keySize;
aes.BlockSize = blockSize;
aes.Mode = cipherMode;
aes.Padding = paddingMode;
aes.Key = encryptionKey;
aes.GenerateIV();
using (MemoryStream ms = new MemoryStream())
{
ms.Write(aes.IV, 0, aes.IV.Length);
using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(inputBytes, 0, inputBytes.Length);
cs.FlushFinalBlock();
}
cipher = ms.ToArray();
}
}
string base64SignedPayload;
using (HMACSHA256 hmac = new HMACSHA256(authenticationKey))
{
using (MemoryStream ms = new MemoryStream())
{
ms.Write(cipher, 0, cipher.Length);
var hash = hmac.ComputeHash(cipher);
ms.Write(hash, 0, hash.Length);
base64SignedPayload = Convert.ToBase64String(ms.ToArray());
}
}
return HttpUtility.UrlEncode(base64SignedPayload);
}
public static string Decrypt(string encryptedText, byte[] encryptionKey, byte[] authenticationKey)
{
var base64SignedPayload = HttpUtility.UrlDecode(encryptedText);
var signedPayload = Convert.FromBase64String(base64SignedPayload);
byte[] cipher;
using (HMACSHA256 hmac = new HMACSHA256(authenticationKey))
{
var storedHash = new byte[hmac.HashSize / 8];
var cipherLength = signedPayload.Length - storedHash.Length;
cipher = new byte[cipherLength];
using (MemoryStream ms = new MemoryStream(signedPayload))
{
ms.Read(cipher, 0, cipherLength);
ms.Read(storedHash, 0, storedHash.Length);
var computedHash = hmac.ComputeHash(cipher);
if (!computedHash.SequenceEqual(storedHash))
{
return null;
}
}
}
using (AesManaged aes = new AesManaged())
{
aes.KeySize = keySize;
aes.BlockSize = blockSize;
aes.Mode = cipherMode;
aes.Padding = paddingMode;
aes.Key = encryptionKey;
var iv = new byte[ivLength];
var encrypted = new byte[cipher.Length - ivLength];
using (MemoryStream ms = new MemoryStream(cipher))
{
ms.Read(iv, 0, ivLength);
aes.IV = iv;
ms.Read(encrypted, 0, encrypted.Length);
using (MemoryStream decrypted = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(decrypted, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(encrypted, 0, encrypted.Length);
}
return Encoding.UTF8.GetString(decrypted.ToArray());
}
}
}
private static string GenerateNonce()
{
var nonceLength = 32;
var validChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._~";
var nonceString = new StringBuilder();
using (var rnd = new RNGCryptoServiceProvider())
{
while (nonceString.Length < nonceLength)
{
var bytes = new byte[1];
rnd.GetBytes(bytes);
var character = (char)bytes[0];
if (validChars.Contains(character))
{
nonceString.Append(character);
}
}
}
return nonceString.ToString();
}
}
var CryptoJS = require('crypto-js');
var _ = require('lodash');
var encryptionKey = CryptoJS.enc.Base64.parse('DbU0fQQc5IbF4v9a/KUvMrzF2EWGhnp7Ussb4GvWk9M=');
var authenticationKey = CryptoJS.enc.Base64.parse('HPqKD+TDmsZPuKSZHSmpZT+Y2nGsZ7uijy1NesJWbyU=');
var ivLength = 128 / 8;
var nonce = generateNonce(32);
var utcNow = new Date().toISOString();
var json = {
"firstName": "John",
"lastName": "Doe",
"dateOfBirth": "1970-01-01T00:00:00Z",
"emailAddress": "[email protected]",
"phoneNumber": "07000123456",
"address1": "1 Anchor Road",
"address2": "Kingsclere",
"town": "Newbury",
"postalCode": "RG20 5NE",
"partnerReference": "01F0B37A-E056-4415-93D9-03F75506EE17",
"nonce": nonce,
"timestamp": utcNow
}
var payload = JSON.stringify(json);
var encryptedText = encrypt(payload, encryptionKey, authenticationKey);
var decryptedText = decrypt(encryptedText, encryptionKey, authenticationKey);
function encrypt(input, encryptionKey, authenticationKey) {
var iv = CryptoJS.lib.WordArray.random(ivLength);
var encrypted = CryptoJS.AES.encrypt(payload, encryptionKey, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});
var hashData = iv.concat(encrypted.ciphertext);
var hash = CryptoJS.HmacSHA256(hashData, authenticationKey);
var signedPayload = hashData.concat(hash);
var base64SignedPayload = CryptoJS.enc.Base64.stringify(signedPayload);
return encodeURIComponent(base64SignedPayload);
}
function decrypt(encryptedText, encryptionKey, authenticationKey) {
var base64SignedPayload = decodeURIComponent(encryptedText);
var signedPayload = CryptoJS.enc.Base64.parse(base64SignedPayload);
//CryptoJS WordArray is 4 bytes in a single value
var wordArray = 4;
var hashLength = 256 / 8; // bytes
var cipherlength = signedPayload.words.length - (hashLength / wordArray);
// Split the signedPayload into two arrays - cipher & hash
var cipher = signedPayload.clone();
cipher.sigBytes = cipherlength * wordArray;
cipher.clamp();
var hash = signedPayload.clone();
hash.words.splice(0, cipherlength);
hash.sigBytes -= cipherlength * wordArray;
// compute the hash and compare to what was sent
var computedHash = CryptoJS.HmacSHA256(cipher, authenticationKey);
var out = _.difference(computedHash.words, hash.words);
if (out.length != 0) {
console.log("incorrect hash");
return;
}
// split the cipher into the two arrays - iv & the encrypted message
var iv = cipher.clone();
iv.sigBytes = (ivLength);
iv.clamp();
var encrypted = cipher.clone();
encrypted.words.splice(0, wordArray);
encrypted.sigBytes -= ivLength;
var decrypted = CryptoJS.AES.decrypt({
ciphertext: encrypted
}, encryptionKey, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
function generateNonce(length) {
var bytes = new Uint8Array(length);
var random = window.crypto.getRandomValues(bytes);
var result = [];
var charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._~';
random.forEach(function (c) {
result.push(charset[c % charset.length]);
});
return result.join('');
}
Updated about 5 years ago