Getting started

edit

Install the package

Add the Meziantou.Framework.SensitiveData package to a project:

dotnet package add Meziantou.Framework.SensitiveData

The examples of this documentation omit the using directives: they need using Meziantou.Framework;.

Store and reveal a secret

SensitiveData.Create copies a value into a new SensitiveData<T>. The contents stay protected until a Reveal method is called:

// Create sensitive data from a string
using var secret = SensitiveData.Create("secret");

// Reveal the data
string str = secret.RevealToString();
char[] chars = secret.RevealToArray();
Assert.Equal("secret", str);
Assert.Equal("secret".ToCharArray(), chars);

var buffer = new char[secret.GetLength()];
secret.RevealInto(buffer);

// Or use it without keeping a copy of your own
var lengths = new List<int>();
secret.RevealAndUse(arg: lengths, static (span, list) => list.Add(span.Length));
Assert.Equal([6], lengths);

// Create sensitive data from a buffer of any unmanaged type
using var key = SensitiveData.Create(new byte[] { 1, 2, 3, 4, 5 });
byte[] revealedKey = key.RevealToArray();
Assert.Equal(new byte[] { 1, 2, 3, 4, 5 }, revealedKey);

Keep secrets out of logs

Once the secret is in a SensitiveData<T>, the usual ways a value escapes do not show it:

using var secret = SensitiveData.Create("my-password");

// Formatting the instance gives its type name, not its contents
var message = $"Connecting with {secret}";
Assert.DoesNotContain("my-password", message, StringComparison.Ordinal);

// Serializing it gives an empty object
var json = JsonSerializer.Serialize(secret);
Assert.Equal("{}", json);

The same goes for a logger that formats the value, or an object that holds a SensitiveData<T> property and is serialized as a whole. To show or send the secret, reveal it explicitly.

The value you pass stays in memory

Create copies the value: the string or the array you pass is not changed and stays in memory until the garbage collector reclaims it. Create the SensitiveData<T> as close as possible to where the secret enters the application, and clear the arrays you own once the copy is made, for instance with CryptographicOperations.ZeroMemory. A string cannot be cleared.

Next steps