VisaCheckoutDecryptor
public class VisaCheckoutDecryptor
{
private const int HMAC_LENGTH = 32, IV_LENGTH = 16;
public static string DecryptPayload(string key, string dynamicKey, string payload)
{
var payloadData = Convert.FromBase64String(payload);
var dynamicKeyData = Convert.FromBase64String(dynamicKey);
var keyData = Encoding.UTF8.GetBytes(key);
var decryptedDynamicKey = Decrypt(keyData, dynamicKeyData);
var decryptedPayload = Decrypt(decryptedDynamicKey, payloadData);
return Encoding.UTF8.GetString(decryptedPayload);
}
private static byte[] Decrypt(byte[] key, byte[] data)
{
if (data == null || data.Length <= IV_LENGTH + HMAC_LENGTH)
{
throw new ArgumentException("Bad input data", "data");
}
var hmac = new byte[HMAC_LENGTH];
Array.Copy(data, 0, hmac, 0, HMAC_LENGTH);
var iv = new byte[IV_LENGTH];
Array.Copy(data, HMAC_LENGTH, iv, 0, IV_LENGTH);
var payload = new byte[data.Length - HMAC_LENGTH - IV_LENGTH];
Array.Copy(data, HMAC_LENGTH + IV_LENGTH, payload, 0, payload.Length);
//if (byteArrayEquals(hmac, CreateHmac(key, byteArrayConcat(iv, payload)))) {
// TODO: Handle HMAC validation failure
//}
using (var aes = new AesManaged())
{
aes.BlockSize = 128;
aes.KeySize = 256;
aes.Key = Hash(key);
aes.IV = iv;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(payload, 0, payload.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
}
}
private static byte[] Hash(byte[] key)
{
return (new SHA256Managed()).ComputeHash(key);
}
private static byte[] CreateHmac(byte[] key, byte[] data)
{
return (new HMACSHA256(key)).ComputeHash(data);
}
}