David
David

Reputation: 67

Porting machinekey.protect encryption from .net 4.5 to .net 7.0 (c#)

I'm working on porting a solution from .net 4.5.2 to .net 7.0. In this solution there is a class used to decrypt data which is encoded using MachineKey.Protect on a different device (the data is stored in a database). In .net 7.0 MachineKey.Protect no longer exists.

The original code is as follows:

    public class EncryptionHandler
    {
        public string Protect(byte[] data)
        {
            if (data == null || data.Length == 0) return null;
            var value = MachineKey.Protect(data);
            return Convert.ToBase64String(value);
        }

        public string Unprotect(string value)
        {
            if (value == "") return value;
            return Encoding.Unicode.GetString(MachineKey.Decode(value, MachineKeyProtection.Encryption));
        }

        internal void HackMachineKey() //This is used to insert the machinekey from the other device
        {
            var getter = typeof(MachineKeySection).GetMethod("GetApplicationConfig", BindingFlags.Static | BindingFlags.NonPublic);
            var config = (MachineKeySection)getter.Invoke(null, null);
            Console.WriteLine("Current Decryptionkey: " + config.DecryptionKey);
            var readOnlyField = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
            readOnlyField.SetValue(config, false);

            config.DecryptionKey = Properties.Settings.Default.MachineKeyDecryptionKey; 
            config.ValidationKey = Properties.Settings.Default.MachineKeyValidationKey;

            readOnlyField.SetValue(config, true);
        }
    }

In my port to .net 7 I try to insert the keys as "purposes", but that obviously is not working:

    internal class NewEncryptionHandler
    {
        private static Logger _logger = LogManager.GetCurrentClassLogger();
        private IDataProtector _protector;
        //ToDo: move to external config
        private string _decryptionKey = "myMachineKey";
        private string _validationKey = "myValidationKey";

        internal NewEncryptionHandler(Config config)
        {
            var provider = DataProtectionProvider.Create("EzGetSettings");
            _protector = provider.CreateProtector(config.DecryptionKey, config.ValidationKey, "MachineKeyProtection.All");
        }

        internal string Unprotect(string? value)
        {
            byte[] protectedData = Encoding.UTF8.GetBytes( value);
            var unprotected= _protector.Unprotect(protectedData);
            return Convert.ToBase64String(unprotected);
        }
    }

I'm unsure how to create or config the DataProtectionProvider properly. Any help would be much appreciated!

Upvotes: 0

Views: 128

Answers (1)

Denis Michealk
Denis Michealk

Reputation: 1850

Following this Example from the documentation.

Make sure to add this in the Program.cs.

builder.Services.AddDataProtection();

Then in your class Dependency inject the interface IDataProtectionProvider in the constructor like below:

public class NewEncryptionHandler
{
   IDataProtector _protector;

   public NewEncryptionHandler(IDataProtectionProvider provider)
   {
     _protector = provider.CreateProtector("purpose");
   }
}

and then in your NewEncryptionHandler to encrypt:

var encrypted = _protector.Protect("TEST");

to decrypt:

var decrypted = _protector.Unprotect(encrypted);

EDIT

An Example with Console and using the main method:

static void Main(string[] args)
{
    // add data protection services
    var serviceCollection = new ServiceCollection();
    serviceCollection.AddDataProtection();
    var serviceProvider = serviceCollection.BuildServiceProvider();


    // Create a data protector
    var dataProtector = serviceProvider.GetService<IDataProtectionProvider>();

    // Create an instance of NewEncryptionHandler
    var newEncryptionHandler = new NewEncryptionHandler(dataProtector);

    // Call encryption and decryption methods
    var plainText = "Hello, world!";
    var encryptedData = newEncryptionHandler.EncryptData(plainText);
    var decryptedText = newEncryptionHandler.DecryptData(encryptedData);


    Console.WriteLine($"Plain text: {plainText}");
    Console.WriteLine($"Encrypted data: {encryptedData}");
    Console.WriteLine($"Decrypted text: {decryptedText}");
}

The NewEncryptionHandler Class:

public class NewEncryptionHandler
{
    private readonly IDataProtector _dataProtector;

    public NewEncryptionHandler(IDataProtectionProvider dataProtector)
    {
        _dataProtector = dataProtector.CreateProtector("purpose");
    }

    public string EncryptData(string plainText)
    {
        // Encrypt data using the data protector
        return _dataProtector.Protect(plainText);
    }

    public string DecryptData(string encryptedData)
    {
        // Decrypt data using the data protector
        return _dataProtector.Unprotect(encryptedData);
    }
}

Upvotes: 1

Related Questions