/// <summary>
        ///  Encrypt RestSharp request payloads.
        /// </summary>
        /// <param name="request">A RestSharp request object</param>
        public void InterceptRequest(IRestRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            try
            {
                // Check request actually has a payload
                var bodyParam = request.Parameters.FirstOrDefault(param => param.Type == ParameterType.RequestBody);
                if (bodyParam == null)
                {
                    // Nothing to encrypt
                    return;
                }
                var payload = bodyParam.Value.ToString();
                if (string.IsNullOrEmpty(payload))
                {
                    // Nothing to encrypt
                    return;
                }

                // Encrypt fields & update headers
                string encryptedPayload;
                if (_config.UseHttpHeaders())
                {
                    // Generate encryption params and add them as HTTP headers
                    var parameters = FieldLevelEncryptionParams.Generate(_config);
                    UpdateRequestHeader(request, _config.IvHeaderName, parameters.IvValue);
                    UpdateRequestHeader(request, _config.EncryptedKeyHeaderName, parameters.EncryptedKeyValue);
                    UpdateRequestHeader(request, _config.EncryptionCertificateFingerprintHeaderName, _config.EncryptionCertificateFingerprint);
                    UpdateRequestHeader(request, _config.EncryptionKeyFingerprintHeaderName, _config.EncryptionKeyFingerprint);
                    UpdateRequestHeader(request, _config.OaepPaddingDigestAlgorithmHeaderName, parameters.OaepPaddingDigestAlgorithmValue);
                    encryptedPayload = FieldLevelEncryption.EncryptPayload(payload, _config, parameters);
                }
                else
                {
                    // Encryption params will be stored in the payload
                    encryptedPayload = FieldLevelEncryption.EncryptPayload(payload, _config);
                }

                // Update body and content length
                bodyParam.Value = encryptedPayload;
                UpdateRequestHeader(request, "Content-Length", encryptedPayload.Length);
            }
            catch (EncryptionException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new EncryptionException("Failed to intercept and encrypt request!", e);
            }
        }
        public void TestWrapUnwrapSecretKey_ShouldReturnTheOriginalKey()
        {
            // GIVEN
            var config           = TestUtils.GetTestFieldLevelEncryptionConfigBuilder().Build();
            var originalKeyBytes = Convert.FromBase64String("mZzmzoURXI3Vk0vdsPkcFw==");

            // WHEN
            var wrappedKeyBytes   = FieldLevelEncryptionParams.WrapSecretKey(config, originalKeyBytes);
            var unwrappedKeyBytes = FieldLevelEncryptionParams.UnwrapSecretKey(config, wrappedKeyBytes, config.OaepPaddingDigestAlgorithm);

            // THEN
            Assert.IsTrue(originalKeyBytes.SequenceEqual(unwrappedKeyBytes));
        }
        /// <summary>
        /// Decrypt RestSharp response payloads.
        /// </summary>
        /// <param name="response">A RestSharp response object</param>
        public void InterceptResponse(IRestResponse response)
        {
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            try
            {
                // Read response payload
                var encryptedPayload = response.Content;
                if (string.IsNullOrEmpty(encryptedPayload))
                {
                    // Nothing to decrypt
                    return;
                }

                // Decrypt fields & update headers
                string decryptedPayload;
                if (_config.UseHttpHeaders())
                {
                    // Read encryption params from HTTP headers and delete headers
                    var ivValue           = ReadAndRemoveHeader(response, _config.IvHeaderName);
                    var encryptedKeyValue = ReadAndRemoveHeader(response, _config.EncryptedKeyHeaderName);
                    var oaepPaddingDigestAlgorithmValue = ReadAndRemoveHeader(response, _config.OaepPaddingDigestAlgorithmHeaderName);
                    ReadAndRemoveHeader(response, _config.EncryptionCertificateFingerprintHeaderName);
                    ReadAndRemoveHeader(response, _config.EncryptionKeyFingerprintHeaderName);
                    var parameters = new FieldLevelEncryptionParams(_config, ivValue, encryptedKeyValue, oaepPaddingDigestAlgorithmValue);
                    decryptedPayload = FieldLevelEncryption.DecryptPayload(encryptedPayload, _config, parameters);
                }
                else
                {
                    // Encryption params are stored in the payload
                    decryptedPayload = FieldLevelEncryption.DecryptPayload(encryptedPayload, _config);
                }

                // Update body and content length
                var contentTypeInfo = response.GetType().GetTypeInfo().GetDeclaredField("_content");
                contentTypeInfo.SetValue(response, new Lazy <string>(() => decryptedPayload));
            }
            catch (EncryptionException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new EncryptionException("Failed to intercept and decrypt response!", e);
            }
        }
        public void TestGenerate_Nominal()
        {
            // GIVEN
            var config = TestUtils.GetTestFieldLevelEncryptionConfigBuilder().Build();

            // WHEN
            var parameters = FieldLevelEncryptionParams.Generate(config);

            // THEN
            Assert.IsNotNull(parameters.IvValue);
            Assert.IsNotNull(parameters.GetIvBytes());
            Assert.IsNotNull(parameters.EncryptedKeyValue);
            Assert.IsNotNull(parameters.GetSecretKeyBytes());
            Assert.AreEqual("SHA256", parameters.OaepPaddingDigestAlgorithmValue);
        }
        public void TestUnwrapSecretKey_InteroperabilityTest_OaepSha256()
        {
            // GIVEN
            var config = TestUtils.GetTestFieldLevelEncryptionConfigBuilder()
                         .WithOaepPaddingDigestAlgorithm("SHA-256")
                         .Build();
            const string wrappedKey      = "ZLB838BRWW2/BtdFFAWBRYShw/gBxXSwItpxEZ9zaSVEDHo7n+SyVYU7mayd+9vHkR8OdpqwpXM68t0VOrWI8LD8A2pRaYx8ICyhVFya4OeiWlde05Rhsk+TNwwREPbiw1RgjT8aedRJJYbAZdLb9XEI415Kb/UliHyvsdHMb6vKyYIjUHB/pSGAAmgds56IhIJGfvnBLPZfSHmGgiBT8WXLRuuf1v48aIadH9S0FfoyVGTaLYr+2eznSTAFC0ZBnzebM3mQI5NGQNviTnEJ0y+uZaLE/mthiKgkv1ZybyDPx2xJK2n05sNzfIWKmnI/SOb65RZLlo1Q+N868l2m9g==";
            var          wrappedKeyBytes = Convert.FromBase64String(wrappedKey);

            // WHEN
            var unwrappedKeyBytes = FieldLevelEncryptionParams.UnwrapSecretKey(config, wrappedKeyBytes, config.OaepPaddingDigestAlgorithm);

            // THEN
            var expectedKeyBytes = Convert.FromBase64String("mZzmzoURXI3Vk0vdsPkcFw==");

            Assert.IsTrue(expectedKeyBytes.SequenceEqual(unwrappedKeyBytes));
        }
        public void TestUnwrapSecretKey_InteroperabilityTest_OaepSha512()
        {
            // GIVEN
            var config = TestUtils.GetTestFieldLevelEncryptionConfigBuilder()
                         .WithOaepPaddingDigestAlgorithm("SHA-512")
                         .Build();
            const string wrappedKey      = "RuruMYP5rG6VP5vS4kVznIrSOjUzXyOhtD7bYlVqwniWTvxxZC73UDluwDhpLwX5QJCsCe8TcwGiQRX1u+yWpBveHDRmDa03hrc3JRJALEKPyN5tnt5w7aI4dLRnLuNoXbYoTSc4V47Z3gaaK6q2rEjydx2sQ/SyVmeUJN7NgxkhtHTyVWTymEM1ythL+AaaQ5AaXedhpWKhG06XYZIX4KV7T9cHEn+See6RVGGB2RUPHBJjrxJo5JoVSfnWN0gkTMyuwbmVaTWfsowbvh8GFibFT7h3uXyI3b79NiauyB7scXp9WidGues3MrTx4dKZrSbs3uHxzPKmCDZimuKfwg==";
            var          wrappedKeyBytes = Convert.FromBase64String(wrappedKey);

            // WHEN
            var unwrappedKeyBytes = FieldLevelEncryptionParams.UnwrapSecretKey(config, wrappedKeyBytes, config.OaepPaddingDigestAlgorithm);

            // THEN
            var expectedKeyBytes = Convert.FromBase64String("mZzmzoURXI3Vk0vdsPkcFw==");

            Assert.IsTrue(expectedKeyBytes.SequenceEqual(unwrappedKeyBytes));
        }
        public void TestGetSecretKeyBytes_ShouldThrowEncryptionException_WhenFailsToReadEncryptedKey()
        {
            try
            {
                // GIVEN
                var config     = TestUtils.GetTestFieldLevelEncryptionConfigBuilder().Build();
                var parameters = new FieldLevelEncryptionParams(config, null, "INVALID VALUE");

                // WHEN
                var secretKeyBytes = parameters.GetSecretKeyBytes();
                Assert.Fail($"Unexpected {secretKeyBytes}");
            }
            catch (Exception e)
            {
                // THEN
                Assert.AreEqual("Failed to decode and unwrap the provided secret key value!", e.Message);
                throw;
            }
        }
        public void TestGetIvBytes_ShouldThrowEncryptionException_WhenFailsToDecodeIV()
        {
            try
            {
                // GIVEN
                var config     = TestUtils.GetTestFieldLevelEncryptionConfigBuilder().Build();
                var parameters = new FieldLevelEncryptionParams(config, "INVALID VALUE", null);

                // WHEN
                var ivBytes = parameters.GetIvBytes();
                Assert.Fail($"Unexpected {ivBytes}");
            }
            catch (Exception e)
            {
                // THEN
                Assert.AreEqual("Failed to decode the provided IV value!", e.Message);
                throw;
            }
        }
        /// <summary>
        /// Decrypt a RestSharp response payload
        /// </summary>
        /// <param name="response">A RestSharp response object</param>
        /// <param name="encryptedPayload">The encrypted payload to be decrypted</param>
        /// <returns>The decrypted payload</returns>
        internal override string DecryptPayload(IRestResponse response, string encryptedPayload)
        {
            // Decrypt fields & update headers
            string decryptedPayload;

            if (_config.UseHttpHeaders())
            {
                // Read encryption params from HTTP headers and delete headers
                var ivValue           = ReadAndRemoveHeader(response, _config.IvHeaderName);
                var encryptedKeyValue = ReadAndRemoveHeader(response, _config.EncryptedKeyHeaderName);
                var oaepPaddingDigestAlgorithmValue = ReadAndRemoveHeader(response, _config.OaepPaddingDigestAlgorithmHeaderName);
                ReadAndRemoveHeader(response, _config.EncryptionCertificateFingerprintHeaderName);
                ReadAndRemoveHeader(response, _config.EncryptionKeyFingerprintHeaderName);
                var parameters = new FieldLevelEncryptionParams(_config, ivValue, encryptedKeyValue, oaepPaddingDigestAlgorithmValue);
                decryptedPayload = FieldLevelEncryption.DecryptPayload(encryptedPayload, _config, parameters);
            }
            else
            {
                // Encryption params are stored in the payload
                decryptedPayload = FieldLevelEncryption.DecryptPayload(encryptedPayload, _config);
            }
            return(decryptedPayload);
        }
        /// <summary>
        /// Encrypt a RestSharp request payload.
        /// </summary>
        /// <param name="request">A RestSharp request object</param>
        /// <param name="payload">The payload to be encrypted</param>
        /// <returns>The encrypted payload</returns>
        internal override string EncryptPayload(IRestRequest request, string payload)
        {
            // Encrypt fields & update headers
            string encryptedPayload;

            if (_config.UseHttpHeaders())
            {
                // Generate encryption params and add them as HTTP headers
                var parameters = FieldLevelEncryptionParams.Generate(_config);
                UpdateRequestHeader(request, _config.IvHeaderName, parameters.IvValue);
                UpdateRequestHeader(request, _config.EncryptedKeyHeaderName, parameters.EncryptedKeyValue);
                UpdateRequestHeader(request, _config.EncryptionCertificateFingerprintHeaderName, _config.EncryptionCertificateFingerprint);
                UpdateRequestHeader(request, _config.EncryptionKeyFingerprintHeaderName, _config.EncryptionKeyFingerprint);
                UpdateRequestHeader(request, _config.OaepPaddingDigestAlgorithmHeaderName, parameters.OaepPaddingDigestAlgorithmValue);
                encryptedPayload = FieldLevelEncryption.EncryptPayload(payload.ToString(), _config, parameters);
            }
            else
            {
                // Encryption params will be stored in the payload
                encryptedPayload = FieldLevelEncryption.EncryptPayload(payload.ToString(), _config);
            }
            return(encryptedPayload);
        }