/// <summary>
        /// Reads an EncryptedKeyIdentifierClause from a XML stream.
        /// </summary>
        /// <param name="reader">An XML reader positioned at an EncryptedKey element as defined in 'http://www.w3.org/TR/2002/REC-xmlenc-core-20021210' .</param>
        /// <returns>SecurityKeyIdentifierClause instance of type EncryptedKeyIdentifierClause.</returns>
        /// <exception cref="ArgumentNullException">The <paramref name="reader"/> is null.</exception>
        /// <exception cref="InvalidOperationException">If the <paramref name="reader"/> is not positioned at an EncryptedKey element.</exception>
        public override SecurityKeyIdentifierClause ReadKeyIdentifierClause(XmlReader reader)
        {
            if (reader == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
            }

            // <EncryptedKey>
            if (reader.IsStartElement(XmlEncryptionConstants.Elements.EncryptedKey, XmlEncryptionConstants.Namespace))
            {
                EncryptedKeyElement encryptedKey = new EncryptedKeyElement(KeyInfoSerializer);
                encryptedKey.ReadXml(XmlDictionaryReader.CreateDictionaryReader(reader));
                return(new EncryptedKeyIdentifierClause(encryptedKey.CipherData.CipherValue, encryptedKey.Algorithm, encryptedKey.KeyIdentifier));
            }

            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID3275, reader.Name, reader.NamespaceURI)));
        }
        /// <summary>
        /// Reads an EncryptedKeyIdentifierClause from a XML stream.
        /// </summary>
        /// <param name="reader">An XML reader positioned at an EncryptedKey element as defined in 'http://www.w3.org/TR/2002/REC-xmlenc-core-20021210' .</param>
        /// <returns>SecurityKeyIdentifierClause instance of type EncryptedKeyIdentifierClause.</returns>
        /// <exception cref="ArgumentNullException">The <paramref name="reader"/> is null.</exception>
        /// <exception cref="InvalidOperationException">If the <paramref name="reader"/> is not positioned at an EncryptedKey element.</exception>
        public override SecurityKeyIdentifierClause ReadKeyIdentifierClause(XmlReader reader)
        {
            if (reader == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
            }

            // <EncryptedKey>
            if (reader.IsStartElement(XmlEncryptionConstants.Elements.EncryptedKey, XmlEncryptionConstants.Namespace))
            {
                EncryptedKeyElement encryptedKey = new EncryptedKeyElement(KeyInfoSerializer);
                encryptedKey.ReadXml(XmlDictionaryReader.CreateDictionaryReader(reader));
                return new EncryptedKeyIdentifierClause(encryptedKey.CipherData.CipherValue, encryptedKey.Algorithm, encryptedKey.KeyIdentifier);
            }

            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID3275, reader.Name, reader.NamespaceURI)));
        }
        internal static XmlDictionaryReader CreatePlaintextReaderFromEncryptedData(
                        XmlDictionaryReader reader,
                        SecurityTokenResolver serviceTokenResolver,
                        SecurityTokenSerializer keyInfoSerializer,
                        Collection<EncryptedKeyIdentifierClause> clauses,
                        out EncryptingCredentials encryptingCredentials)
        {
            if (reader == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
            }

            reader.MoveToContent();
            if (reader.IsEmptyElement)
            {
#pragma warning suppress 56504 // bogus - thinks reader.LocalName, reader.NamespaceURI need validation
                throw DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID3061, reader.LocalName, reader.NamespaceURI));
            }

            encryptingCredentials = null;

            XmlUtil.ValidateXsiType(reader, Saml2Constants.Types.EncryptedElementType, Saml2Constants.Namespace);

            reader.ReadStartElement();
            EncryptedDataElement encryptedData = new EncryptedDataElement(keyInfoSerializer);

            // <xenc:EncryptedData> 1
            encryptedData.ReadXml(reader);

            // <xenc:EncryptedKey> 0-oo
            reader.MoveToContent();
            while (reader.IsStartElement(XmlEncryptionConstants.Elements.EncryptedKey, XmlEncryptionConstants.Namespace))
            {
                SecurityKeyIdentifierClause skic;
                if (keyInfoSerializer.CanReadKeyIdentifierClause(reader))
                {
                    skic = keyInfoSerializer.ReadKeyIdentifierClause(reader);
                }
                else
                {
                    EncryptedKeyElement encryptedKey = new EncryptedKeyElement(keyInfoSerializer);
                    encryptedKey.ReadXml(reader);
                    skic = encryptedKey.GetClause();
                }

                EncryptedKeyIdentifierClause encryptedKeyClause = skic as EncryptedKeyIdentifierClause;
                if (null == encryptedKeyClause)
                {
                    throw DiagnosticUtility.ThrowHelperXml(reader, SR.GetString(SR.ID4172));
                }

                clauses.Add(encryptedKeyClause);
            }

            reader.ReadEndElement();

            // Try to resolve the decryption key from both the embedded 
            // KeyInfo and any external clauses
            SecurityKey decryptionKey = null;
            SecurityKeyIdentifierClause matchingClause = null;

            foreach (SecurityKeyIdentifierClause clause in encryptedData.KeyIdentifier)
            {
                if (serviceTokenResolver.TryResolveSecurityKey(clause, out decryptionKey))
                {
                    matchingClause = clause;
                    break;
                }
            }

            if (null == decryptionKey)
            {
                foreach (SecurityKeyIdentifierClause clause in clauses)
                {
                    if (serviceTokenResolver.TryResolveSecurityKey(clause, out decryptionKey))
                    {
                        matchingClause = clause;
                        break;
                    }
                }
            }

            if (null == decryptionKey)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new EncryptedTokenDecryptionFailedException());
            }

            // Need a symmetric key
            SymmetricSecurityKey symmetricKey = decryptionKey as SymmetricSecurityKey;
            if (null == symmetricKey)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new SecurityTokenException(SR.GetString(SR.ID4023)));
            }

            // Do the actual decryption
            SymmetricAlgorithm decryptor = symmetricKey.GetSymmetricAlgorithm(encryptedData.Algorithm);
            byte[] plainText = encryptedData.Decrypt(decryptor);

            // Save off the encrypting credentials for roundtrip
            encryptingCredentials = new ReceivedEncryptingCredentials(decryptionKey, new SecurityKeyIdentifier(matchingClause), encryptedData.Algorithm);

            return XmlDictionaryReader.CreateTextReader(plainText, reader.Quotas);
        }