JsonCryption.Newtonsoft offers Field Level Encryption (FLE) when serializing/deserializing between .NET objects and JSON.
Install-Package JsonCryption.Newtonsoft
dotnet add package JsonCryption.Newtonsoft
Field Level Encryption of C# objects during JSON serialization/deserialization should be:
- Relatively easy to use
- Powered by industry-standard cryptography best-practices
With default configuration, encrypting a field/property just requires decorating it with EncryptAttribute
, and serializing the object as usual:
// decorate properties to be encrypted
class Foo
{
[Encrypt]
public string MySecret { get; set; }
}
// serialize as normal
Foo foo = new Foo() { ... };
JsonSerializer serializer = ...
using TextWriter textWriter = ...
serializer.Serialize(textWriter, foo);
More details on usage scenarios can be found below.
Currently, JsonCryption.Newtonsoft is built on top of the Microsoft.AspNetCore.DataProtection
library for handling encryption-related responsibilities:
- Encryption/decryption
- Key management
- Algorithm management
- etc.
Internally, we only depend on the two interfaces IDataProtector
and IDataProtectionProvider
. If you don't want to use Microsoft's implementations, you could just depend on Microsoft.AspNetCore.DataProtection.Abstractions
and provide alternative implementations of IDataProtector
and IDataProtectionProvider
. One use case for this functionality might be creating a segregated IDataProtector
per user, potentially making it easy to support GDPR's "right to forget" user data.
JsonCryption.Newtonsoft should support any type serializable by Newtonsoft.Json. If you spot a missing type, please let me know (or better yet, create a PR!).
JsonCryption.Newtonsoft depends on the Microsoft.AspNetCore.DataProtection
library. Therefore, you should first ensure that your DataProtection layer is configured properly.
NOTE: Technically, since we only rely on the interfaces IDataProtector
and IDataProtectionProvider
, you don't need to configure this layer according to Microsoft's docs linked to above... You could just create any custom object to implement these two interfaces. Just be aware of the risks. It would probably be better to create a broader adapter layer that could include a number of managed encryption providers more directly.
To configure JsonCryption.Newtonsoft with dependency injection, you'll need to register your default JsonSerializer with our EncryptedContractResolver
:
// pseudo code
container.Register<JsonSerializer>(() => new JsonSerializer()
{
ContractResolver = new EncryptedContractResolver(container.Resolve<IDataProtectionProvider>())
});
Once configured, using JsonCryption.Newtonsoft is just a matter of decorating the properties/fields you wish to encrypt and the EncryptAttribute
and serializing your C# objects as you normally would:
class Foo
{
[Encrypt]
public string EncryptedString { get; }
public string UnencryptedString { get; }
}
var myFoo = new Foo("some important value", "something very public");
// serializing
var serializer = ...
var builder = new StringBuilder();
using var textWriter = new StringWriter(builder);
serializer.Serialize(textWriter, myFoo);
var json = builder.ToString();
// deserializing
using var textReader = new StringReader(json);
using var reader = new JsonTextReader(textReader);
var deserialized = serializer.Deserialize<Foo>(json);
We're trying to maintain feature parity when it comes to annotations, but I'm likely missing finer details in places. Let me know if you spot something. When in doubt, verify what's possible via the tests
The easiest way to do this is to decorate the field/property with an additional JsonPropertyAttribute
:
class NonPublicFoo
{
[Encrypt]
[JsonProperty]
internal string InternalProperty { get; set; }
[Encrypt]
[JsonProperty]
protected bool ProtectedField;
[Encrypt]
[JsonProperty]
private Guid PrivateProperty { get; set; }
}
JsonCryption.Newtonsoft is open to PRs and more regular contributors. Feel free to reach out if you're interested in helping.
Next, I'm hoping to do some benchmarking...