Hands off crypto - useful for protecting app.config values and performing install time machine fingerprinting...
Recently I was asked to provide better security / encryption on several data items normally contained within a CONFIG file.... for example a connection string or other sensitive data values.
Of course this is a trivial task these days with the security classes available in the .NET world. However, these techniques require some sort of Key/Salt values which in turn become sensitive data values that require protection. Oh Mama make it stop.
So the goal becomes one of making encryption/decryption self contained - in other words secure to each machine / instance without the need for any user involvement or support staff maintenance.
Our first step will be conjuring up some unique and repeatable strings for use as a key/salt value pair. I remembered some old techniques for digging out serial numbers for specific components on the computer system. Using a collection of these values - and passing the result to a HASH generator - we can easily produce a unique string of 32 characters. See the FingerPrint class in the source code for this bit of magic.
Once we have a repeatable hash string - we can easily pick off fixed portions of it for the key/salt value pairs - the Fingerprint class offers both 8 and 16 character sub parts of the fingerprint by pealing off the leading chars for the key and the trailing chars for the salt.
- Provides 32 character (hash) of machine FingerPrint
- This class provides Static methods from which one can obtain the right and left 8 chars of the Fingerprint
- These 8 char keys are assumed by Crypto to be the Key/Salt values used in DESCrypto
Next we pick a encryption / decryption class from the
namespace - I chose DES... And create a simply Crypto class.
- Provides string encryption and decryption services
- This class exposes two methods (Encrypt and Decrypt) into which one is expected to pass a data string to cypher
- Decrypt of course expects a encrypted string to decrypt
- Encrypt of course expects a raw text string to encrypt.
- Decrypt and Encrypt are overridden allowing passing of Key and/or Salt values to be used.
Using the Code
Reference the GCSSecurity.dll
assembly in your project
Step 2 Declare an instance of the Crypto Class
GCS.Security.Crypto _crypto = new GCS.Security.Crypto();
Dim _crypto as New GCS.Security.Crypto()
To encrypt a string:
String encrypted = _crypto.Encrypt("my raw text string");
Dim encrypted As String = _crypto.Encrypt("my raw text string")
To decrypt an encrypted string:
String decrypted = _crypto.Decrypt(encrypted);
Dim decrypted As String = _crypto.Encrypt(encrypted)
The source provided also contains a tester application which contains working handlers for all the above.
By making use of the
class we can now easily hide sensitive values in the application CONFIG file using code something like this...
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
if (config.AppSettings.Settings["myKey"] != null)
config.AppSettings.Settings["myKey"].Value = _crypto.Encrypt("My RAW data value");
Points of Interest
Assume for a moment that we have a installer for our application - and we wish to hide some special values contained in the config file...
One might wish to use the InstallerClass.Commit event handler and perform something like the above... with the raw text value already resident in the app.config file...
By placing the ENCRYPT call inside of the installer... we only have to perform the Decrypt on the config value during program execution.
We in fact have done this very thing in the orginal client request that spawned this solution - they asked for a Windows Service assembly - which has a database connection value in the config file. We have a custom dialog box during the install which collects and tests the database connection... once tested the resulting connection string is encrypted and saved to the app.config.
Our runtime code - the handler expecting to perform the decryption - performs a simple test for part of a valid connection string - like Contains("Catalog").... in the event the given substring is NOT present we assume it is encrypted... otherwise we assume the connection string is found in raw text form and do not decrypt - this affords tech support to modify the connection string without the worry of keys/salt or encryption.
Feature or Bug?
When calling the Crypto methods (single string overrides) our class will obtain the key / salt from the machine the code is executing on... This implies that one MUST not pass an encrypted string around to different computers. Which is why we performed the encryption during app install... for the install is executing on the same computer that will be executing the applicaiton.
We feel this is a feature - but for those that see this as a bug - we refer you to the Crypto overrides that accept the string along with key and salt values....
It would be a trival matter to include in the app.config, the fingerprint used for encryption - and thus have it available for decryption at runtime.
I believe the source is laid out in easy to follow form... so for complete reference I suggest looking at the source.