private SymmetricAlgorithm DecryptEncryptedKeyClass(EncryptedKey encryptedKey, string symmetricAlgorithmUri)
        {
            if (encryptedKey == null)
            {
                throw ExceptionUtility.ArgumentNull(nameof(encryptedKey));
            }

            SymmetricAlgorithm decryptionKey = null;

            if (encryptedKey.KeyInfo != null)
            {
                foreach (var keyInfo in encryptedKey.KeyInfo)
                {
                    // Извлечение ключа по имени
                    if (keyInfo is KeyInfoName)
                    {
                        var keyName      = ((KeyInfoName)keyInfo).Value;
                        var keyAlgorithm = this.GetKeyNameMapping()[keyName];

                        if (keyAlgorithm != null)
                        {
                            if (keyAlgorithm is SymmetricAlgorithm)
                            {
                                decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, (SymmetricAlgorithm)keyAlgorithm, symmetricAlgorithmUri, encryptedKey.EncryptionMethod.KeyAlgorithm);
                            }
                            else if (keyAlgorithm is RSA)
                            {
                                var useOaep = (encryptedKey.EncryptionMethod != null) && (encryptedKey.EncryptionMethod.KeyAlgorithm == XmlEncRSAOAEPUrl);
                                decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, (RSA)keyAlgorithm, useOaep, symmetricAlgorithmUri);
                            }
                            else if (keyAlgorithm is GostAsymmetricAlgorithm)
                            {
                                decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, (GostAsymmetricAlgorithm)keyAlgorithm);
                            }
                        }

                        break;
                    }

                    // Извлечение ключа из сертификата
                    if (keyInfo is KeyInfoX509Data)
                    {
                        var certificates = CryptographyXmlUtils.BuildBagOfCertsDecryption((KeyInfoX509Data)keyInfo);

                        foreach (var certificate in certificates)
                        {
                            var privateKey = certificate.GetPrivateKeyAlgorithm();

                            if (privateKey is RSA)
                            {
                                var useOaep = (encryptedKey.EncryptionMethod != null) && (encryptedKey.EncryptionMethod.KeyAlgorithm == XmlEncRSAOAEPUrl);
                                decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, (RSA)privateKey, useOaep, symmetricAlgorithmUri);
                            }
                            else if (privateKey is GostAsymmetricAlgorithm)
                            {
                                decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, (GostAsymmetricAlgorithm)privateKey);
                            }
                        }

                        break;
                    }

                    // Извлечение ключа по ссылке
                    if (keyInfo is KeyInfoRetrievalMethod)
                    {
                        var idValue   = CryptographyXmlUtils.ExtractIdFromLocalUri(((KeyInfoRetrievalMethod)keyInfo).Uri);
                        var idElement = GetIdElement(this.GetDocument(), idValue);

                        if (idElement != null)
                        {
                            var secondEncryptedKey = new EncryptedKey();
                            secondEncryptedKey.LoadXml(idElement);

                            decryptionKey = DecryptEncryptedKeyClass(secondEncryptedKey, symmetricAlgorithmUri);
                        }

                        break;
                    }

                    // Ключ в готовом виде
                    if (keyInfo is KeyInfoEncryptedKey)
                    {
                        var secondEncryptedKey = ((KeyInfoEncryptedKey)keyInfo).EncryptedKey;
                        var symmetricAlgorithm = DecryptEncryptedKeyClass(secondEncryptedKey, symmetricAlgorithmUri);

                        if (symmetricAlgorithm != null)
                        {
                            decryptionKey = DecryptKeyClass(encryptedKey.CipherData.CipherValue, symmetricAlgorithm, symmetricAlgorithmUri, encryptedKey.EncryptionMethod.KeyAlgorithm);
                        }

                        break;
                    }
                }
            }

            return(decryptionKey);
        }
        public override SymmetricAlgorithm GetDecryptionKey(EncryptedData encryptedData, string symmetricAlgorithmUri)
        {
            if (encryptedData == null)
            {
                throw ExceptionUtility.ArgumentNull(nameof(encryptedData));
            }

            SymmetricAlgorithm decryptionKey = null;

            if (encryptedData.KeyInfo != null)
            {
                EncryptedKey encryptedKey = null;

                foreach (var keyInfo in encryptedData.KeyInfo)
                {
                    // Извлечение ключа по имени
                    if (keyInfo is KeyInfoName)
                    {
                        var keyName      = ((KeyInfoName)keyInfo).Value;
                        var keyAlgorithm = this.GetKeyNameMapping()[keyName];

                        if (keyAlgorithm == null)
                        {
                            var nsManager = new XmlNamespaceManager(this.GetDocument().NameTable);
                            nsManager.AddNamespace("enc", XmlEncNamespaceUrl);

                            var encryptedKeyNodes = this.GetDocument().SelectNodes("//enc:EncryptedKey", nsManager);

                            if (encryptedKeyNodes != null)
                            {
                                foreach (XmlElement encryptedKeyNode in encryptedKeyNodes)
                                {
                                    var currentEncryptedKey = new EncryptedKey();
                                    currentEncryptedKey.LoadXml(encryptedKeyNode);

                                    if ((currentEncryptedKey.CarriedKeyName == keyName) && (currentEncryptedKey.Recipient == Recipient))
                                    {
                                        encryptedKey = currentEncryptedKey;
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            decryptionKey = (SymmetricAlgorithm)keyAlgorithm;
                        }

                        break;
                    }

                    // Извлечение ключа по ссылке
                    if (keyInfo is KeyInfoRetrievalMethod)
                    {
                        var idValue   = CryptographyXmlUtils.ExtractIdFromLocalUri(((KeyInfoRetrievalMethod)keyInfo).Uri);
                        var idElement = GetIdElement(this.GetDocument(), idValue);

                        if (idElement != null)
                        {
                            encryptedKey = new EncryptedKey();
                            encryptedKey.LoadXml(idElement);
                        }

                        break;
                    }

                    // Ключ в готовом виде
                    if (keyInfo is KeyInfoEncryptedKey)
                    {
                        encryptedKey = ((KeyInfoEncryptedKey)keyInfo).EncryptedKey;
                        break;
                    }
                }

                if (decryptionKey == null && encryptedKey != null)
                {
                    if (symmetricAlgorithmUri == null)
                    {
                        if (encryptedData.EncryptionMethod == null)
                        {
                            throw ExceptionUtility.CryptographicException(Resources.XmlMissingAlgorithm);
                        }

                        symmetricAlgorithmUri = encryptedData.EncryptionMethod.KeyAlgorithm;
                    }

                    decryptionKey = DecryptEncryptedKeyClass(encryptedKey, symmetricAlgorithmUri);
                }
            }

            return(decryptionKey);
        }