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.
我有一些数据我想在ASP中加密。NET MVC应用程序,以防止用户篡改它。我可以使用密码学类来进行实际的加密/解密,没有问题。主要的问题是要弄清楚在哪里存储加密密钥和管理更改。
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.
因为ASP。NET已经为各种事情维护了一个machineKey (ViewData encryption,等等),我想知道是否存在ASP。NET函数,让我使用machineKey加密/解密我自己的数据?这样,我就不必设计自己的密钥管理系统了。
5 个解决方案
#1
45
With .NET Framwork 4.5 you should use the new API:
使用。net Framwork 4.5你应该使用新的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.
理想情况下,“目的”应该是已知的一个时间有效值,以防止伪造。
#2
40
The new MachineKey class in ASP.NET 4.0 does exactly what you want.
ASP中新的MachineKey类。NET 4.0正是你想要的。
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.
更新:正如这里所提到的,要注意您如何使用这个或您可以允许某人伪造表单身份验证令牌。
#3
9
I guess not directly. I can't remember where I got this from, probably a combination of Reflector and some blogs.
我猜没有直接。我不记得我是从哪儿弄来的,可能是Reflector和一些博客的结合。
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!
购者自慎!
#4
3
If you're working with 3.5 or earlier you can avoid a lot of code and just do this:
如果你使用的是3.5或更早的版本,你可以避免很多代码,只要这样做:
public static string Encrypt(string cookieValue)
{
return FormsAuthentication.Encrypt(new FormsAuthenticationTicket(1,
string.Empty,
DateTime.Now,
DateTime.Now.AddMinutes(20160),
true,
cookieValue));
}
public static string Decrypt(string encryptedTicket)
{
return FormsAuthentication.Decrypt(encryptedTicket).UserData;
}
One of my colleagues talked me into it and I think it's fairly reasonable to do this for custom cookies, if not for general encryption needs.
我的一个同事说服了我,我认为对定制cookie这样做是合理的,如果不是针对一般的加密需求的话。
#5
0
You might be able to reuse the MembershipProvider.EncryptPassword method, which in turn uses some (unfortunately internal) encryption methods of the MachineKeySection class.
您可能可以重用MembershipProvider。EncryptPassword方法,这反过来又使用了一些(不幸的内部)机器keysection类的加密方法。
#1
45
With .NET Framwork 4.5 you should use the new API:
使用。net Framwork 4.5你应该使用新的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.
理想情况下,“目的”应该是已知的一个时间有效值,以防止伪造。
#2
40
The new MachineKey class in ASP.NET 4.0 does exactly what you want.
ASP中新的MachineKey类。NET 4.0正是你想要的。
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.
更新:正如这里所提到的,要注意您如何使用这个或您可以允许某人伪造表单身份验证令牌。
#3
9
I guess not directly. I can't remember where I got this from, probably a combination of Reflector and some blogs.
我猜没有直接。我不记得我是从哪儿弄来的,可能是Reflector和一些博客的结合。
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!
购者自慎!
#4
3
If you're working with 3.5 or earlier you can avoid a lot of code and just do this:
如果你使用的是3.5或更早的版本,你可以避免很多代码,只要这样做:
public static string Encrypt(string cookieValue)
{
return FormsAuthentication.Encrypt(new FormsAuthenticationTicket(1,
string.Empty,
DateTime.Now,
DateTime.Now.AddMinutes(20160),
true,
cookieValue));
}
public static string Decrypt(string encryptedTicket)
{
return FormsAuthentication.Decrypt(encryptedTicket).UserData;
}
One of my colleagues talked me into it and I think it's fairly reasonable to do this for custom cookies, if not for general encryption needs.
我的一个同事说服了我,我认为对定制cookie这样做是合理的,如果不是针对一般的加密需求的话。
#5
0
You might be able to reuse the MembershipProvider.EncryptPassword method, which in turn uses some (unfortunately internal) encryption methods of the MachineKeySection class.
您可能可以重用MembershipProvider。EncryptPassword方法,这反过来又使用了一些(不幸的内部)机器keysection类的加密方法。