Create a instance of IDataProtectionProvider asp.net core

Viewed 10090

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

3 Answers

You can refer to a Microsoft recomendation on how to use Data Protection for non-DI solutions (https://docs.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);
    }
}

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.

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.

Related