internal BCryptAuthenticatedSymmetricAlgorithm(CngAlgorithm algorithm,
                                                       CngProvider implementation,
                                                       KeySizes[] legalBlockSizes,
                                                       KeySizes[] legalKeySizes)
        {
            Debug.Assert(algorithm != null, "algorithm != null");
            Debug.Assert(implementation != null, "implementation != null");
            Debug.Assert(legalBlockSizes != null, "legalBlockSizes != null");
            Debug.Assert(legalKeySizes != null, "legalKeySizes != null");

            m_algorithm      = algorithm;
            m_implementation = implementation;
            m_chainingMode   = CngChainingMode.Gcm;

            LegalBlockSizesValue = legalBlockSizes;
            LegalKeySizesValue   = legalKeySizes;

            // Create a temporary algorithm handle so that we can query it for some properties - such as the
            // block and tag sizes.
            using (SafeBCryptAlgorithmHandle algorithmHandle = SetupAlgorithm())
            {
                // Get block size in bits
                BlockSize = BCryptNative.GetInt32Property(algorithmHandle, BCryptNative.ObjectPropertyName.BlockLength) * 8;

                UpdateLegalTagSizes(algorithmHandle);
            }
        }
        /// <summary>
        ///     Make a deep copy of the authenticated encryption state
        /// </summary>
        private AuthenticatedSymmetricEncryptionState(AuthenticatedSymmetricEncryptionState other)
            : base(other)
        {
            Debug.Assert(other != null, "other != null");

            m_cngChainingMode = other.m_cngChainingMode;

            if (other.m_authenticatedData != null)
            {
                m_authenticatedData = new byte[other.m_authenticatedData.Length];
                Array.Copy(other.m_authenticatedData, m_authenticatedData, m_authenticatedData.Length);
            }
        }
        /// <summary>
        ///     Capture the parameters used for encryption, and verify that they make sense together
        /// </summary>
        internal AuthenticatedSymmetricEncryptionState(byte[] key,
                                                       byte[] iv,
                                                       byte[] authenticatedData,
                                                       AuthenticatedSymmetricAlgorithm algorithm)
            : base(key, iv, algorithm, typeof(AuthenticatedSymmetricAlgorithm), false)
        {
            if (authenticatedData != null)
            {
                m_authenticatedData = new byte[authenticatedData.Length];
                Array.Copy(authenticatedData, m_authenticatedData, m_authenticatedData.Length);
            }

            // Since CipherMode doesn't contain authenticated encryption modes, it's not very useful for
            // debugging mode mismatches in authenticated symmetric algorithms.  Our only current
            // authenticated symmetric algorithm implementations ues CNG chaining modes, so we'll grab that
            // if it's available to aid in debugging.
            ICngSymmetricAlgorithm cngAlgorithm = algorithm as ICngSymmetricAlgorithm;

            if (cngAlgorithm != null)
            {
                m_cngChainingMode = cngAlgorithm.CngMode;
            }
        }