Leveraging ASP.NET machineKey For Encrypting My Own Data
我想在ASP.NET MVC应用程序中加密一些数据,以防止用户篡改它。我可以使用加密类来进行实际的加密/解密,没有问题。主要的问题是找出存储加密密钥的位置并管理对其所做的更改。
由于ASP.NET已经为各种各样的东西维护了一个machinekey(viewdata encryption等),我想知道是否有任何ASP.NET函数允许我使用machinekey加密/解密自己的数据?这样我就不用设计自己的钥匙管理系统了。
对于.NET framwork 4.5,您应该使用新的API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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; } } |
理想情况下,"目的"应为已知的一次性有效值,以防止锻造。
ASP.NET 4.0中的新machinekey类完全满足您的需要。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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; } } } |
更新:正如这里提到的,小心使用它,或者允许他人伪造表单身份验证令牌。
我想不是直接的。我不记得是从哪里得到的,可能是反射镜和一些博客的结合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | 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; } } |
自告奋勇!
如果您使用的是3.5或更早版本,则可以避免使用大量代码,只需执行以下操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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; } |
我的一个同事跟我谈过这个问题,我认为如果不是为了一般的加密需求,那么为定制的cookie做这个是相当合理的。
您可能可以重用membershipProvider.encryptPassword方法,该方法反过来使用machineKeySection类的某些(不幸的是,内部)加密方法。