/// <summary>
        /// Encrypts the provided data using the descriptor string specified
        /// by <see cref="ProtectionDescriptor"/>.
        /// </summary>
        /// <param name="node">The data to encrypt.</param>
        /// <returns>The encrypted form of the input data.</returns>
        public override XmlNode Encrypt(XmlNode node)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            // precondition checks

            if (String.IsNullOrWhiteSpace(ProtectionDescriptor))
            {
                throw new InvalidOperationException("The ProtectionDescriptor property has not been initialized.");
            }

            // protect the data

            byte[] unprotectedData = Encoding.UTF8.GetBytes(node.OuterXml);
            byte[] protectedData   = new ProtectionDescriptorClass(ProtectionDescriptor).ProtectSecret(unprotectedData);

            // and turn it into the correct data format

            return(XElementToXmlNode(
                       new XElement("EncryptedData",
                                    new XComment($"Payload protected to protection descriptor '{ProtectionDescriptor}'"),
                                    new XElement("CipherData",
                                                 new XElement("CipherValue", Convert.ToBase64String(protectedData))))));
        }
        /// <summary>
        /// Decrypts the provided data which was previously encrypted
        /// using <see cref="Encrypt(XmlNode)"/>.
        /// </summary>
        /// <param name="encryptedNode">The data to decrypt.</param>
        /// <returns>The decrypted form of the input data.</returns>
        public override XmlNode Decrypt(XmlNode encryptedNode)
        {
            if (encryptedNode == null)
            {
                throw new ArgumentNullException(nameof(encryptedNode));
            }

            // convert to usable type and extract protected payload

            XElement encryptedElement = XmlNodeToXElement(encryptedNode);
            string   protectedBase64  = null;

            if (encryptedElement.Name == "EncryptedData")
            {
                protectedBase64 = encryptedElement.Element("CipherData")?.Element("CipherValue")?.Value;
            }

            if (String.IsNullOrWhiteSpace(protectedBase64))
            {
                throw new ConfigurationErrorsException("The provided node is malformed.");
            }

            // unprotect the data

            byte[] protectedData   = Convert.FromBase64String(protectedBase64);
            byte[] unprotectedData = ProtectionDescriptorClass.UnprotectSecret(protectedData);
            string unprotectedXml  = Encoding.UTF8.GetString(unprotectedData);

            // turn this back into an XML doc

            XmlDocument xmlDocument = new XmlDocument()
            {
                PreserveWhitespace = true
            };

            xmlDocument.LoadXml(unprotectedXml);
            return(xmlDocument.DocumentElement);
        }
        /// <summary>
        /// Encrypts the provided data using the descriptor string specified
        /// by <see cref="ProtectionDescriptor"/>.
        /// </summary>
        /// <param name="node">The data to encrypt.</param>
        /// <returns>The encrypted form of the input data.</returns>
        public override XmlNode Encrypt(XmlNode node)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            // precondition checks

            if (String.IsNullOrWhiteSpace(ProtectionDescriptor))
            {
                throw new InvalidOperationException("The ProtectionDescriptor property has not been initialized.");
            }

            // protect the data

            byte[] unprotectedData = Encoding.UTF8.GetBytes(node.OuterXml);
            byte[] protectedData = new ProtectionDescriptorClass(ProtectionDescriptor).ProtectSecret(unprotectedData);
            
            // and turn it into the correct data format

            return XElementToXmlNode(
                new XElement("EncryptedData",
                    new XComment($"Payload protected to protection descriptor '{ProtectionDescriptor}'"),
                    new XElement("CipherData",
                        new XElement("CipherValue", Convert.ToBase64String(protectedData)))));
        }