Following DDD practices, I am running into a problem while implementing a small AES encryptor/decryptor (wrapping .NET's AesCryptoServiceProvider
).
public class Aes256CbcCryptor : ISymmetricCryptor
{
private SymmetricAlgorithm AesProvider { get; set; }
// Poor man's DI - beside the point
public Aes256Cbc()
{
this.AesProvider = new AesCryptoServiceProvider()
{
BlockSize = 128,
KeySize = 256,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
Key = // OH DEAR IT TAKES STATE
};
}
public Aes256Cbc(SymmetricAlgorithm aesProvider)
{
this.AesProvider = aesProvider;
}
public byte[] Encrypt(byte[] keyBytes, byte[] plaintextBytes)
{} // TODO
public byte[] Decrypt(byte[] keyBytes, byte[] ciphertextBytes)
{} // TODO
}
As you can see, .NET's AesCryptoServiceProvider
is stateful - it takes a key as a property. But as I've come to understand, services are not supposed to be stateful.
- Is the key being a property (rather than, say, a method parameter) the main thing going wrong here?
- How would you implement the class in a DDD way?
- In some situations, having a provider initialized with a given key seems useful and efficient (if that key is to be used a lot). Is there a justification for stateful services, or an alternative?
I imagine we could just instantiate a new Provider on every method call, but it seems very wasteful. We could implement caching to reduce the waste, but the whole thing then starts feeling overengineered.
Another alternative I have come up with is to create an Aes256CbcCryptorFactory
instead. The factory's CreateCryptor(byte[] key)
returns a Value Object Aes256CbcCryptor
that is actually stateful. A consuming service could now at least keep this object around in the scope of one of its methods, if it needs to make multiple cryptor calls.
On the other hand, such a consuming service could still not store the Value Object in one of its properties, as doing so would make that service stateful.
- Seeing as there are some benefits, is this a thing that is done? The type of behavior seems very servicey for a Value Object, but at least we can have some temporary state.