예제 #1
0
        /// <summary>
        /// Asynchronously decrypts the fields, specified by JSONPath, that are contained in the given json document string.
        /// </summary>
        /// <param name="crypto">
        /// The instance of <see cref="ICrypto"/> that ultimately responsible for performing decryption operations
        /// on field values.
        /// </param>
        /// <param name="jsonString">A string containing an json document.</param>
        /// <param name="jsonPathsToDecrypt">One or more JSONPaths of the fields to decrypt.</param>
        /// <param name="credentialName">
        /// The name of the credential to use for this encryption operation,
        /// or null to use the default credential.
        /// </param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A task that will contain the same json document, except with the specified fields decrypted.</returns>
        public static async Task <string> DecryptJsonAsync(this ICrypto crypto, string jsonString, IEnumerable <string> jsonPathsToDecrypt, string credentialName = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (crypto == null)
            {
                throw new ArgumentNullException(nameof(crypto));
            }
            if (jsonString == null)
            {
                throw new ArgumentNullException(nameof(jsonString));
            }
            if (jsonPathsToDecrypt == null)
            {
                throw new ArgumentNullException(nameof(jsonPathsToDecrypt));
            }

            var token = JToken.Parse(jsonString);

            var decryptor = new Lazy <IAsyncDecryptor>(() => crypto.AsAsync().GetAsyncDecryptor(credentialName));

            var anyPaths = false;

            foreach (var jsonPath in jsonPathsToDecrypt)
            {
                if (jsonPath == null)
                {
                    throw new ArgumentException($"{nameof(jsonPathsToDecrypt)} cannot have null items.", nameof(jsonPathsToDecrypt));
                }

                anyPaths = true;

                foreach (var match in token.SelectTokens(jsonPath).ToArray())
                {
                    var decryptedToken = JToken.Parse(await decryptor.Value.DecryptAsync(match.Value <string>(), cancellationToken));

                    if (ReferenceEquals(token, match))
                    {
                        token = decryptedToken;
                        continue;
                    }

                    switch (match.Parent)
                    {
                    case JProperty property:
                        property.Value = decryptedToken;
                        break;

                    case JArray array:
                        array[array.IndexOf(match)] = decryptedToken;
                        break;
                    }
                }
            }

            if (!anyPaths)
            {
                throw new ArgumentException($"{nameof(jsonPathsToDecrypt)} must have at least one item.", nameof(jsonPathsToDecrypt));
            }

            return(token.ToString(Formatting.None));
        }
예제 #2
0
        /// <summary>
        /// Asynchronously decrypts the fields, specified by XPath, that are contained in the given xml document string.
        /// </summary>
        /// <param name="crypto">
        /// The instance of <see cref="ICrypto"/> that ultimately responsible for performing decryption operations
        /// on field values.
        /// </param>
        /// <param name="xmlString">A string containing an xml document.</param>
        /// <param name="xpathsToDecrypt">One or more XPaths of the fields to decrypt.</param>
        /// <param name="credentialName">
        /// The name of the credential to use for this encryption operation,
        /// or null to use the default credential.
        /// </param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A task that will contain the same xml document, except with the specified fields decrypted.</returns>
        public static async Task <string> DecryptXmlAsync(this ICrypto crypto, string xmlString, IEnumerable <string> xpathsToDecrypt, string credentialName = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (crypto == null)
            {
                throw new ArgumentNullException(nameof(crypto));
            }
            if (xmlString == null)
            {
                throw new ArgumentNullException(nameof(xmlString));
            }
            if (xpathsToDecrypt == null)
            {
                throw new ArgumentNullException(nameof(xpathsToDecrypt));
            }

            var doc = new XmlDocument();

            doc.LoadXml(xmlString);
            var navigator = doc.CreateNavigator();

            var decryptor = new Lazy <IAsyncDecryptor>(() => crypto.AsAsync().GetAsyncDecryptor(credentialName));

            var anyPaths = false;

            foreach (var xpath in xpathsToDecrypt)
            {
                if (xpath == null)
                {
                    throw new ArgumentException($"{nameof(xpathsToDecrypt)} cannot have null items.", nameof(xpathsToDecrypt));
                }

                anyPaths = true;

                foreach (XPathNavigator match in navigator.Select(xpath))
                {
                    var decrypted = await decryptor.Value.DecryptAsync(match.InnerXml, cancellationToken).ConfigureAwait(false);

                    if (decrypted != match.InnerXml)
                    {
                        try
                        {
                            match.InnerXml = decrypted;
                        }
                        catch
                        {
                            match.SetValue(decrypted);
                        }
                    }
                }
            }

            if (!anyPaths)
            {
                throw new ArgumentException($"{nameof(xpathsToDecrypt)} must have at least one item.", nameof(xpathsToDecrypt));
            }

            return(doc.OuterXml);
        }
예제 #3
0
        /// <summary>
        /// Asynchronously encrypts the fields, specified by XPath, that are contained in the given xml document string.
        /// </summary>
        /// <param name="crypto">
        /// The instance of <see cref="ICrypto"/> that ultimately responsible for performing encryption operations
        /// on field values.
        /// </param>
        /// <param name="xmlString">A string containing an xml document.</param>
        /// <param name="xpathsToEncrypt">One or more XPaths of the fields to encrypt.</param>
        /// <param name="credentialName">
        /// The name of the credential to use for this encryption operation,
        /// or null to use the default credential.
        /// </param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A task that will contain the same xml document, except with the specified fields encrypted.</returns>
        public static async Task <string> EncryptXmlAsync(this ICrypto crypto, string xmlString, IEnumerable <string> xpathsToEncrypt, string credentialName = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (crypto == null)
            {
                throw new ArgumentNullException(nameof(crypto));
            }
            if (xmlString == null)
            {
                throw new ArgumentNullException(nameof(xmlString));
            }
            if (xpathsToEncrypt == null)
            {
                throw new ArgumentNullException(nameof(xpathsToEncrypt));
            }

            var doc = new XmlDocument();

            doc.LoadXml(xmlString);
            var navigator = doc.CreateNavigator();

            var encryptor = new Lazy <IAsyncEncryptor>(() => crypto.AsAsync().GetAsyncEncryptor(credentialName));

            var anyPaths = false;

            foreach (var xpath in xpathsToEncrypt)
            {
                if (xpath == null)
                {
                    throw new ArgumentException($"{nameof(xpathsToEncrypt)} cannot have null items.", nameof(xpathsToEncrypt));
                }

                anyPaths = true;

                foreach (XPathNavigator match in navigator.Select(xpath))
                {
                    // If there are any child elements, or the value contains escaped characters...
                    if (match.HasChildren && match.Value != match.InnerXml)
                    {
                        // ...encrypt the InnerXml property.
                        var plaintext = match.InnerXml;

                        // SetValue throws if the navigator has any child elements.
                        while (match.MoveToFirstChild())
                        {
                            match.DeleteSelf();
                        }

                        match.SetValue(await encryptor.Value.EncryptAsync(plaintext, cancellationToken).ConfigureAwait(false));
                    }
                    else
                    {
                        // Else, this is a plain value, so encrypt the Value property.
                        match.SetValue(await encryptor.Value.EncryptAsync(match.Value, cancellationToken).ConfigureAwait(false));
                    }
                }
            }

            if (!anyPaths)
            {
                throw new ArgumentException($"{nameof(xpathsToEncrypt)} must have at least one item.", nameof(xpathsToEncrypt));
            }

            return(doc.OuterXml);
        }