Introduction
This articles shows how to create a basic wrapper for encrypting and decrypting strings using existing built-in methods in the .NET framework that are by default not accessible.
Background
I had to reverse engineer script resource URLs (like ScriptResource.axd?d=WIkfIHx2pe1WhCNefMjMESVyFb1-lrFL...) for a script combining project, so I could actually put resource paths like System.Web.Forms.js instead of those long unfriendly URLs in the config files... One thing I noticed is that resource names are getting encrypted using the MachingKeySection
class, and since all of those really useful methods are either declared as private
or internal
, I have decided to create a wrapper that would enable me to easily access all those functionalities.
Using the code
The code is pretty straightforward if you know what to look for in the .NET framework. First of all, we get the type of the class we are looking for. In this case, it's the MachineKeySection
class which contains the EncryptOrDecryptData
method we are looking for.
Type machineKeySection = typeof(System.Web.Configuration.MachineKeySection);
Now that we know the type, we can use Reflection to get a reference to the EncryptOrDecryptData
method. This method is used for almost everything internally by the .NET framework. So now, we have the power to decrypt almost everything. Since the computer's machine key is used as the encryption key, we can only decrypt data what was encrypted on the same server.
MethodInfo _EncDecMethod = machineKeySection.GetMethod("EncryptOrDecryptData",
BindingFlags.NonPublic | BindingFlags.Static, Type.DefaultBinder,
new[] { typeof(bool), typeof(byte[]), typeof(byte[]), typeof(int), typeof(int) },
null);
Now that we have a reference to the encryption-decryption method, we can invoke it.
internal static byte[] EncryptOrDecryptData(bool fEncrypt, byte[] buf,
byte[] modifier, int start, int length)
bool fEncrypt
- set to true
if you want the data to be encrypted, or to false
if you want the data to be decrypted.
byte[] buf
- data that you want to encrypt or decrypt.
int length
- Length of the data, usually just buf.length
if you want to encrypt or decrypt the entire byte array.
Extending
If you require string encryption and decryption, then you could extend the functionalities of your class by adding two other methods. One for decrypting and one for encrypting data. Instead of passing in a byte array and converting it to a string and vice versa, you would only pass in a string and also get a string as the result.
Encryption example:
string data = "Encrypt me";
byte[] bytes = Encoding.UTF8.GetBytes(data);
byte[] encData = (byte[])_EncDecMethod.Invoke(null,
new object[] { true, bytes, null, 0, bytes.Length });
string encData Convert.ToBase64String(encData);
The resulting string can now be copied to wherever you want and then copied back and decrypted. The decryption method is pretty much the same, just in reverse order. Both method implementations are included in the demo project.
Conclusion
This code is really useful if you are creating custom configuration files or if you have XML documents that contain sensitive data. By calling EncryptOrDecryptData
directly, you can encrypt almost everything.