7

I am trying to create a static class and methods to encrypt and decrypt data in asp.net core.

But the problem is that I have to get the "IDataProtectionProvider provider" in constructor with DI and then pass it to the methods so that a CreateProtector be used.

I donot want that and directly want to instanciate the IDataProtectionProvider provider in the method it self.

The controller code:

private readonly IDataProtectionProvider _provider;
public addMDL(IDataProtectionProvider provider)
{
    _provider = provider;
}

public IActionResult OnGet()
{
    DataProProvider.decData(0, "ABC", _provider)
}

and the static class is :

public static class DataProProvider
{

    public static string encData(int intData, string strData, IDataProtectionProvider provider)
    {
        string str;
        IDataProtector dataProtector;
        dataProtector = provider.CreateProtector("AA");
        if (!string.IsNullOrEmpty(strData))
        {
            str = dataProtector.Protect(strData);
        }
        else
        {
            str = dataProtector.Protect(intData.ToString());
        }
        return str;
    }

    public static string decData(int intData, string strData, IDataProtectionProvider provider)
    {
        string str;
        IDataProtector dataProtector;
        dataProtector = provider.CreateProtector("A3");
        if (!string.IsNullOrEmpty(strData))
        {
            str = dataProtector.Unprotect(strData);
        }
        else
        {
            str = dataProtector.Unprotect(intData.ToString());
        }
        return str;
    }
}

[UPDATE]

As per suggestion I have moved to a smpler approch using Encrypting & Decrypting a String in C# enter link description here

user614946
  • 599
  • 5
  • 10
  • 27
  • I suppose I'm still uncertain what your intention is here. you're trying to remove the notion of resolving this type at the controller and want to resolve it in your static class constructor, or each time a particular method is called? – Brett Caswell Aug 25 '18 at 19:37
  • also, to me.. it looks like your building extension methods: `public static string encData(this IDataProtectionProvider provider, int intData, string strData) {...} ` – Brett Caswell Aug 25 '18 at 19:38
  • Brett its not an extension..plain old static method – user614946 Aug 26 '18 at 01:42

3 Answers3

8

You can refer to a Microsoft recomendation on how to use Data Protection for non-DI solutions (https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/non-di-scenarios?view=aspnetcore-2.2).

Briefly, use static method DataProtectionProvider.Create() for that:

using Microsoft.AspNetCore.DataProtection;
static class Program
{
    static void Main()
    {
        var dataProtectionProvider = DataProtectionProvider.Create("Test App");
        var protector = dataProtectionProvider.CreateProtector("Program.No-DI");
        var plainText = "ABCDEFGH";
        var protectedText = protector.Protect(plainText);
    }
}
zergius
  • 344
  • 1
  • 6
  • 12
  • How to include Microsoft.AspNetCore.DataProtection to console application? – sergtk Feb 22 '20 at 19:50
  • @sergtk You should be able to use NuGet to add the parent library for it, (assuming use of .NET core). Please post your own question if you are having trouble with this. Ref. for NuGet package: https://www.nuget.org/packages/Microsoft.AspNetCore.DataProtection/ – ryanwebjackson Jul 04 '21 at 21:10
4

Browsing the sources it seems that instantiating an IDataProtectionProvider without DI can be achieved only through some reflection hacking or code duplicating.

Having a look at this code you can see what implementations are registered for the various interfaces in the DI container. E.g. the implementation for IDataProtectionProvider is KeyRingBasedDataProtectionProvider. Now check out the source of that class. It's internal so you cannot instantiate it outside the declaring assembly (without reflection). After some more digging, it turns out that the provider creates KeyRingBasedDataProtector instances which is declared as internal, as well.

All this suggests that DataProtection API is not intended to be used without a DI container. You should reconsider that you really want to use it that way.

Adam Simon
  • 2,762
  • 16
  • 22
  • 5
    It's also worth noting that the data protection API isn't intended for long term storage. From https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/consumer-apis/limited-lifetime-payloads?view=aspnetcore-2.1 "It's not advised to use these APIs to protect payloads which require long-term or indefinite persistence. 'Can I afford for the protected payloads to be permanently unrecoverable after a month?' can serve as a good rule of thumb; if the answer is no then developers should consider alternative APIs." That may not be an issue for the OP, but worth noting. – Justin Helgerson Aug 25 '18 at 19:17
  • Justin, thanks for pointing that out, i' ll look for some other api also. – user614946 Aug 26 '18 at 01:39
  • Thanks Adam, i will look for some other way or api. – user614946 Aug 26 '18 at 01:40
  • I believe the comment regarding long term storage refers to time limited protector interface ITimeLimitedDataProtector – gbro3n Feb 15 '21 at 23:08
  • Your link is dead. – Erik Philips Sep 17 '21 at 07:25
  • 2
    @ErikPhilips Fixed. I hope MS has finally stopped moving around their repos... – Adam Simon Sep 17 '21 at 13:42
0

The use of DI cannot be avoided due to the implementation under the hood. If you have a look at the "non DI example" DataProtectionProvider.Create(...) you'll see, that they're using a dedicated composition root just for providing the protector.

Inspired by this I wrote this method:

private static IDataProtectionProvider CreateDataProtectionProviderWithPostgresKeyRepository(string connectionString)
{
    var services = new ServiceCollection();
    var builder = services.AddDataProtection();
    
    builder.Services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(sp =>
    {
        return new ConfigureOptions<KeyManagementOptions>(options =>
        {
            options.XmlRepository = new PostgresDataProtectionKeyRepository(connectionString);
        });
    });
    
    return services.BuildServiceProvider().GetRequiredService<IDataProtectionProvider>();
}

where PostgresDataProtectionKeyRepository is just a stupid implementation of IXmlRepository used to store the keys in the database.

Marc Wittke
  • 2,991
  • 2
  • 30
  • 45