I need to be able to store sensitive data in an appsettings.json config file for .NET 5.0 applications. I have been using RSA encryption of config files for .NET Framework apps, but I am moving to .NET 5.0 app development instead and I want a simpler way of storing/accessing secrets than the old reg_iis.exe approach.
I have tried one approach and gotten dangerously close to having it work, but perhaps there is a better way. My approach:
$SecureString = Read-Host "Enter the String to Encrypt" -AsSecureString
$EncryptedString = ConvertFrom-SecureString -SecureString $SecureString
$EncryptedString
public static string Decrypt(this string str)
{
int length = str.Length / 2;
byte[] encryptedData = new byte[length];
for (int index = 0; index < length; ++index)
{
encryptedData[index] = byte.Parse(str.Substring(2 * index, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
// Decrypt the byte array to Unicode byte array
byte[] data = ProtectedData.Unprotect(encryptedData, null, DataProtectionScope.CurrentUser);
// Convert Unicode byte array to string
return Encoding.Unicode.GetString(data);
}
System.Security.Cryptography.ProtectedData
class. This thing is apparently not supported out of the box with .NET 5.0, instead it is a Platform Extension that can be included via NuGet. I have done so, and as I said, it works if its in an application directly, but as part of the class library, it does not... If I include the class library assembly reference in an application, the class library builds fine, but there is an exception:System.IO.FileNotFoundException: 'Could not load file or assembly 'System.Security.Cryptography.ProtectedData, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.'
It's not deploying the ProtectedData .dll to the consuming application, and I think it should be...
So, am I doing this inherently wrong, or am I close?
You're running into missing assembly errors because you're referencing the compiled library directly. The build system doesn't know about its dependencies (i.e. ProtectedData.dll), so it doesn't include them in your output folder when you build the application.
When you instead reference the library as a project, the build system can figure out everything that the library depends on by reading the project file, and include those dependencies in the output folder.
If you really need to reference the DLL directly for some reason, you need to copy its dependencies (generally the entire output folder from building it) into your application's directory.
It's much easier to just reference it as a project, unless there's some constraint preventing it. If it's not possible, deploying and referencing it as a NuGet package is an alternative that will ensure you automatically get all of the dependencies, but that comes with its own complexity.
On the topic of what you're trying to do with appsettings, this isn't going to work.
The methods you're calling pass through to the winapi CryptProtectData
and CryptUnprotectData
methods. They use a key derived from your login credentials, so it's not possible for data encrypted on one machine to be decrypted by another machine (or even another user on the same machine).
You can read up on alternative approaches for storing sensitive information here: https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0&tabs=windows