feanz
8/7/2017 - 2:18 PM

VisaCheckoutDecryptor

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);
        }
    }