![]() |
Sphyrnidae Common Library
2.0.1
Shared Utilities/Library
|
Encryption turns a string with valuable information (eg. passwords, credit card numbers, personal information, etc) into an encrypted value. This encrypted value will be meaningless to the hacker unless they have a key to decrypt it, and the correct algorithm to do so. The IEncryption interface defines the methods needed for encryption:
The implementation EncryptionDispatcher makes everything configurable:
Interface: IEncryption
Mock: EncryptionNone
Implementations:
Wrapper: EncryptionExtensions (string extension methods)
The preferred implementation of IEncryption is the EncryptionDispatcher. How this works is that any encryption attempt will use the default key, which will also be linked to a unique identifier. It will also use the default algorithm, which also has a unique identifier. These identifiers will be a part of the final encryption string so that the decryption attempt knows which key and algorithm to use.
This implementation utilizes 2 additional interfaces for it's functionality:
An encryption key is a secret key (usually a string, Base64 string, or byte[]) that you must possess to encrypt or decrypt. Without this key, an encrypted value will be impossible to decrypt. Because of the importance of this key, it must be kept in a secure location such as:
Which one you choose is completely up to you and your security needs. The end result is that you should have at least 1 key (possibly more), and have an invalidation scheme for these keys.
EncryptionDispatcher will perform lookup of encryption keys via the interface IEncryptionKeyManager.
As with encryption keys, you may wish to have a dynamic set of encryption algorithms in case one of them gets compromised. These algorithms will ultimately inherit from IEncryption, so you could directly register these as an IEncryption implementation. However, it would be better to keep multiple algorithms on-hand and swich as necessary. This will also allow you to decrypt older strings that may have been encrypted using a previous method.
The EncryptionDispatcher does this utilizing the IEncryptionAlgorithms interface. You essentially specify all the possible algorithms, which one is current, and you're off and running.
The default implementation of the IEncryptionAlgorithms interface is SphyrnidaeEncryptionAlgorithms. This registers the following algorithms:
If no key is found, the 'void' algorithm is EncryptionOld. You should likely implement your own set of algorithms.
// // Registering your own algorithm(s) // // Create the algorithm (Note this is not using the key mangaer) public class MyEncryptionAlgorithm : EncryptionAlgorithm { private IEncryptionKeyManager KeyManager { get; set; } public MyEncryptionAlgorithm(IEncryptionKeyManager keyManager) => KeyManager = keyManager; public override string Id => "my unique algorithm id"; public override DecryptionResponse Decrypt(string str) => new DecryptionResponse { IsCurrent = true, Value = "decrypted value" }; public override string Encrypt(string str) => "Encrypted Value"; public override byte[] Hash(string str, string salt) => new byte[0]; } // Create registration class public class MyEncryptionAlgorithms : SphyrnidaeEncryptionAlgorithms { public MyEncryptionAlgorithms(IEncryptionKeyManager manager) : base(manager) { } public override List<EncryptionAlgorithm> All => new List<EncryptionAlgorithm> { Current }; public override EncryptionAlgorithm Current => new MyEncryptionAlgorithm(Manager); public override EncryptionAlgorithm Void => Current; } // Update service registration (startup.cs) services.Transient<IEncryptionAlgorithms, MyEncryptionAlgorithms>(); // // Custom Key Manager // // Create the key manager public class MyKeyManager : IEncryptionKeyManager { // Will want to look these up from a key vault public EncryptionKey CurrentKey => new EncryptionKey { Id = "my key identifier", Key = "my encryption key", IsCurrent = true }; public FoundEncryptionKey GetKeyFromString(string encrypted) { if (!encrypted.StartsWith(CurrentKey.Id)) // May look for other keys in the key vault that match throw new Exception("Unable to locate matching encryption key"); return new FoundEncryptionKey(CurrentKey, encrypted); } } // Update service registration (startup.cs) services.Transient<IEncryptionKeyManager, MyKeyManager>(); // // Performing Encryption // IEncryption encryption; // Should be injected var myVal = "string to encrypt"; var encrypted = myVal.Encrypt(encryption); var decrypted = encrypted.Decrypt(encryption); if (string.IsNullOrWhiteSpace(decrypted.Value)) throw new Exception("Unable to decrypt"); if (!decrypted.IsCurrent) var updatedEncryption = decrypted.Value.Encrypt(encryption); // Store this back into your repository with latest method return decrypted.Value;