// // System.Web.Configuration.MachineKeyRegistryStorage // // Authors: // Marek Habersack // // (C) 2007 Novell, Inc // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Security.Cryptography; using Microsoft.Win32; namespace System.Web.Configuration { internal class MachineKeyRegistryStorage { public enum KeyType { Validation, Encryption }; const int encryptionKeyLength = 64; const int validationKeyLength = 64; static string keyEncryption; static string keyValidation; static bool noStore; static MachineKeyRegistryStorage () { string appName = AppDomain.CurrentDomain.SetupInformation.ApplicationName; if (appName == null) { noStore = true; return; } string hash = appName.GetHashCode ().ToString ("x"); keyEncryption = "software\\mono\\asp.net\\" + Environment.Version.ToString () + "\\autogenkeys\\" + hash + "-" + ((int)KeyType.Encryption).ToString (); keyValidation = "software\\mono\\asp.net\\" + Environment.Version.ToString () + "\\autogenkeys\\" + hash + "-" + ((int)KeyType.Validation).ToString (); } public static byte[] Retrieve (KeyType kt) { byte[] ret = GetKey (kt); if (ret == null) { ret = Generate (kt); if (ret != null) Store (ret, kt); } return ret; } static byte[] GetKey (KeyType kt) { string key = null; int len; switch (kt) { case KeyType.Validation: key = keyValidation; len = validationKeyLength; break; case KeyType.Encryption: key = keyEncryption; len = validationKeyLength; break; default: throw new ArgumentException ("Unknown key type."); } if (key == null) return null; object o = null; try { RegistryKey v = OpenRegistryKey (key, false); o = v.GetValue ("AutoGenKey", null); } catch (Exception) { return null; } if (o == null || o.GetType () != typeof (byte[])) return null; byte[] ret = (byte[])o; if (ret.Length != len) return null; return ret; } static RegistryKey OpenRegistryKey (string path, bool write) { RegistryKey ret, tmp; string[] keys = path.Split ('\\'); int klen = keys.Length; ret = Registry.CurrentUser; for (int i = 0; i < klen; i++) { tmp = ret.OpenSubKey (keys [i], true); if (tmp == null) { if (!write) return null; tmp = ret.CreateSubKey (keys [i]); } ret = tmp; } return ret; } static void Store (byte[] buf, KeyType kt) { if (buf == null) return; string key = null; int len; switch (kt) { case KeyType.Validation: key = keyValidation; len = validationKeyLength; break; case KeyType.Encryption: key = keyEncryption; len = validationKeyLength; break; default: throw new ArgumentException ("Unknown key type."); } if (key == null) return; if (buf.Length != len) throw new ArgumentException ("Key has invalid length"); try { using (RegistryKey rk = OpenRegistryKey (key, true)) { #if NET_2_0 rk.SetValue ("AutoGenKey", buf, RegistryValueKind.Binary); rk.SetValue ("AutoGenKeyCreationTime", DateTime.Now.Ticks, RegistryValueKind.QWord); rk.SetValue ("AutoGenKeyFormat", 2, RegistryValueKind.DWord); #else rk.SetValue ("AutoGenKey", buf); rk.SetValue ("AutoGenKeyCreationTime", DateTime.Now.Ticks); rk.SetValue ("AutoGenKeyFormat", 2); #endif rk.Flush (); // we want it synchronous } } catch (Exception ex) { throw new ApplicationException ("Failed to store encryption key in the registry.", ex); } } static byte[] Generate (KeyType kt) { RandomNumberGenerator rng = RandomNumberGenerator.Create (); byte[] ret = null; switch (kt) { case KeyType.Validation: ret = new byte [validationKeyLength]; break; case KeyType.Encryption: ret = new byte [encryptionKeyLength]; break; default: throw new ArgumentException ("Unknown key type."); } rng.GetBytes (ret); return ret; } } }