I have some data I want to encrypt in an ASP.NET MVC application to prevent users from tampering with it. I can use the Cryptography classes to do the actual encryption/decryption, no problem there. The main problem is figuring out where to store the encryption key and managing changes to it.
Since ASP.NET already maintains a machineKey for various things (ViewData encryption, etc), I was wondering if there were any ASP.NET functions which let me encrypt/decrypt my own data using the machineKey? This way I would not have to devise my own key management system.
With .NET Framwork 4.5 you should use the new API:
public class StringProtector
{
private const string Purpose = "Authentication Token";
public string Protect(string unprotectedText)
{
var unprotectedBytes = Encoding.UTF8.GetBytes(unprotectedText);
var protectedBytes = MachineKey.Protect(unprotectedBytes, Purpose);
var protectedText = Convert.ToBase64String(protectedBytes);
return protectedText;
}
public string Unprotect(string protectedText)
{
var protectedBytes = Convert.FromBase64String(protectedText);
var unprotectedBytes = MachineKey.Unprotect(protectedBytes, Purpose);
var unprotectedText = Encoding.UTF8.GetString(unprotectedBytes);
return unprotectedText;
}
}
Ideally the "Purpose" should be a known one time valid value to prevent forging.
The new MachineKey class in ASP.NET 4.0 does exactly what you want.
For example:
public static class StringEncryptor {
public static string Encrypt(string plaintextValue) {
var plaintextBytes = Encoding.UTF8.GetBytes(plaintextValue);
return MachineKey.Encode(plaintextBytes, MachineKeyProtection.All);
}
public static string Decrypt(string encryptedValue) {
try {
var decryptedBytes = MachineKey.Decode(encryptedValue, MachineKeyProtection.All);
return Encoding.UTF8.GetString(decryptedBytes);
}
catch {
return null;
}
}
}
UPDATE: As mentioned here, be careful how you use this or you could allow someone to forge a forms authentication token.
I guess not directly. I can't remember where I got this from, probably a combination of Reflector and some blogs.
public abstract class MyAwesomeClass
{
private static byte[] cryptKey;
private static MachineKeySection machineKeyConfig =
(MachineKeySection)ConfigurationManager
.GetSection("system.web/machineKey");
// ... snip ...
static MyAwesomeClass()
{
string configKey;
byte[] key;
configKey = machineKeyConfig.DecryptionKey;
if (configKey.Contains("AutoGenerate"))
{
throw new ConfigurationErrorsException(
Resources.MyAwesomeClass_ExplicitAlgorithmRequired);
}
key = HexStringToByteArray(configKey);
cryptKey = key;
}
// ... snip ...
protected static byte[] Encrypt(byte[] inputBuffer)
{
SymmetricAlgorithm algorithm;
byte[] outputBuffer;
if (inputBuffer == null)
{
throw new ArgumentNullException("inputBuffer");
}
algorithm = GetCryptAlgorithm();
using (var ms = new MemoryStream())
{
algorithm.GenerateIV();
ms.Write(algorithm.IV, 0, algorithm.IV.Length);
using (var cs = new CryptoStream(
ms,
algorithm.CreateEncryptor(),
CryptoStreamMode.Write))
{
cs.Write(inputBuffer, 0, inputBuffer.Length);
cs.FlushFinalBlock();
}
outputBuffer = ms.ToArray();
}
return outputBuffer;
}
protected static byte[] Decrypt(string input)
{
SymmetricAlgorithm algorithm;
byte[] inputBuffer, inputVectorBuffer, outputBuffer;
if (input == null)
{
throw new ArgumentNullException("input");
}
algorithm = GetCryptAlgorithm();
outputBuffer = null;
try
{
inputBuffer = Convert.FromBase64String(input);
inputVectorBuffer = new byte[algorithm.IV.Length];
Array.Copy(
inputBuffer,
inputVectorBuffer,
inputVectorBuffer.Length);
algorithm.IV = inputVectorBuffer;
using (var ms = new MemoryStream())
{
using (var cs = new CryptoStream(
ms,
algorithm.CreateDecryptor(),
CryptoStreamMode.Write))
{
cs.Write(
inputBuffer,
inputVectorBuffer.Length,
inputBuffer.Length - inputVectorBuffer.Length);
cs.FlushFinalBlock();
}
outputBuffer = ms.ToArray();
}
}
catch (FormatException e)
{
throw new CryptographicException(
"The string could not be decoded.", e);
}
return outputBuffer;
}
// ... snip ...
private static SymmetricAlgorithm GetCryptAlgorithm()
{
SymmetricAlgorithm algorithm;
string algorithmName;
algorithmName = machineKeyConfig.Decryption;
if (algorithmName == "Auto")
{
throw new ConfigurationErrorsException(
Resources.MyAwesomeClass_ExplicitAlgorithmRequired);
}
switch (algorithmName)
{
case "AES":
algorithm = new RijndaelManaged();
break;
case "3DES":
algorithm = new TripleDESCryptoServiceProvider();
break;
case "DES":
algorithm = new DESCryptoServiceProvider();
break;
default:
throw new ConfigurationErrorsException(
string.Format(
CultureInfo.InvariantCulture,
Resources.MyAwesomeClass_UnrecognizedAlgorithmName,
algorithmName));
}
algorithm.Key = cryptKey;
return algorithm;
}
private static byte[] HexStringToByteArray(string str)
{
byte[] buffer;
if (str == null)
{
throw new ArgumentNullException("str");
}
if (str.Length % 2 == 1)
{
str = '0' + str;
}
buffer = new byte[str.Length / 2];
for (int i = 0; i < buffer.Length; ++i)
{
buffer[i] = byte.Parse(
str.Substring(i * 2, 2),
NumberStyles.HexNumber,
CultureInfo.InvariantCulture);
}
return buffer;
}
}
Caveat emptor!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With