92 lines
3.4 KiB
C#
92 lines
3.4 KiB
C#
// 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
|
|
{
|
|
/// <summary>
|
|
/// An <see cref="IXmlDecryptor"/> that decrypts XML elements that were encrypted with <see cref="DpapiNGXmlEncryptor"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This API is only supported on Windows 8 / Windows Server 2012 and higher.
|
|
/// </remarks>
|
|
public sealed class DpapiNGXmlDecryptor : IXmlDecryptor
|
|
{
|
|
private readonly ILogger _logger;
|
|
|
|
/// <summary>
|
|
/// Creates a new instance of a <see cref="DpapiNGXmlDecryptor"/>.
|
|
/// </summary>
|
|
public DpapiNGXmlDecryptor()
|
|
: this(services: null)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new instance of a <see cref="DpapiNGXmlDecryptor"/>.
|
|
/// </summary>
|
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to provide ancillary services.</param>
|
|
public DpapiNGXmlDecryptor(IServiceProvider services)
|
|
{
|
|
CryptoUtil.AssertPlatformIsWindows8OrLater();
|
|
|
|
_logger = services.GetLogger<DpapiNGXmlDecryptor>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Decrypts the specified XML element.
|
|
/// </summary>
|
|
/// <param name="encryptedElement">An encrypted XML element.</param>
|
|
/// <returns>The decrypted form of <paramref name="encryptedElement"/>.</returns>
|
|
public XElement Decrypt(XElement encryptedElement)
|
|
{
|
|
if (encryptedElement == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(encryptedElement));
|
|
}
|
|
|
|
try
|
|
{
|
|
// <encryptedKey>
|
|
// <!-- This key is encrypted with {provider}. -->
|
|
// <!-- rule string -->
|
|
// <value>{base64}</value>
|
|
// </encryptedKey>
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|