// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Xml.Linq; using Microsoft.AspNetCore.Cryptography; using Microsoft.AspNetCore.DataProtection.Cng; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.DataProtection.XmlEncryption { /// /// An that decrypts XML elements that were encrypted with . /// /// /// This API is only supported on Windows 8 / Windows Server 2012 and higher. /// public sealed class DpapiNGXmlDecryptor : IXmlDecryptor { private readonly ILogger _logger; /// /// Creates a new instance of a . /// public DpapiNGXmlDecryptor() : this(services: null) { } /// /// Creates a new instance of a . /// /// An optional to provide ancillary services. public DpapiNGXmlDecryptor(IServiceProvider services) { CryptoUtil.AssertPlatformIsWindows8OrLater(); _logger = services.GetLogger(); } /// /// Decrypts the specified XML element. /// /// An encrypted XML element. /// The decrypted form of . public XElement Decrypt(XElement encryptedElement) { if (encryptedElement == null) { throw new ArgumentNullException(nameof(encryptedElement)); } try { // // // // {base64} // byte[] protectedSecret = Convert.FromBase64String((string)encryptedElement.Element("value")); if (_logger.IsDebugLevelEnabled()) { string protectionDescriptorRule; try { protectionDescriptorRule = DpapiSecretSerializerHelper.GetRuleFromDpapiNGProtectedPayload(protectedSecret); } catch { // swallow all errors - it's just a log protectionDescriptorRule = null; } _logger.DecryptingSecretElementUsingWindowsDPAPING(protectionDescriptorRule); } using (Secret secret = DpapiSecretSerializerHelper.UnprotectWithDpapiNG(protectedSecret)) { return secret.ToXElement(); } } catch (Exception ex) { // It's OK for us to log the error, as we control the exception, and it doesn't contain // sensitive information. _logger?.ExceptionOccurredTryingToDecryptElement(ex); throw; } } } }