Moving the protected memory from a private backing field to a property will not help as now one only needs to read a public property, and the memory protected by the class ProtectedMemory can be read by any application that injected in your assembly and run in your process, there are a lot of ways to do that!
I guess that's why MS stoped with secure string and ProtectedMemory in the newer frameworks as it really doesn't make much of a difference to a skilled attacker or some fool with the right tools...
What else... well one imported thing to note is that this is you need to clean up any memory that contains GDPR related data asap as one can use Heap inspection to find confidential data.
Basically what you need to do is use encryption and only make data accessible when you need it and clear it as soon as you do not.
As to your problem, here is one way I solve it using my Walter.Cypher nuget package. I used your class added a salad and assumed you would like to prevent anyone else using my NuGet package from reading your data by "padding the password".
using System;
using System.Text;
public class User
{
public User(int id, string name)
{
Id = id;
_name = name.Encrypt(
string.Concat(Id, "APPLICAT10N PA$$wo0rd").AsShaHash(HashMethod.SHA1, 8) //use a salt based key protect the user and the application
, Walter.Cypher.CipherMethod.Medium //use a 365 bit hash
);
}
public int Id { get; }
private byte[] _name;
internal string GetName()
{
return _name.Decrypt(
string.Concat(Id, "APPLICAT10N PA$$wo0rd").AsShaHash(HashMethod.SHA1, 8) //use a salt based key protect the user and the application
, Walter.Cypher.CipherMethod.Medium //use a 365 bit hash
);
}
}
public class UserViewModel : IDisposable
{
User _user;
private Lazy<string> _userName;
private bool _disposedValue;
public UserViewModel(User user)
{
_user = user;
_userName =new Lazy<string>(_user.GetName());
}
public string Name
{
get => _userName.Value;
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
//do what you need to do
}
_userName = null;
_disposedValue = true;
}
}
~UserViewModel()
{
Dispose(disposing: false);
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
This code will work on all platforms as it does not rely on any window API but asymmetric encrtiption.
Whenever you feel the need to use a property to store confidential data, make sure you understand that that is a security issue.