/// <summary>
        /// Decrypts the provided <paramref name="ciphertext"/> value using the provided <see cref="DataEncryptionKey"/>.
        /// </summary>
        /// <typeparam name="T">The plaintext value <see cref="Type"/>.</typeparam>
        /// <param name="ciphertext">The encrypted value.</param>
        /// <param name="encryptionKey">The key used to decrypt the <paramref name="ciphertext"/> value.</param>
        /// <returns>The decrypted <paramref name="ciphertext"/> value.</returns>
        /// <remarks>
        /// This method decrypts data that was encrypted using <see cref="EncryptionType.Randomized"/> encryption and the
        /// default serializer registered under type <typeparamref name="T"/> with the <see cref="StandardSerializerFactory"/>
        /// </remarks>
        /// <exception cref="MicrosoftDataEncryptionException"><paramref name="encryptionKey"/> is null.</exception>
        public static T Decrypt <T>(this byte[] ciphertext, DataEncryptionKey encryptionKey)
        {
            encryptionKey.ValidateNotNull(nameof(encryptionKey));

            DataProtector  encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Randomized);
            Serializer <T> serializer          = StandardSerializerFactory.Default.GetDefaultSerializer <T>();

            byte[] plaintextData = encryptionAlgorithm.Decrypt(ciphertext);
            return(serializer.Deserialize(plaintextData));
        }
        /// <summary>
        /// Encrypts the provided <paramref name="plaintext"/> value using the provided <see cref="EncryptionSettings{T}"/>.
        /// </summary>
        /// <typeparam name="T">The <paramref name="plaintext"/> value <see cref="Type"/>.</typeparam>
        /// <param name="plaintext">The plaintext value to encrypt.</param>
        /// <param name="encryptionSettings">The settings used to configure how the <paramref name="plaintext"/> should be encrypted.</param>
        /// <returns>The encrypted <paramref name="plaintext"/> value.</returns>
        /// <exception cref="MicrosoftDataEncryptionException">
        /// <paramref name="encryptionSettings"/> is null.
        /// -or-
        /// <paramref name="encryptionSettings"/> <see cref="EncryptionType"/> is set to <see cref="EncryptionType.Plaintext"/>.
        /// </exception>
        public static byte[] Encrypt <T>(this T plaintext, EncryptionSettings <T> encryptionSettings)
        {
            encryptionSettings.ValidateNotNull(nameof(encryptionSettings));
            encryptionSettings.ValidateNotPlaintext(nameof(encryptionSettings));

            DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionSettings.DataEncryptionKey, encryptionSettings.EncryptionType);
            ISerializer   serializer          = encryptionSettings.GetSerializer();

            byte[] serializedData = serializer.Serialize(plaintext);
            return(encryptionAlgorithm.Encrypt(serializedData));
        }
        /// <summary>
        /// Decrypts the provided <paramref name="ciphertext"/> value using the provided <see cref="EncryptionSettings{T}"/>.
        /// </summary>
        /// <typeparam name="T">The plaintext value <see cref="Type"/>.</typeparam>
        /// <param name="ciphertext">The encrypted value.</param>
        /// <param name="encryptionSettings">The settings used to configure how the <paramref name="ciphertext"/> should be decrypted.</param>
        /// <returns>The decrypted <paramref name="ciphertext"/> value.</returns>
        /// <exception cref="MicrosoftDataEncryptionException">
        /// <paramref name="encryptionSettings"/> is null.
        /// -or-
        /// <paramref name="encryptionSettings"/> <see cref="EncryptionType"/> is set to <see cref="EncryptionType.Plaintext"/>.
        /// </exception>
        public static T Decrypt <T>(this byte[] ciphertext, EncryptionSettings <T> encryptionSettings)
        {
            encryptionSettings.ValidateNotNull(nameof(encryptionSettings));
            encryptionSettings.ValidateNotPlaintext(nameof(encryptionSettings));

            DataProtector  encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionSettings.DataEncryptionKey, EncryptionType.Plaintext);
            Serializer <T> serializer          = encryptionSettings.Serializer;

            byte[] plaintextData = encryptionAlgorithm.Decrypt(ciphertext);
            return(serializer.Deserialize(plaintextData));
        }
        /// <summary>
        /// Encrypts each plaintext value of a sequence using the provided <see cref="DataEncryptionKey"/>.
        /// </summary>
        /// <typeparam name="T">The type of the plaintext elements of <paramref name="source"/>.</typeparam>
        /// <param name="source">A sequence of values to encrypt.</param>
        /// <param name="encryptionKey">The key used to encrypt the plaintext values of <paramref name="source"/>.</param>
        /// <returns>An <see cref="IEnumerable{T}"/> of <see cref="T:Byte[]"/> whose elements are the result of encrypting each element of <paramref name="source"/>.</returns>
        /// <remarks>
        /// This method encrypts using <see cref="EncryptionType.Randomized"/> encryption and the
        /// default serializer registered under type <typeparamref name="T"/> with the <see cref="StandardSerializerFactory"/>
        /// </remarks>
        /// <exception cref="MicrosoftDataEncryptionException"><paramref name="encryptionKey"/> is null.</exception>
        public static IEnumerable <byte[]> Encrypt <T>(this IEnumerable <T> source, DataEncryptionKey encryptionKey)
        {
            encryptionKey.ValidateNotNull(nameof(encryptionKey));

            DataProtector  encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Randomized);
            Serializer <T> serializer          = StandardSerializerFactory.Default.GetDefaultSerializer <T>();

            foreach (T item in source)
            {
                byte[] serializedData = serializer.Serialize(item);
                yield return(encryptionAlgorithm.Encrypt(serializedData));
            }
        }
        /// <summary>
        /// Decrypts each ciphertext value of a sequence using the provided <see cref="EncryptionSettings{T}"/>.
        /// </summary>
        /// <typeparam name="T">The type of the plaintext elements of <paramref name="source"/>.</typeparam>
        /// <param name="source">A sequence of values to decrypt.</param>
        /// <param name="encryptionSettings">The settings used to configure how the values of <paramref name="source"/> should be decrypted.</param>
        /// <returns>An <see cref="IEnumerable{T}"/> whose elements are the result of decrypting each element of <paramref name="source"/>.</returns>
        /// <exception cref="MicrosoftDataEncryptionException">
        /// <paramref name="encryptionSettings"/> is null.
        /// -or-
        /// <paramref name="encryptionSettings"/> <see cref="EncryptionType"/> is set to <see cref="EncryptionType.Plaintext"/>.
        /// </exception>
        public static IEnumerable <T> Decrypt <T>(this IEnumerable <byte[]> source, EncryptionSettings <T> encryptionSettings)
        {
            encryptionSettings.ValidateNotNull(nameof(encryptionSettings));
            encryptionSettings.ValidateNotPlaintext(nameof(encryptionSettings));

            DataProtector  encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionSettings.DataEncryptionKey, EncryptionType.Plaintext);
            Serializer <T> serializer          = encryptionSettings.Serializer;

            foreach (byte[] item in source)
            {
                byte[] plaintextData = encryptionAlgorithm.Decrypt(item);
                yield return(serializer.Deserialize(plaintextData));
            }
        }
        /// <summary>
        /// Decrypts each ciphertext value of a sequence using the provided <see cref="DataEncryptionKey"/>.
        /// </summary>
        /// <typeparam name="T">The type of the plaintext elements of <paramref name="source"/></typeparam>
        /// <param name="source">A sequence of encrypted values to decrypt.</param>
        /// <param name="encryptionKey">The key used to decrypt the ciphertext values of <paramref name="source"/>.</param>
        /// <returns>An <see cref="IEnumerable{T}"/> whose elements are the result of decrypting each element of <paramref name="source"/>.</returns>
        /// <remarks>
        /// This method decrypts data that was encrypted using <see cref="EncryptionType.Randomized"/> encryption and the
        /// default serializer registered under type <typeparamref name="T"/> with the <see cref="StandardSerializerFactory"/>
        /// </remarks>
        /// <exception cref="MicrosoftDataEncryptionException"><paramref name="encryptionKey"/> is null.</exception>
        public static IEnumerable <T> Decrypt <T>(this IEnumerable <byte[]> source, DataEncryptionKey encryptionKey)
        {
            encryptionKey.ValidateNotNull(nameof(encryptionKey));

            DataProtector             encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Randomized);
            Serializer <T>            serializer          = StandardSerializerFactory.Default.GetDefaultSerializer <T>();
            StandardSerializerFactory myFactory           = new StandardSerializerFactory();

            myFactory.RegisterSerializer(typeof(string), new SqlNCharSerializer());

            foreach (byte[] item in source)
            {
                byte[] plaintextData = encryptionAlgorithm.Decrypt(item);
                yield return(serializer.Deserialize(plaintextData));
            }
        }