/// <summary>
        /// Gets the algorithm handle instance for a given algorithm and instantiates it using the provided key and the encryption type.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="type"></param>
        /// <param name="algorithmName"></param>
        /// <param name="encryptionAlgorithm"></param>
        internal void GetAlgorithm(SqlClientSymmetricKey key, byte type, string algorithmName, out SqlClientEncryptionAlgorithm encryptionAlgorithm)
        {
            encryptionAlgorithm = null;

            SqlClientEncryptionAlgorithmFactory factory = null;

            if (!_encryptionAlgoFactoryList.TryGetValue(algorithmName, out factory))
            {
                throw SQL.UnknownColumnEncryptionAlgorithm(algorithmName,
                                                           SqlClientEncryptionAlgorithmFactoryList.GetInstance().GetRegisteredCipherAlgorithmNames());
            }

            Debug.Assert(null != factory, "Null Algorithm Factory class detected");

            // If the factory exists, following method will Create an algorithm object. If this fails,
            // it will raise an exception.
            encryptionAlgorithm = factory.Create(key, (SqlClientEncryptionType)type, algorithmName);
        }
        /// <summary>
        /// <para> Decrypts the symmetric key and saves it in metadata. In addition, initializes
        /// the SqlClientEncryptionAlgorithm for rapid decryption.</para>
        /// </summary>
        internal static void DecryptSymmetricKey(SqlCipherMetadata md, SqlConnection connection, SqlCommand command)
        {
            Debug.Assert(md is not null, "md should not be null in DecryptSymmetricKey.");

            SqlClientSymmetricKey symKey = null;
            SqlEncryptionKeyInfo  encryptionkeyInfoChosen = null;

            DecryptSymmetricKey(md.EncryptionInfo, out symKey, out encryptionkeyInfoChosen, connection, command);

            // Given the symmetric key instantiate a SqlClientEncryptionAlgorithm object and cache it in metadata
            md.CipherAlgorithm = null;
            SqlClientEncryptionAlgorithm cipherAlgorithm = null;
            string algorithmName = ValidateAndGetEncryptionAlgorithmName(md.CipherAlgorithmId, md.CipherAlgorithmName);                        // may throw

            SqlClientEncryptionAlgorithmFactoryList.GetInstance().GetAlgorithm(symKey, md.EncryptionType, algorithmName, out cipherAlgorithm); // will validate algorithm name and type
            Debug.Assert(cipherAlgorithm is not null);
            md.CipherAlgorithm   = cipherAlgorithm;
            md.EncryptionKeyInfo = encryptionkeyInfoChosen;
            return;
        }
        /// <summary>
        /// Return the algorithm name mapped to an Id.
        /// </summary>
        /// <param name="cipherAlgorithmId"></param>
        /// <param name="cipherAlgorithmName"></param>
        /// <returns></returns>
        private static string ValidateAndGetEncryptionAlgorithmName(byte cipherAlgorithmId, string cipherAlgorithmName)
        {
            if (TdsEnums.CustomCipherAlgorithmId == cipherAlgorithmId)
            {
                if (null == cipherAlgorithmName)
                {
                    throw SQL.NullColumnEncryptionAlgorithm(SqlClientEncryptionAlgorithmFactoryList.GetInstance().GetRegisteredCipherAlgorithmNames());
                }

                return(cipherAlgorithmName);
            }
            else if (TdsEnums.AEAD_AES_256_CBC_HMAC_SHA256 == cipherAlgorithmId)
            {
                return(SqlAeadAes256CbcHmac256Algorithm.AlgorithmName);
            }
            else
            {
                throw SQL.UnknownColumnEncryptionAlgorithmId(cipherAlgorithmId, GetRegisteredCipherAlgorithmIds());
            }
        }