1

I have data that's being encrypted by .NET Framework 4.5.1 code using FormsAuthentication.Encrypt, and I need to be able to decrypt it in code using dotnet core 3.1.

Based on this documentation, I believe I should be able to make this work by using Microsoft.AspNetCore.DataProtection.SystemWeb on the .NET Framework side, and configuring data protection identically on the dotnet core side. However, I get the following error instead:

CryptographicException: The payload was invalid.

On the .NET Framework side, I configure data protection as documented:

public class DataProtector : DataProtectionStartup
{
    public override void ConfigureServices(IServiceCollection services)
    {
        services.AddDataProtection()
            .SetApplicationName("myapp")
            .PersistKeysToFileSystem(new System.IO.DirectoryInfo("C:\\PathToKeys\\"));
    }
}

The encrypted value is the direct output of FormsAuthentication.Encrypt(ticket);. I've confirmed that it uses the new mechanism: It persists keys to the file system, and the resulting cipher text leads with the expected 09F0C9F0 header, and the dotnet core code both recognizes it and is able to recognize that it has a relevant key. However, it fails to actually Unprotect.

The dotnet core code uses that as the value of "ciphertext" in the following code:

static void Main(string[] args)
{
    var provider = DataProtectionProvider.Create(new DirectoryInfo("/pathToKeys"));
    var protector = provider.CreateProtector("myapp");//("FormsAuthentication.Ticket");
    byte[] b = HexToBinary(ciphertext);
    protector.Unprotect(b); // Error thrown here
}

Based on my reading of the relevant code, I've attempted using a few alternate purposes such as "FormsAuthentication.Ticket" but without any luck. Is there a step I'm missing here, or a purpose I need to specify that I don't know about?

Adding the HexToBinary code as suggested. This is lifted directly from Microsoft.

        public static byte[] HexToBinary(string data)
    {
        if (data == null || data.Length % 2 != 0)
        {
            // input string length is not evenly divisible by 2
            return null;
        }

        byte[] binary = new byte[data.Length / 2];

        for (int i = 0; i < binary.Length; i++)
        {
            int highNibble = HexToInt(data[2 * i]);
            int lowNibble = HexToInt(data[2 * i + 1]);

            if (highNibble == -1 || lowNibble == -1)
            {
                return null; // bad hex data
            }
            binary[i] = (byte)((highNibble << 4) | lowNibble);
        }

        return binary;
    }
    public static int HexToInt(char h)
    {
        return (h >= '0' && h <= '9') ? h - '0' :
        (h >= 'a' && h <= 'f') ? h - 'a' + 10 :
        (h >= 'A' && h <= 'F') ? h - 'A' + 10 :
        -1;
    }
2
  • Maybe you can refer to this,and see what Chris Pratt said. Commented Sep 22, 2020 at 2:59
  • Thanks, but that's essentially what I'm already doing here by using Microsoft.AspNetCore.DataProtection.SystemWeb in order to replace the machine key mechanism. Commented Sep 22, 2020 at 15:00

1 Answer 1

1

I was able to work this one out. The code above works when specifying FormsAuthentication.Ticket as a subPurpose value:

static void Main(string[] args)
{
    var provider = DataProtectionProvider.Create(new DirectoryInfo("/pathToKeys"));
    var protector = provider.CreateProtector("myapp", new string[] {"FormsAuthentication.Ticket"});
    byte[] b = HexToBinary(ciphertext);
    protector.Unprotect(b);
}

Note that this shakes out a little differently in some other cases. For instance, when used in a web service, I needed to add data protection e.g.

WebHost.CreateDefaultBuilder(args)
.ConfigureServices(configureServices => {
    configureServices.AddDataProtection()
    .SetApplicationName("myapp")
    .PersistKeysToFileSystem(new DirectoryInfo(keyPath));
})
.UseStartup<Startup>()
.Build();

After this, subsequent calls can create the relevant protector as follows:

public Foo(IDataProtectionProvider provider)
{
    var protector = provider.CreateProtector("FormsAuthentication.Ticket");
    protector.Unprotect(ciphertext);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.